Wednesday, September 10, 2014

REST service on weblogic 10.3.4

In this blog we will be developing a simple REST service using jdev and deploying it on weblogic 10.3.4.


NOTE: Jdeveloper 12c has better support for REST service creation but in this blog I am using Jdev 11.1.2.4 (or any older version) because I have to deploy these services on weblogic 10.3.4

NOTE: We will be using Jersey reference implementation of jsr311 to create REST services

We will perform following steps
1. Configure weblogic 10.3.4 with Jersey libraries
2. Create a REST service
3. Configure web.xml for REST service resources
4. Configure weblogic.xml to refer shared Jersey libraries
5. Deploy project on weblogic server
6. Access REST service

==================================================================
1. Configure weblogic 10.3.4 with Jersey libraries:

We get Jersey libraries with weblogic but they are not by default installed so we need to install them ourself.
Jersey libraries are available at $WL_HOME/common/deployable-libraries
Install jersey-bundle-1.1.5.1.war, jsr311-api-1.1.1.war on weblogic server as a Shared libraries.
Follow these steps for installing libraries (one at a time)
a. Launch weblogic console http://<server>:<port>/console
b. Navigate to Deployments
c. Click on Install
    
d. Select jersey-bundle-1.1.5.war
    
e. Select 'Install this deployment as library'
   
f. Select server on which you want to deploy this library. Note you can deploy rest service on same server. I am selecting 'Admin Server' so while deploying I can deploy REST service only on 'Admin server'. Admin server serves request from port 7001, which I need to use while accessing service.
  
f. Click Next Next and finish on rest of the pages.


Similarly install jsr311-api.war


2. Create a REST service

Next we need to create a simple REST service
Follow these steps to create REST service

a. Create an application/project.
    If you don't have an application/project already, create it.
    Create custom application/project.

    

   


b. Add Jersey library to project
     


c. Create a new java class to represent a resource
    REST stands for 'Representational State Transfer'. Actually we are transferring a resource between client and server. Every resource can be represented by structure (XML, HTML, TEXT, JSON) etc. We just want to transfer that representation of resource using REST service.

   Create a java class as shown below
   package com.san.rest.service;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;


@Path("helloworld")
public class HelloWorld {

  // To generate plain text
  @GET
  @Produces(MediaType.TEXT_PLAIN)
  public String helloInPlainText() {
    return "Hello! How are you?";
  }

  // To generate xml
  @GET
  @Produces(MediaType.TEXT_XML)
  public String helloInXML() {
    return "<?xml version=\"1.0\"?>" + "<welcomeMsg> Hello! How are you?" + "</welcomeMsg>";
  }

  // To generate html
  @GET
  @Produces(MediaType.TEXT_HTML)
  public String helloInHTML() {
    return "<html> " + "<title>" + "Hello" + "</title>"
        + "<body><h1>" + "How are you?" + "</body></h1>" + "</html> ";
  }

}

3. Configure web.xml for REST service resources
  
a. Create web.xml (Java EE deployment descriptor) for your project.
     New > Search for 'Java EE Deployment Descriptor'
     Follow wizard
    

b. Add following entry in web.xml file
NOTE: There are other ways also to specify resource classes to jersey. For example using init parameter javax.ws.rs.Application, but I believe using com.sun.jersey.config.property.packages parameter is easiest way. 

NOTE: If you have service resource in multiple packages specify value as 
  <param-value>pkg1;pkg2;pkg3</param-value>

4. Configure weblogic.xml to refer shared Jersey libraries

   a. Create weblogic deployment descriptor (weblogic.xml) file
       New > Search for 'Weblogic Deployment Descriptor'

    



b. Add shared libraries in weblogic.xml file


5. Deploy project on weblogic server

a. Set context root for your project
 b. Create WAR deployment profile
   Project Properties > Deployment Profile > New (War deployment profile)
  

c. Deploy project on weblogic server
     Now deploy project on weblogic server as normal war file.
      You can create app server connection in resource palate and then right click on project and deploy
      OR alternatively you can deploy war file first and then deploy it using weblogic console

 
6. Access REST service 

You can access service as http://<server>:<port>/<context-root>/<url-pattern>/<path>

server: weblogic server host
port: weblogic server port
context-root: defined in step 5. myrestservice in our case
url-pattern: defined in web.xml. /rest in our case
path: defined as @Path annotation in service class. helloworld in our case



Disclaimer: Any views or opinions presented in this blog are solely those of the author and do not necessarily represent those of the company.

Friday, August 15, 2014

WebCenter: Content Presenter and Secured images

In WebCenter we use sitestudio and content presenter to show content from UCM. This blog could be useful for you if you find following behavior
1. Content presenter is not able to show images
2. You are able to see images sometime but not always
3. One browser shows images but other is not able to show
4. You are able to see images but your friend is not or vice versa.

Answer of all these problems lies in they way images are accessed using content presenter.

If we do F12 and see the url of image generated by content presenter, we found that its a direct URL to content server. For example

http://<server-name>:16200/cs/idcplg?IdcService=GET_FILE&dDocName=MY_Image&RevisionSelectionMethod=LatestReleased

This url is directly pointing to content server. Now content server can only give images if either of this is true
1. Image document is public. (Immediate solution but not feasible in for secured images)
2. You are explicitly logged into content server (may in another tab) and you have access to image document. (Cause which is responsible why we see images sometime)
3. You have SSO enabled so that your webcenter session can be used to access content server. (Best solution)

In above three cases you will be able to see image otherwise you would not.

Disclaimer: Any views or opinions presented in this blog are solely those of the author and do not necessarily represent those of the company.

Saturday, August 9, 2014

Jdeveloper and Disk space issue

Recently I was running out of disk space and then I thought of analyzing it. I found that one of my middleware home (which I use frequently) is much bigger than others. WinDirStat shows that there are few hprof files in my middleware-home/jdeveloper/jdev/bin directory, which are taking lots of space. (3GB each around).

hprof files gets generated whenever jvm crashes or jdev shows outofmemory error. All heap information is dumped in hprof file and its size is generally same as your jdev memory size. That is why they are so huge.

These files can be used to analyze jvm crash but most of the time we are not interested in that untill its happening too frequently. We can delete them safely, which should give us lots of disk space back.


Another thing you may want to change it system directory location from C drive to some other location. For that you can set JDEV_USER_DIR environment variable. 

Disclaimer: Any views or opinions presented in this blog are solely those of the author and do not necessarily represent those of the company.

Friday, August 8, 2014

ADF Mobile: Issues faced while migrating from 11.1.2.4 to 12.1.3.0

Till 11.1.2.4 it was ADF Mobile and from 12.1.3.0 it is Mobile Application Framework (MAF). In this blog I am just writing few issues that I have faced while migrating one of my ADF mobile (11.1.2.4) project to MAF.

====================================================================
Issue 1:
Error: Unable to copy to output directory, D:\<file-path>\ApplicationController\src\META-INF\adfmf-skins.xml not found    ApplicationController.jpr    D:\<file-path>\ApplicationController    ApplicationController.jpr


Error: Unable to copy to output directory, D:\<file-path>\ViewController\src\META-INF\adfmf-feature.xml not found    ViewController.jpr    D:\<file-path>\ViewController    ViewController.jpr

Solution: https://community.oracle.com/thread/3579575
a. Remove .data directory
b. Do a clean build as there is no adfmf-skins.xml. Its changed to maf-skins.xml

====================================================================

Issue 2: Skin (css file) developed in 11.1.2.4 is not picked
Solution: Use version Id with 12.1.3 to define your skins and also to refer oracle provided base skins, which you are extending.
See bottom of this blog to set correct entries of maf-skin.xml and maf-config.xml

====================================================================

Issue 3: Error (Line 22, Column 48): Attribute allowDeviceAccess not defined on element adfmf:featureReference
Solution: remove allowDeviceAccess attribute from maf-application.xml

====================================================================

Issue 4:
Unable to load resource JSON file
/data/data/com.company.AbsenceManagemetn/files/baseProfiles/profile.json
Empty Response
Error: a profile is required to set up the base page

Solution: Problem with skin configuration in maf-skins.xml file. Start using skin versioning
See bottom of this blog to set correct entries of maf-skin.xml and maf-config.xml


====================================================================

Issue 5: KXmlUtil.loadFromXml Unexpected element - HTML Expected schema
Solution: Redeploy apk and use that.

====================================================================

Issue 6: The custom authentication page does not have credentials field.
Solution: This issue only occurs if we have created custom login page in 11.1.2.4 by copying adf-mobile-provided-login-pages-and-js. We need to again copy new login page and customize that as per our need. 


=========================================================
Correct way of extending skins in MAF

Disclaimer: Any views or opinions presented in this blog are solely those of the author and do not necessarily represent those of the company.


Saturday, July 19, 2014

ADF Good (Best) Practice: Register bean in backingbeans cope

This blog is to highlight why we should register our beans in backing bean scope.

ADF supports following scopes: backingbean, request, view, pageFlow, session and application.

As a good practice we should register our beans in backingbean scope.

1. Why we should not use view, pageFlow, session, application: System needs to serialize any information in these scopes during fail over and also when user times out. Generally we bind UI components with a bean and these components are not serializable so if bean is registered in above scopes it will not get serialized and serialization will fail.


2. Why we should not use requestScope: Serialization is not a problem if bean is registered in request scope because system does not serialize any object that is present in request scope. That make sense also because anything that is in request scope should be lost in next request so what is the point to serialize that information. BUT still we should not register our beans in request scope. That is because if we use a task-flow on a page twice and task-flow has a request-scope bean, both instances of task-flow will start sharing same instance of bean. It can create a lot of confusion.


3. Why should we use backing-bean Scope: Backing bean scope is almost same a request scope in terms of life cyle so system need not to serialize any such bean. Also we get advantage that system create two instances of bean if we use task-flow twice on a page.


4. Is it good enough: Now question is "Can we meet all requirements by storing beans in backing-bean scope?". I would say most of the time YES, you can. Mostly we need to put certain INFORMATION on higher scopes (like pageFlow, session, application) and to store that we don't need to put bean in that scope. We can directly put INFORMATION (or value) in scope. For example we have a 4 page task-flow, which has employee search on first page and user can select an employee on first page. After selecting employee user can navigate to page 2, 3, 4. On page 4 we need to know selected employee record.
To achieve this one developer do following
   a. Bind employee table of first page on a page-flow bean
   b. Bind table with the bean.
   c. On page 4, get page-flow bean and then get table and then try to get selected employee row.

Other developer can follow this approach
   a. Bind employee table of first page on backingbean-scoped bean
   b. Bind table with that bean
   c. While navigating to page-2 get selected row from employee table and store its (employee-id or any other needed information) in page-flow scope. If you need complete employee information you can create employee-pojo (object) and set its attribute and then store employee object in page-flow
   d. Access employee information from page-flow scope.

[IF you are using bindings and on selection you have selection listener which makes employee row current, you can directly create binding of same vo on page-4. That could be even better]

We see mostly we need to information on different pages, so its better to store those information on needed scope rather than bean.


5. If you really want to store bean in higher scopes: If you really need bean in higher scopes atleast use ComponentReference.

http://myfaces.apache.org/trinidad/trinidad-api/apidocs/org/apache/myfaces/trinidad/util/ComponentReference.html



Disclaimer: Any views or opinions presented in this blog are solely those of the author and do not necessarily represent those of the company.

Wednesday, July 9, 2014

ADF: Programatic user authentication instead of j_security_check (Password retrieval )

When we create ADF project and enable security, system creates a login page for us. Which has following code.


<form method="POST" action="j_security_check">
      <table cellspacing="2" cellpadding="3" border="1">
        <tr>          <th>Username:</th>
          <td>            <input type="text" name="j_username"/>          </td>
        </tr>
        
        <tr>          <th>Password:</th>
          <td>            <input type="password" name="j_password"/>          </td>
        </tr>
      </table>
      <p>
        <input type="submit" name="submit" value="Submit"/>
      </p>
    </form>

When user clicks on submit button, login form get submitted. It calls j_security_check, which is provided by framework. It validates username/password against ldap configured in weblogic.

We do not get any point to know what was username/password. At times we may want to derive  username/password combination. A usecase could be integration with third party. Imagine you want to integrate with third party system which takes username/password. For example sharepoint webservices. I tried checking OPSS apis but seems like there is no way to retrieve password using them. OPSS apis not retrieving password makes sense also.

To solve our problem I can think of a solution to capture user password while he is trying to login and if authentication is fine store user password in sessionscope. Use it later when calling third party system.

I personally think there might be better ways to do it but I could not find any solution. In this blog I am just describing a way to authenticate user programmatically instead of j_security_check.

Here are the steps:

1. Change login.html to login.jspx: Instead of using normal login.html page lets create a jspx page for login.
Put following form entry in it.

<af:panelFormLayout id="pfl2" styleClass="form_layout">
                        <f:facet name="footer"/>
                        <af:inputText label="#{portalBundle.USER_NAME}:" id="it1"
                                      value="#{viewScope.username}"
                                      required="true" maximumLength="50"
                                      partialTriggers="cb1"/>
                        <af:inputText label="#{portalBundle.PASSWORD}:" id="it2"
                                      value="#{viewScope.password}"
                                      secret="true" required="true"
                                      maximumLength="50" partialTriggers="cb1"
                                      shortDesc="Enter Password"/>
                        <af:commandButton id="cb1"
                                          action="#{backingBeanScope.LoginPageBean.doLogin}"
                                          text="#{portalBundle.LOGIN}"
                                          styleClass="login"
                                          partialSubmit="true"/>
                      </af:panelFormLayout>


In above code commandButton-cb1 does a partial submit and calls doLogin method of LoginPageBean. Username and password are stored in viewscope.

LoginPageBean code should look like



import com.kbace.hrc.common.util.diagnostic.DiagnosticUtil;


import java.io.IOException;

import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;

import javax.security.auth.Subject;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import oracle.adf.share.ADFContext;
import oracle.adf.share.logging.ADFLogger;
import oracle.adf.share.security.SecurityContext;
import oracle.adf.view.rich.component.rich.RichPopup;
import oracle.adf.view.rich.component.rich.output.RichOutputText;

import weblogic.security.URLCallbackHandler;
import weblogic.security.services.Authentication;

import weblogic.servlet.security.ServletAuthentication;


public class LoginPageBean {
    private static ADFLogger _logger =
        ADFLogger.createADFLogger(LoginPageBean.class);
    private RichOutputText pageInit;
    private RichPopup loginErrorPopup;
    private RichPopup userRoleErrorPopup;

    public LoginPageBean() {
    }
    private String _username, _password;


       public String doLogin() {
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
        _username = (String)ADFUtil.evaluateEL("#{viewScope.username}");
        _password = (String)ADFUtil.evaluateEL("#{viewScope.password}");
        String un = _username;
        byte[] pw = _password.getBytes();
        FacesContext ctx = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest)ctx.getExternalContext().getRequest();
        String loginStatus = "login_failed";
        try {
            Subject subject =   Authentication.login(new URLCallbackHandler(un, pw));
            weblogic.servlet.security.ServletAuthentication.runAs(subject,     request);
            ServletAuthentication.generateNewSessionID(request);

            loginStatus = "success";
             String redirecturl = "/adfAuthentication?success_url=/index.html";
            Map session = (Map)ADFUtil.evaluateEL("#{sessionScope}");
            session.put("userPassword", _password);
            session.put("username", _username);

                try {
                   FacesContext.getCurrentInstance().getExternalContext().redirect(FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath() + redirecturl);
               
                } catch (Exception nm) {
                    nm.printStackTrace();
                }
          
        } catch (FailedLoginException fle) {
            ADFUtil.getRequestFlowScope().put("pShowAuthError", "Y");
            RichPopup.PopupHints pph=new RichPopup.PopupHints();
            this.getLoginErrorPopup().show(pph);
            ADFUtil.setEL("#{viewScope.password}", null);

        } catch (LoginException le) {
            FacesMessage msg =
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error Logging In",
                                 "Error Logging In");
            ctx.addMessage(null, msg);

        }
        return null;
    }



}




Above method doLogin tries following things
1. Get username/password from viewscope
2. Authenticate username/password using weblogic security apis. 
3. If valid username/password then start a new session.
4. Store username/password in sessionscope
5. Redirect to index.html if successful login.
6. Show error popup if authentication fails.
   

Also we need to add following libraries in our project


a.       com.bea.core.weblogic.security.auth_1.1.0.0.jar: $MW_HOME\modules
b.      com.bea.core.weblogic.security.identity_1.1.2.1.jar: $MW_HOME\modules
c.       ws.api.jar: $MW_HOME\wlserver_10.3\server\lib



I am not very sure if its best way of doing it. I would definitely love to know better ways of doing this but for time being I just know this way.


Disclaimer: Any views or opinions presented in this blog are solely those of the author and do not necessarily represent those of the company.

Saturday, May 17, 2014

ADF Mobile Dependent (Cacading) LOV

This blog is to show how we can create depending (or cascading) LOVs using ADF Mobile

Steps are
1. Create client classes to store data that needs to appear in LOVs
2. Create datacontrol class to hold LOV data in a list (array) and provide mechanism to refresh LOV data
3. Create select-one-choice on page using datacontrol
4. Set valuechange listner of LOV1 to refresh dataprovider of LOV2.



In this example I will create a Country/State LOVs

Country LOV will have India, US values. and State LOV will show states of India or US.

==============================

Step 1. Create client classes to store data that needs to appear in LOVs

To represent country and states we need two classes Country, State

Country.java 
package com.san.mobile.client;

public class Country {
    private String countryName;
  
    public Country( String countryName) {
        super();
        this.countryName = countryName;
    }


    public void setCountryName(String countryName) {
        this.countryName = countryName;
    }

    public String getCountryName() {
        return countryName;
    }

}




State.java
package com.san.mobile.client;

public class State {
    private String stateName;
    public State(String stateName) {
        super();
        this.stateName = stateName;
    }

    public void setStateName(String stateName) {
        this.stateName = stateName;
    }

    public String getStateName() {
        return stateName;
    }
}




========================================================

Step 2. Create datacontrol class to hold LOV data in a list (array) and provide mechanism to refresh LOV data 

package com.san.mobile.dc;

import com.san.mobile.client.Country;
import com.san.mobile.client.State;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.java.beans.ProviderChangeListener;
import oracle.adfmf.java.beans.ProviderChangeSupport;

public class DependentLOVDC {
    private List countries = new ArrayList();
    private List states = new ArrayList();
  
    protected transient ProviderChangeSupport providerChangeSupport = new ProviderChangeSupport(this);
    public DependentLOVDC() {
        super();
      
        //NOTE: You can call a webservice here to get actual country data.
      
        countries.add(new Country("India"));
        countries.add(new Country("US"));
    }
  
    public void addProviderChangeListener(ProviderChangeListener l) { 
         providerChangeSupport.addProviderChangeListener(l);
       }
       public void removeProviderChangeListener(ProviderChangeListener l) { 
         providerChangeSupport.removeProviderChangeListener(l);
       }
     
     
    public Country[] getCountries(){      
        return (Country[])countries.toArray(new Country[countries.size()]);      
    }
  
  public State[] getStates(){
       
        states = new ArrayList();
            Map pageFlow = (Map)AdfmfJavaUtilities.evaluateELExpression("#{pageFlowScope}");
            String countryName = (String)pageFlow.get("pCountryName");
                      
           
            if(countryName == null || "India".equals(countryName)){
                //NOTE: You can call a webservice here to get actual country data.
                states.add(new State("Delhi"));
                states.add(new State("Karnataka"));
            }
            else  if("US".equals(countryName)){
                //NOTE: You can call a webservice here to get actual country data.
               states.add(new State("California"));
                states.add(new State("Georgia"));
            }
           
           
            return (State[])states.toArray(new State[states.size()]);
           
        }
  
  
        public void refresh(){
            providerChangeSupport.fireProviderRefresh("states");
        }
      
    }


In above class I mainly have two getters, which returns list of countries and states. State getter is returning based on pageFlow variable pCountryName. It means if on selection of country we can set pCountryName in pageFlow. Which is easy.
I have also added provider change support on this class by adding 

protected transient ProviderChangeSupport providerChangeSupport = new ProviderChangeSupport(this); 

and 


  public void addProviderChangeListener(ProviderChangeListener l) { 
         providerChangeSupport.addProviderChangeListener(l);
       }
       public void removeProviderChangeListener(ProviderChangeListener l) { 
         providerChangeSupport.removeProviderChangeListener(l);
       }  



There are two big problems we need to resolve
1. How would we ask framework to execute getStates once we have selected a project.

2. How would we ask framework to refresh UI LOV if getStates returns new set of data. 

Both of this can be done using providerChangeSuuport. You just need to add a refresh method on this class as 


public void refresh(){
            providerChangeSupport.fireProviderRefresh("states");
        }


Expose this class as a datacontrol. For this right click on
DependentLOVDC and select 'Create data control'.
You will wee following structure in Data Controls. 



 











===================================================================
Step 3. Create select-one-choice on page using datacontrol

 Drag and drop countries/states on your page and create select-one-choice as shown below.




















Select OK on next popup.

You will get following code in your amx

    <amx:selectOneChoice value="#{bindings.countries.inputValue}" label="#{bindings.countries.label}" id="soc1">
      <amx:selectItems value="#{bindings.countries.items}" id="si1"/>
    </amx:selectOneChoice>
    <amx:selectOneChoice value="#{bindings.states.inputValue}" label="#{bindings.states.label}" id="soc2">
      <amx:selectItems value="#{bindings.states.items}" id="si2"/>
    </amx:selectOneChoice>


AS we know in ADF when you select a choice list value and try to use valueChangeEvent.getNewValue(), it returns index but not the actual value. To avoid using valueChangeEvent.getNewValue() we can create an attribute binding in pageDef as 



================================================================
4. Set valuechange listner of LOV1 to refresh dataprovider of LOV2.


Create method action binding for refresh method of DependentLOVDC in pageDef.























Create a bean and register it as usual. Write valuechangelistener on country LOV as

    public void handleCountrySelection(ValueChangeEvent valueChangeEvent) {
        // Add event code here...
       
        Map pageFlow = (Map)AdfmfJavaUtilities.evaluateELExpression("#{pageFlowScope}");
        String countryName = (String)valueChangeEvent.getNewValue();
       
        pageFlow.put("pCountryName", countryName);
       
        MethodExpression me = AdfmfJavaUtilities.getMethodExpression("#{bindings.refresh.execute}", Object.class, new Class[] {});
        me.invoke(AdfmfJavaUtilities.getAdfELContext(), new Object[]{});
    }


======================================================

Thats it.

Code flow is like

1. System create both lovs using datacontrol data provider
2. On selection of country, valuechange listener runs. Listener executes a bean method, which sets pageFlow variable pCountryName and calls refresh method of binding. Binding refresh points to refresh method of datacontrol.
3. Refresh method asks providerChangeSupport to refresh "states" dataprovider, which is nothing but getStates method of DependentLOVDC. Once data is changed, providerchangesupport will refresh on UI components showing data from that dataprovider.

Disclaimer: Any views or opinions presented in this blog are solely those of the author and do not necessarily represent those of the company.