Friday, March 20, 2015

MAF: Take picture and upload

Problem Description:
In this blog we will see how we can take a picture using MAF and then upload it on server.

Approach:
We will follow below steps
1. Write a REST service: This service will take image-data as input and saves it somewhere in server. Service expects image-data to be a base64 encoded string representation of image.

2. MAF code to take picture and then call REST service: On mobile code we will take picture using device apis and then pass it to REST service as a base64 encoded string.


Implementation

1. Write REST service:
I have already blogged about writing REST services using JAX-RS. We can see http://sanjeev-technology.blogspot.in/2014/09/rest-service-on-weblogic-1034.html and http://sanjeev-technology.blogspot.in/2014/09/rest-adding-json-support-using-jackson.html for more details.
Here is important screenshot of creating REST service to take image-data as string and save it local folder.

   Jersey servlet registration in web.xml: It means we need to put our services in 'com.san.rest.service' folder.

 
    Directory structure:

     PhotoEntity.java

    PhotoService.java




In my code I am trying to put image in my D:\\Temp directory. If you also want to try same think please create same directory.

Now deploy above service on weblogic server. Based on web.xml settings and annotations, URL for service will be http://<server>:<port>/<context>/rest/photos/postImage

2. TEST REST service using Chrome-Extension 'Advanced REST client'
To test this service you can use Chrome-Extension 'Advanced REST client'. Select following values
URL: http://<server>:<port>/<context>/rest/employees/postImage
Method: POST
Payload: imageData={"imageDataB64": "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NeIa78CfFfhvVE1DwXqMl2A5ERScW11CG3D72QpG3ALAgksflAr6TooA+YLD4z/EDwd9m03xDp32jbsfGp20kNy0PC4DcZztb52VjnOc9K7PTf2k9Blt2bVND1K2n3kKlqyTqVwOSzFCDnPGOw5549kvrCz1Ozks7+0gu7WTG+GeMSI2CCMqeDggH8K4+++D/gHULyS6m8OQJI+MiCWSFBgAcIjBR07Dnr1oApwfHH4fTW8Ur61JA7oGaKSzmLISPunahGR04JHoTUn/AAu34ef9DD/5JXH/AMbrDn/Z18GzXEsqXeswI7llijuIyqAn7o3Rk4HTkk+pNR/8M4+D/wDoJa5/3/h/+NUAWL79obwVaXkkEMWq3sa4xPBbqEfIB4DurcdOQOnpzXEan+0prEvlf2T4fsbXGfM+1zPcbumMbdmO/XOcjpjn0ex+BXgG0s44JtLnvZFzmee7kDvkk8hGVeOnAHT15rsNG8KeH/D2w6RotjZSLEIfOhgUSMgxwz43N0BOSckZPNAHzZB4V+KnxTEV1qE12dPncSLLfy+RbgiP5XWEdipwGRCCWPP3jXq/hL4D+GfDtxFeai8mtXaIylLqJRbkk8MIsHkLx8zMM5OAcY9UooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA//9k="}

Note: to create payload use form tab in REST client. If you pasted above payload as as raw data then you need to click on 'Encode payload' option.


You will see that a nice photo has been uploaded in your D:\Temp directory.
If you want to test with your image, you can copy image as D:\Temp\MyPhoto.png and run below program to generate base64 encoded string for your image file.

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class PhotoBase64 {
    public static void main(String[] args) throws IOException {
       String dirName="D:\\Temp\\";
       ByteArrayOutputStream baos=new ByteArrayOutputStream(1000);
       File file = new File (dirName, "MyPhoto.png");
       BufferedImage img=ImageIO.read(file);
       ImageIO.write(img, "jpg", baos);
       baos.flush();
         
       String base64String=Base64.encode(baos.toByteArray());
       System.out.println(base64String);
       baos.close();
    }
    
    
}


3. MAF code to take picture and then call REST service:
Now coming to actual MAF code. Approach is
a. Create a REST connection to the service:
               
b. Create a MAF feature with amx page
             
c. Create PhotoBean.java class and register it as a bean


d. Implement bean method to take photo and call REST service
 

e. AMX code to call bean method on button click
<amx:commandButton text="Take Photo" id="cb3" actionListener="#{viewScope.PhotoBean.submitPhoto}"/>


Now keep service running. Generate apk file for your mobile app. Install it on your mobile and click on 'Take photo' button. It will allow you to take photo and same photo will get uploaded into server.


Thats it.

Code can be downloaded from https://github.com/Sanjeev1Chauhan/MAF-Upload-Picture-REST-B64
Follow Doc\readme.txt to deploy application.

Tuesday, March 10, 2015

ADF: Bookmark taskflows

Problem description:
In ADF bookmarking a task flow is always a problem. We can only bookmark pages but not regions (embedded task-flow) in those pages. Let say we have a HR page, its shows lots of information and one corner of this shows a task-flow with employees in tabular format

Now if I select employee id = 2 row, inner task-flow will start shwoing details of that employee. Technically we have navigated to new fragment in task-flow. Page would look something like

Now what if we want to bookmark employee detail page directly. Because url has not changed our bookmark will save http://127.0.0.1:7101/ADFBookmarking-ViewController-context-root/faces/pages/MyLandingPage.jspx url only. Next time when we load url again, we will get employee list page first. User needs to again select employee id =2. But our requirement is we want to bookmark a url so that we can directly go to employee detail page, without employee-list page.

This blog is to solve this problem only.

If we closely look there are two problems
1. How to change url when user selects an employee: Everything that needs to be bookmarkeable should have a unique url. So we need to change url on selection of employee row. We can add some parameter in url to modify it. For example ?page=empDetails&empId=2
BUT BUT at any cost url change should not fire a new complete request to server. Otherwise full page refresh will happen, which is not needed. In modern browser we can use
window.history.replaceState to change url of current page without refreshing page completely. We are going to use this approach.

2. If we launch url later with extra parameter (?page=empDetails&empId=2), task-flow should jump to appropriate fragment (employee-details in this case): To solve this problem we will call a bean method from task-flow and read request parameter in it. Based on request parameter we will navigate to appropriate page.


Here is the code snippet to see complete solution

1. MyLandingPage.jspx: This page has some static text and also Employee-flow as a region


2. Employee-Flow: This is a task-flow which is appearing on MyLandingPage.jspx as a region. This task-flow has two pages EmpList.jsff and EmpDetails.jsff. EmpList.jsff shows complete list of employees in tabular format. On selection of employee we select employee record in model and then navigate to EmpDetails.jsff page. EmpDetails.jsff page show currently selected employee record in tabular format.


Now let us modify this application so that we can bookmark EmpDetails page as well.

We will do following modification for that
a. Use JavaScript to change url on employee selection: For this purpose we will modify EmpList.jsff. We will add below javascript



Also change link code to call this javascript.
b. Modify task-flow to accept parameter for request and navigate to appropriate fragment:
We can create a bean and register it in task-flow backingbeanscope as
 We can implement prepareBookmarking method in bean. This method will read request parameter and then put them in pageFlowScope appropriately. Router will use these pageFlowScope parameters to decide, which page to navigate.
Now we can call this method from taskflow by using method call activity. We can make this activity as default activity for taskflow so that task-flow starts from here.

We can use a router activity to decide which page to call based on pageFlowScope parameter.


With that our coding is over.

Now if we see end result
1. Initial page:

2. Click on id=2 and navigate to empDetails page
3. Bookmark complete url [http://127.0.0.1:7101/ADFBookmarking-ViewController-context-root/faces/pages/MyLandingPage.jspx?page=empDetails&empId=2]. Now open url in new tab

RESULT: We have a bookmarkeable url for employee detail page and whenever we load it we will see employee detail page directly.

Thats all. But there is a catch here. What if I drop same task-flow twice on a page? May be I will try to resolve it in my next blog.

Monday, March 9, 2015

ADF: URL simplification

In this blog I would like to describe how can we shorten url of our ADF pages. In ADF URL looks like 

http://127.0.0.1:7101/URLSimplification-ViewController-context-root/faces/MyPage.jspx?_afrLoop=6129381558176&_afrWindowMode=0&_adf.ctrl-state=onxhkg6zm_4

Our aim is to provide a simplified url like (http://sandemo.com) to end user and it should take him to our welcome page.

In above url _afrLoop=6129381558176&_afrWindowMode=0&_adf.ctrl-state=onxhkg6zm_4 gets added automatically so its not harming us. We can keep it as it is. Remaining url that needs to be simplified is http://127.0.0.1:7101/URLSimplification-ViewController-context-root/faces/MyPage.jspx

[URL redirection and simplification can be achieved using OHS but in this blog we will try it without OHS]

This url has following parts
1. http: This is protocol and we want it in our final url also so let it be like that
2. 127.0.0.1: This is m/c name. If we want to save sandemo.com we need to change our m/c name to sandemo.com. 
3. 7101: This is port. My weblogic server is listening at 7101 port. If I can change it to 80, I need not to pass it in URL. That way we can remove it from url.
4. URLSimplification-ViewController-context-root: This is a context root. We can deploy multiple web application on same weblogic server. Every application will have a unique context root. Using that weblogic knows which application to call. We can certainly reduce it but here we want to remove it from url. In other words we need to set it to /
5. faces/MyPage.jspx: This part is actually pointing to the page within application. We need to make sure if nothing is provided after context root, ADF should point to our welcome page. Which is faces/MyPage.jspx

As I don't have admin privileges on my box so I will not change my m/c name. So aim is if I type 127.0.0.1, on url, it should show me my welcome page.

We will perform following steps for URL simplification

1. Change port of web server to 80
2. Change context root to /
3. Set welcome page 


1. Change port of web server to 80: For this you need to open your console and select appropriate server on which you are going to deploy application. Change its listen port to 80. You can also change SSL Listen port if its https based application. Follow this navigation
   console > Environment > Servers > [Select appropriate server] > [Change port settings]


2. Change context root to /: You can change web-projects Java-EE Web Context root property for this but there is a catch. 


BUT BUT this does not work. The moment I try to save this setting I get error as




OK. Now lets try to play with jdeveloper and try to change this using a text editor directly. We can open UI project's jpr file and then search for property j2eeContextRoot. Now change its value to "/" as shown in below diagram.

If we open UI project's property we will see context-root is changed to "/". Use cancel to close project properties and run the page.

If we try to deploy it on admin server, we may found error as below

According to error there is another application that is running with / as a context root. We need to stop it. This application is nothing bur a welcome page application of weblogic and it gives information about weblogic server. We can stop it without any harm. Locate 'FMW Welcome Page Application' in weblogic deployments and stop it.


3. Set welcome page :
Welcome page setup is done in web.xml. Add following entry in web.xml
  <welcome-file-list>
    <welcome-file>/faces/MyPage.jspx</welcome-file>
  </welcome-file-list>


Now if you type only 127.0.0.1, system will redirect you to your welcome page. 

If your page is in a folder like com/san/pages, your initial url could be http://127.0.0.1:7101/URLSimplification-ViewController-context-root/faces/com/san/pages/MyPage.jspx. In such case you can generate an id for your jspx file by dropping it in adfc-config.xml. That way your url will change to http://127.0.0.1:7101/URLSimplification-ViewController-context-root/faces/MyPage. Now you can try to remove port and context-root from it.