Tuesday, December 6, 2011

Special Characters in Google Search

Unfortunately you usually can not search phrases with special characters. The following is the quote from the Google support link:
http://www.google.com/support/websearch/bin/answer.py?answer=134479

Generally, punctuation is ignored, including @#$%^&*()=+[]\ and other special characters.
By the way, that article has this useful tip:
Search is always case insensitive. A search for [ new york times ] is the same as a search for [ New York Times ].

Monday, October 17, 2011

How Are the Per Web Application Singleton Objects Created in the JSF Framework

In the JSF framework, there are several key classes that are the singletons for the application. They are created using the following way:
FactoryFinder --> Factory --> Singleton Object.
To guarantee that the object is a singleton, the FactoryFinder and the Factory do the following:
  1. The Factories are also singletons. So you can just use plain code to get a field object of it as a singleton too.
  2. The FactoryFinder defines all its fields and methods to be static. And it puts the code to retrieve the factoies in a synchronized block. So when you get a factory object from FactoryFinder, it will be a singleton.
  3. Now since the web app uses the static method of FactoryFinder to get the factory object, will different web applications deployed on the same server share the same factory object? The answer is "No" and it is very important. The FactoryFinder uses classloader of the specific web application to achieve this result.

Note 1: If the purpose is to just create a singleton, then there is no need to use Factory. I think the main purpose to use Factory here is to give a mechanism so the different implementations of the singleton classes can be used. Factory uses some algorithm to find and load the implementation classes.

Note 2: The factories are loaded at the startup time of the server. This is before the web application is used by any user.

In FactoryFinder, there are four factories that can be created. They are: ApplicationFactory, FacesContextFactory, LifecycleFactory, and RenderKitFactory.

Take the Application singleton as the example.

From javadoc, javax.faces.application.Application represents a per-web-application singleton object. It is created by the following:
Application application = ApplicationFactory.getApplication();

The implementation ApplicationFactoryImpl is simply the following:
private Application application;

   public Application getApplication(){
      if (application == null )
      {
         application = new ApplicationImpl();
       }
       return applicaiton;
   }
You can see that this code does not deal with thread safety. And it is not static. So this code itself does not guarantee that the returned applicaiton object will be a singleton.

The javax.faces.application.ApplicationFactory is also a per-web-application singleton. It is created by the following in FactoryFinder:
private static HashMap applicationMaps = new HashMap();
  
   public static Object getFactory(String factoryName) throws FacesException{
    validateFactoryName(factoryName);
    synchronized (applicationMaps) {
            Map appMap = getApplicationMap();
   
              Object 
      factory = null,
      factoryOrList = appMap.get(factoryName);
                if (factoryOrList != null && (!(factoryOrList instanceof List))) {
     
                    return (factoryOrList);
                }
        
                factory = getImplementationInstance(classLoader, factoryName,
          (List) factoryOrList);
         
                if (null == factory) {
                    ResourceBundle rb = LOGGER.getResourceBundle();
                    String message = rb.getString("severe.no_factory");
                    message = MessageFormat.format(message, factoryName);
                    throw new IllegalStateException(message);
                }
    
                appMap.put(factoryName, factory);
                return (factory);
        }
   
   }

So in this method, the synchronized code is used. it is guaranteed that the singleton will be returned.
Let us look at the code in more detail to see why the returned factory object is per-web application.
The line Map appMap = getApplicationMap(); creates a local Map variable appMap. The method called is the following:
private static HashMap applicationMaps = new HashMap();

private static Map getApplicationMap() {
        // Identify the web application class loader
        ClassLoader classLoader = getClassLoader();
 Map result = null;
 
 // Return any previously instantiated factory instance (of the
 // specified name) for this web application
 result = (HashMap) applicationMaps.get(classLoader);
 if (result == null) {
     result = new HashMap();
     applicationMaps.put(classLoader, result);
 }
 return result;
    }
So it is a map from the classLoader to another map. This classLoader object is different for different web applications deployed on the same server. The method is the following:
private static ClassLoader getClassLoader() throws FacesException {

        // J2EE 1.3 (and later) containers are required to make the
        // web application class loader visible through the context
        // class loader of the current thread.
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl == null) {
            throw new FacesException("getContextClassLoader");
        }
        return (cl);

    }
You can see that it uses the current thread to get the ClassLoader object. The static instance variable applicationMaps of the class FactoryFinder contains the following information:
classLoader --> {factoryName --> factoryObject}
So in a more strict sense, the factoryObject singleton is not a singleton across the JVM. It is a singleton inside each web applicaiton.

Thursday, October 13, 2011

Main Classes Called by the Phase Objects in JSF Lifecycle

UIViewRoot and ViewHandler

The JSF lifecycle has 6 phases. They are RestoreViewPhase, ApplyRequestValuesPhase,ProcessValidationsPhase, UpdateModelValuesPhase, InvokeApplicationPhase, and RenderResponsePhase. The corresponding classes are all in the package com.sun.faces.lifecycle.

The RestoreViewPhase gets the UIViewRoot from the facesContext or the viewhandler. Either way, it will eventually set the viewRoot in the facesContext.

The ApplyRequestValuesPhase basically uses the ViewRoot to do decoding:
public void execute(FacesContext facesContext) throws FacesException{
         ......
         UIComponent component = facesContext.getViewRoot();
         ......
         component.processDecodes(facesContext);
         .......
      }
 
The ProcessValidationsPhase basically uses the ViewRoot to invoke the validators:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processValidators(facesContext); 
          .......
       }
 
The UpdateModelValuesPhase uses the ViewRoot to process updates:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processUpdates(facesContext);
          .......
       }
The InvokeApplicationPhase uses the ViewRoot to process application:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processApplication(facesContext); 
          .......
       }
The RenderResponsePhase uses the viewHandler and the ViewRoot to render the view:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          facesContext.getApplication().getViewHandler().renderView(facesContext, facesContext.getViewRoot());
          .......
       }
From the above, we can see that the ViewRoot object plays an important role. All the phases between the RestoreViewPhase and the RenderViewPhase just delegate the work to the ViewRoot.

Some Notes on UIViewRoot

The UIViewRoot class calls the broadcast(event) method of the UIComponent class in many places. The name of this method is misleading. If you look at the code, it actually does not just broadcast the event. It actually also invokes the event listeners to perform actions.
The following is the method in the UIComponentBase class:
public void broadcast(FacesEvent event)
        throws AbortProcessingException {
        if (event == null) {
            throw new NullPointerException();
        }
        if (listeners == null) {
            return;
        }
        Iterator iter = listeners.iterator();
        while (iter.hasNext()) {
            FacesListener listener = iter.next();
            if (event.isAppropriateListener(listener)) {
                event.processListener(listener);
            }
        }
    }
There are two concrete event classes that implement the processListener(...) method. One is ActionEvent, and the other is ValueChangeEvent. The ActionEvent class has the following:
public void processListener(FacesListener listener) {
        ((ActionListener) listener).processAction(this);
    }
The ValueChangeEvent class has the following:
public void processListener(FacesListener listener) {
        ((ValueChangeListener) listener).processValueChange(this);
    }
So here the event actually lets the listeners to act on the event itself. It does not just sit at the listeners.
The following are more details. The com.sun.faces.application.ActionListenerImpl has the code below:
public void processAction(ActionEvent event) {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("processAction(" + event.getComponent().getId() + ")");
        }
        UIComponent source = event.getComponent();
        ActionSource actionSource = (ActionSource) source;
        FacesContext context = FacesContext.getCurrentInstance();

        Application application = context.getApplication();

        Object invokeResult = null;
        String outcome = null;
        MethodBinding binding = null;

 binding = actionSource.getAction();
 if (binding != null) {
     try {
  if (null != (invokeResult = binding.invoke(context, null))) {
                    outcome = invokeResult.toString();
                }
                // else, default to null, as assigned above.
     } catch (MethodNotFoundException e) {
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.log(Level.SEVERE, e.getMessage(), e);
                }
  throw new FacesException
                    (binding.getExpressionString() + ": " + e.getMessage(), e);
     }
     catch (EvaluationException e) {
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.log(Level.SEVERE, e.getMessage(), e);
                }
  throw new FacesException
                    (binding.getExpressionString() + ": " + e.getMessage(), e);
     }
 }

        // Retrieve the NavigationHandler instance..

        NavigationHandler navHandler = application.getNavigationHandler();

        // Invoke nav handling..

        navHandler.handleNavigation(context,
                                    (null != binding) ?
                                    binding.getExpressionString() : null,
                                    outcome);

        // Trigger a switch to Render Response if needed
        context.renderResponse();
    }
The javax.faces.event.MethodExpressionValueChangeListener class has the code below:
public void processValueChange(ValueChangeEvent valueChangeEvent) throws AbortProcessingException {
                         
        if (valueChangeEvent == null) {
            throw new NullPointerException();
        }
        try {
            FacesContext context = FacesContext.getCurrentInstance();
            ELContext elContext = context.getELContext();
            methodExpression.invoke(elContext, new Object[] {valueChangeEvent});
        } catch (ELException ee) {
            throw new AbortProcessingException(ee.getMessage(), ee.getCause());
        }
    }
The javax.faces.event.MethodExpressionActionListener class has the code below:
public void processAction(ActionEvent actionEvent) throws AbortProcessingException {

        if (actionEvent == null) {
            throw new NullPointerException();
        }
        try {
            FacesContext context = FacesContext.getCurrentInstance();
            ELContext elContext = context.getELContext();
            methodExpression.invoke(elContext, new Object[] {actionEvent});
        } catch (ELException ee) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
                LOGGER.log(Level.SEVERE,
                           "severe.event.exception_invoking_processaction",
                           new Object[]{
                                 ee.getCause().getClass().getName(),
                                 methodExpression.getExpressionString(),
                                 actionEvent.getComponent().getId()
                           });
                StringWriter writer = new StringWriter(1024);
                ee.getCause().printStackTrace(new PrintWriter(writer));
                LOGGER.severe(writer.toString());
            }
            throw new AbortProcessingException(ee.getMessage(), ee.getCause());
        }
    }

A Closer Look at How the InvokeApplicationPhase works

The code of the execute(...) method of the InvokeApplicationPhase is very simple. Essentially it just calls root.processApplication(facesContext) where root is the UIViewRoot. And the essential code in the processApplication(...) method of UIViewRoot is the following:
broadcastEvents(context,PhaseId.INVOKE_APPLICATION);
So let's see how it works in reality. The example used here is a simple jsp file with a form:
<html>
       ...
       <f:view>
          ...
          <h:form>
             ...
             <h:commandButton action="#{quiz.answerAction}" />
             ...
          </h:form>
         ...
       </f:view>
     </html>
Here is what happened during the lifecycle of JSF. We can see when and where the event object is created.
  1. In the ApplyRequestValuePhase, JSF iterates through all the UIComponents in the UIForm and calls the processDecodes method of each component.
  2. The CommandButton component gets the Render and lets the Render do the decode.
  3. The ButtonRender creates an ActionEvent and queues the event to the UIViewRoot. The event has the Invoke_Application phase ID and so will be used in the Invoke_Applicaiton pahse. Interestingly at this point, the events[] field of the UIViewRoot class is still null. So it is created and the ActionEvent is put in. Actually this makes sense because the events[] field in UIViewRoot class is a transient field. So it is not saved in the session and can not be restored in the Restore_View phase.
  4. In the Invoke_Applicaiton phase, the UIViewRoot will pick up this event and let it work.

Monday, October 10, 2011

How Does the JSF Restore_View Phase Restore the View?

The Restore_View phase is one of the key points in the JSF lifecycle. How does JSF restore the view? From where?

When does the Restore_View actually restore the view?

When a user navigates through various pages of an application on the brower, he or she may visit the same jsp file multiple times. A jsp file is a view in JSF. Will this view be saved by the JSF framework and then be restored in every subsequent visit? In general the answer is no. We will use jsf-1.2 in this analysis.

The java file in JSF to do the RESTORE_VIEW phase is com.sun.faces.lifecycle.RestoreViewPhase.java. Two of its methods are the following
/**
     * PRECONDITION: the necessary factories have been installed in the
     * ServletContext attr set. 
     * POSTCONDITION: The facesContext has been initialized with a tree.
     */

    public void execute(FacesContext facesContext) throws FacesException {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("Entering RestoreViewPhase");
        }
        
        ......
        
        Util.getViewHandler(facesContext).initView(facesContext);        

        // If an app had explicitely set the tree in the context, use that;
        //
        UIViewRoot viewRoot = facesContext.getViewRoot();
        Locale locale = null;
        if (viewRoot != null) {
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Found a pre created view in FacesContext");
            }
            locale = facesContext.getExternalContext().getRequestLocale();
            facesContext.getViewRoot().setLocale(locale);
            doPerComponentActions(facesContext, viewRoot);
            return;
        }

        ......
        
 if (isPostback(facesContext)) {
     // try to restore the view
            ViewHandler viewHandler = Util.getViewHandler(facesContext);
     if (null == (viewRoot = viewHandler.restoreView(facesContext, viewId))) {
                JSFVersionTracker tracker = 
                        ApplicationAssociate.getInstance(facesContext.getExternalContext()).getJSFVersionTracker();

  // The tracker will be null if the user turned off the 
  // version tracking feature.  
                if (null != tracker) {
      // Get the versions of the current ViewHandler and
      // StateManager.  If they are older than the current
      // version of the implementation, fall back to the
      // JSF 1.1 behavior.
                    Version toTest = tracker.
                            getVersionForTrackedClassName(viewHandler.getClass().getName());
                    Version currentVersion = tracker.getCurrentVersion();
      boolean viewHandlerIsOld = false,
   stateManagerIsOld = false;
      
      viewHandlerIsOld = (toTest.compareTo(currentVersion) < 0);
      toTest = tracker.
   getVersionForTrackedClassName(facesContext.getApplication().getStateManager().getClass().getName());
      stateManagerIsOld = (toTest.compareTo(currentVersion) < 0);

                    if (viewHandlerIsOld || stateManagerIsOld) {
                        viewRoot = viewHandler.createView(facesContext, viewId);
                        if (null != viewRoot) {
                            facesContext.renderResponse();
                        }
                    }
                }
                
                if (null == viewRoot) {
                    Object[] params = {viewId};
                    throw new ViewExpiredException(MessageUtils.getExceptionMessageString(
                            MessageUtils.RESTORE_VIEW_ERROR_MESSAGE_ID, params), viewId);
                }
     }
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Postback: Restored view for " + viewId);
            }
 }
 else {
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("New request: creating a view for " + viewId);
            }
            // if that fails, create one
            viewRoot = (Util.getViewHandler(facesContext)).
                createView(facesContext, viewId);
            facesContext.renderResponse();
        } 
        assert (null != viewRoot);

        facesContext.setViewRoot(viewRoot);
        doPerComponentActions(facesContext, viewRoot);

        if (logger.isLoggable(Level.FINE)) {
            logger.fine("Exiting RestoreViewPhase");
        }
    }

    /**
     *
     * @return true if the request method is POST or PUT, or the method
     * is GET but there are query parameters, or the request is not an
     * instance of HttpServletRequest.
     */

    private boolean isPostback(FacesContext context) {
        // Get the renderKitId by calling viewHandler.calculateRenderKitId().
        String renderkitId = 
                context.getApplication().getViewHandler().
                calculateRenderKitId(context);
        ResponseStateManager rsm = RenderKitUtils.getResponseStateManager(context,
                renderkitId);
        return rsm.isPostback(context);
    }
A typical case is the following:

Step 1. The user visits a page the first time. And that page has a form.

Step 2. The user enters the data into the form and then submits the page.

In Step 1, JSF will execute two phases Restore_View and Render_Response. It creates the view in the Restoer_View phase. But here it is just an empty ViewRoot and it is put into the facescontext. In the Render_Response phase, JSF will creates the actual UI components and build the view. It will also save the view into the session using the class com.sun.faces.application.StateManagerImpl in this phase. In Step 2, by default, the page is submitted to the same page. JSF will go through all the phases in the lifecycle. Now looking at the method execute(...) of RestoreViewPhase, we can see an if-else clause. The condition is whether or not this mehtod

isPostback(facesContext)
will return true or false. The javadoc of this method states clearly that it will return true if the request method is POST or PUT, or the method is GET but there are query parameters, or the request is not an instance of HttpServletRequest. In our case, it is a form and method is POST, so the condition is true. Hence the view will be restored using the one saved in the session in Step 1. In a different case, suppose it is still the page that the user visited before. But this time it is a redirect as a result of the processing on the server side. Under this situation, the method isPostback(...) will return false. So even though the page has been visited before, a brand new view will be created just like in Step 1 described above. A typical case is that in the Invoke_Application phase of the lifecycle,JSF determines that everything is successful and invokes a redirect call to some page. Now no matter whether or not that page has been visited before, it will be considered to be a new request. And immmediately following the Invoke_Application phase, the actual call to the Render_Response phase will be skipped. Instead, a new JSF lifecycle will start. And since it is regarded a new request, only two phases Restore_View and Render_Response will be executed for the page that is redirected to.

So under the redirect situation, a view will be re-created just as when the page is visited the first time. But this is not the whole story. To make this more precise, there is some difference here from the first time the page is visited. In the appache tomcat implementation, when the page is visited the first time, the Render_Reponse phase also does the following:

  1. Calls the jsp compiler ( org.apache.jasper.compiler.Compiler ). This compiler will removeGeneratedFiles, generateJava, and generateClass for the jsp page. Note that the three phrases in bold are from the actual log file.
  2. Creates the managed beans used in the JSP page. If the scope of the bean is session, the bean will be stored in the session.
In the subsequest visists to the same page, these compiler actions won't happen. And the session-scoped beans do not need to be created again if it is in the same session.

A closer look at how the view is stored and retrieved

Simply put, a view is stored in the session. When a page is visited the first time, two phases Restore_View and Render_Response will be called. In the Render_Response phase, the method is the following:
public void execute(FacesContext facesContext) throws FacesException
{
   ......
   facesContext.getApplication().getViewHandler().renderView(facesContext, facesContext.getViewRoot());
   ......
}
The ViewHandler will eventually call the following:
stateManager.saveView(context);
where stateManager is an instance of com.sun.faces.applicaiton.StateManagerImpl. This method will in turn invokes the following:
/**
     * Return an opaque Object containing sufficient
     * information for this same instance to restore the state of the
     * current {@link UIViewRoot} on a subsequent request.  The returned
     * object must implement java.io.Serializable. If there
     * is no state information to be saved, return null
     * instead.
     *
     * Components may opt out of being included in the serialized view
     * by setting their transient property to true.
     * This must cause the component itself, as well as all of that component's
     * children and facets, to be omitted from the saved  tree structure
     * and component state information.
     *
     * 

This method must also enforce the rule that, for components with * non-null ids, all components that are descendants of the * same nearest {@link NamingContainer} must have unique identifiers. * * For backwards compatability with existing * StateManager implementations, the default * implementation of this method calls {@link #saveSerializedView} * and creates and returns a two element Object array * with element zero containing the structure property * and element one containing the state property of the * SerializedView. * * @since 1.2 * * @param context {@link FacesContext} for the current request * * @throws IllegalStateException if more than one component or * facet within the same {@link NamingContainer} in this view has * the same non-null component id */ public Object saveView(FacesContext context) { SerializedView view = saveSerializedView(context); Object stateArray[] = { view.getStructure(), view.getState() }; return stateArray; }

And the method saveSerializedView(...) does all the dirty work. Basically it will create two objects treeStructure and componentState from the facesContext in the following code:
public SerializedView saveSerializedView(FacesContext context)
          throws IllegalStateException {
  SerializedView result = null;
  Object treeStructure = null;
  Object componentState = null;
  ......
  result = new SerializedView(treeStructure =
              getTreeStructureToSave(context),
                                    componentState =
                                          getComponentStateToSave(context));

  ......
Object stateArray[] = {treeStructure, componentState};
......
actualMap.put(idInActualMap, stateArray);
......
}
In the above code, the Map object actualMap is in another Map logicalMap. And the logicalMap is created in sessionMap which is an object in the session.

Now in another lifecycle when the view needs to be restored, the Restore_View phase will call viewHander.restoreView(facesContext, viewId) in its execute(...) method. And the restoreView(...) method of the ViewHandlerImpl is the following:

public UIViewRoot restoreView(FacesContext context, String viewId,
                                  String renderKitId) {
   ......
   viewRoot = Util.getStateManager(context).restore(context,viewId,renderKitId);
   ......
}
So it basically uses the StateManage again to retrieve the view saved there before.

Thursday, October 6, 2011

A Note on JSF Lifecycle and Navigation Rule

The JSF text books or tutorials usually shows a clear picture of the jsf life cycle, which contains 6 phases. In particular, the last phase is Render Response phase, which comes after the Invoke Application phase. But this does not necessarily always happen depending on how you interpret the phase.

In the following analysis, the source code of jsf-api-1.2 and jsf-impl-1.2 are used.

The core of service(...) method in FacesServlet.java is the following:

try{
      lifecycle.execute(context);
      lifecycle.render(context);
   }catch(...)
   finally{
      context.release();
   }

It is worth noting that the render phase is called separately.

In the LifecycleImpl.java, the main contents of the two methods called by the servlet are the following:

private Phase phases[] = {
   null, // ANY_PHASE placeholder, not a real phase
   new RestoreViewPhase(),
   new ApplyRequestValuesPhase(),
   new ProcessValidationPhase(),
   new UpdateModelValuesPhase(),
   new InvokeApplicationPhase()
};

public void execute(FacesContext context) throws FacesException
{
   ...
   populateFacesELResolverForJsp(context);
   
   for(int i=1; i<phases.length; i++){
   
     if ( context.getRenderResponse() || context.getResponseComplete() ){
        break;
     }
     
     phase( (PhaseId)PhaseId.VALUES.get(i), phase[i], context);
     
     if ( reload( (PhaseId) PhaseId.VALUES.get(i), context)) {
         context.renderResponse();
     }
   }
}

public void render(FacesContext context) throws FacesException
{
    ...
    if ( !context.getResponseComplete()){
        phase(PhaseId.RENDER_RESPONSE, response, context);
    }
}


Note that in the execute(...) method, only the first 5 phases are iterated. Everytime the method phase(...) is called, it will log the message indicating that it is entering this phase and then exiting this phase. This log message can actually bring confusion. When do you think the life cycle has entered Render_Response phase? I think the lifecycel enters this phase when the FacesServlet calls the lifecycle.render(context) method. In this method, if the condition context.getResponseComplete() is true, then the phase(...) call to RENDER_RESPONSE will be skipped. You will never see the log message saying that it is entering or exiting the RENDER_RESPONSE phase. And this case actually happens quite normally. The following is one typical example.

In the example application called "javaquiz" described in the book <<Core JavaServer Faces>>, the first page displays a question. The JSF life cycle only goes through two phases: Restore_View and Render_Response. Now the user types in the correct answer on the screen. The browser will show the next page. In the log file, it shows the lifecycle goes through the phases 1-5. But it does not show phase 6 (RENDER_RESPONSE). Instead, after the phases 1-5, it shows the phase 1(RESTORE_VIEW) and 6(RENDER_RESPONSE). So what happened here? The truth is that after the user submits the answer, the lifecycle goes through phases 1-5. In phase 5 ( Invoke_Application), the NavigationHandlerImpl redirects to the viewId /success.jsp. When the FacesServlet calls the render(...) method. the condition context.getResponseComplete() returns true. So it does not call phase(PhaseId.RENDER_RESPONSE, response, context). Instead, the FacesServlet invokes another lifecycle for the page success.jsp.

In the access log file of Tomcat, you can actually see the following new messages after submitting the answer on the screen. The first log message is for index.faces because this is the page you submitted. The second log message is for success.faces. You actually did not submit this request. This is the result of the redirecting from phase 5.
127.0.0.1 - - [07/Oct/2011:10:26:32 -0400] "POST /javaquiz/index.faces HTTP/1.1" 302 -
127.0.0.1 - - [07/Oct/2011:10:26:36 -0400] "GET /javaquiz/success.faces HTTP/1.1" 200 1032
The actual call by the NavigationHandlerImpl for redirecting is in the following method:
public void handleNavigation(FacesContext context, String fromAction,
                                 String outcome) {
      ...
      ExternalContext extContext = context.getExternalContext();
      ...
      extContext.redirect(newPath), 
      ...
}

The following is the javadoc of the redirect(...) method called by the NavigationHandlerImpl:

/**
* Redirect a request to the specified URL, and cause the
* responseComplete() method to be called on the
* {@link FacesContext} instance for the current request.
* Servlet: This must be accomplished by calling the
* javax.servlet.http.HttpServletResponse method
* sendRedirect().
* Portlet: This must be accomplished by calling the
* javax.portlet.ActionResponse method
* sendRedirect().
* @param url Absolute URL to which the client should be redirected
* @throws IllegalArgumentException if the specified url is relative
* @throws IllegalStateException if, in a portlet environment,
*  the current response object is a RenderResponse
*  instead of an ActionResponse
* @throws IllegalStateException if, in a servlet environment,
*  the current response has already been committed
* @throws IOException if an input/output error occurs
*/
public abstract void redirect(String url)
throws IOException;

Thursday, September 15, 2011

Two-year Anniversary of the Blog

Just found that I have missed the blog's two-year anniversary date by 3 days. Today is already September 15.
While last year at this time some leaves had already turned red, this year it seems to be delayed a little bit. I planted two eggplants this year. Yesterday I picked up 5 eggplants. This year's tomatoes did not grow as well as last year's. Many of the tomatoes had cracks near the stem and other gargens had the same problem. Maybe this is because of the weather. There are still some green and red tomatoes in my garden. But I do not pick them up now because they do not look good.

Thursday, August 25, 2011

Use Maven To Run Ant Tasks To Build A Webservice Client

The maven-antrun-plugin allows you to run Ant tasks. The following is an example pom to use that plugin. It calls the weblogic clientgen Ant task to build a webservice client. The weblogic version used here is 10.3.2.
<?xml version="1.0" encoding="UTF-8"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.xyz.abc.app</groupId>
	<artifactId>serviceapp-ant</artifactId>
	<version>1.0</version>
	<packaging>jar</packaging>
	<name>serviceapp webservice client</name>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-antrun-plugin</artifactId>
				<version>1.6</version>

				<dependencies>
				
					<dependency>
						<groupId>com.sun</groupId>
						<artifactId>tools</artifactId>
						<version>1.6.0_14</version>
						<scope>system</scope>
						<systemPath>${java.home}/../lib/tools.jar</systemPath>
					</dependency>
				

					<dependency>
						<groupId>org.apache.xmlbeans</groupId>
						<artifactId>xmlbeans</artifactId>
						<version>2.4.0</version>
						<scope>provided</scope>
					</dependency>
			
					<dependency>
						<groupId>com.bea.core.logging</groupId>
						<artifactId>com.bea.core.logging</artifactId>
						<version>1.6.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.utils.classloaders</groupId>
						<artifactId>com.bea.core.utils.classloaders</artifactId>
						<version>1.6.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.annogen</groupId>
						<artifactId>com.bea.core.annogen</artifactId>
						<version>1.3.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.utils.full</groupId>
						<artifactId>com.bea.core.utils.full</artifactId>
						<version>1.7.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.xml.beaxmlbeans</groupId>
						<artifactId>com.bea.core.xml.beaxmlbeans</artifactId>
						<version>1.1.0.0_2-4-1</version>
						<scope>provided</scope>
					</dependency>
					
					<dependency>
						<groupId>com.bea.core.weblogic.stax</groupId>
						<artifactId>com.bea.core.weblogic.stax</artifactId>
						<version>1.6.0.0</version>
						<scope>provided</scope>
					</dependency>
					
					<dependency>
						<groupId>com.bea.core.xml.staxb.runtime</groupId>
						<artifactId>com.bea.core.xml.staxb.runtime</artifactId>
						<version>1.5.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.xml.staxb.buildtime</groupId>
						<artifactId>com.bea.core.xml.staxb.buildtime</artifactId>
						<version>1.4.1.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.sun.xml.ws</groupId>
						<artifactId>jaxws-rt</artifactId>
						<version>2.1.4</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>javax.mail</groupId>
						<artifactId>mail</artifactId>
						<version>1.4.1</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.descriptor</groupId>
						<artifactId>com.bea.core.descriptor</artifactId>
						<version>1.7.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.descriptor.j2ee.binding</groupId>
						<artifactId>com.bea.core.descriptor.j2ee.binding</artifactId>
						<version>1.3.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.descriptor.j2ee</groupId>
						<artifactId>com.bea.core.descriptor.j2ee</artifactId>
						<version>1.3.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.descriptor.wl</groupId>
						<artifactId>com.bea.core.descriptor.wl</artifactId>
						<version>1.3.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.descriptor.wl.binding</groupId>
						<artifactId>com.bea.core.descriptor.wl.binding</artifactId>
						<version>1.3.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.descriptor.settable.binding</groupId>
						<artifactId>com.bea.core.descriptor.settable.binding</artifactId>
						<version>1.6.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.weblogic.saaj</groupId>
						<artifactId>com.bea.core.weblogic.saaj</artifactId>
						<version>1.4.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.weblogic.workmanager</groupId>
						<artifactId>com.bea.core.weblogic.workmanager</artifactId>
						<version>1.7.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.management.core</groupId>
						<artifactId>com.bea.core.management.core</artifactId>
						<version>2.5.0.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>com.bea.core.i18n</groupId>
						<artifactId>com.bea.core.i18n</artifactId>
						<version>1.6.0.0</version>
						<scope>provided</scope>
					</dependency>

					<!-- JEE dependencies -->
					<dependency>
						<groupId>javax.xml</groupId>
						<artifactId>jaxrpc-api</artifactId>
						<version>1.2.1</version>
						<scope>provided</scope>
					</dependency>
					
					
					<dependency>
						<groupId>weblogic</groupId>
						<artifactId>webserviceclient</artifactId>
						<version>10.3.2.0</version>
						<scope>provided</scope>
					</dependency>
					<dependency>
						<groupId>weblogic</groupId>
						<artifactId>wlfullclient</artifactId>
						<version>10.3</version>
						<scope>provided</scope>
					</dependency>
					
				</dependencies>

				<executions>
					<execution>
						<phase>generate-sources</phase>
						<configuration>
							<target>
							
						        <!--	
							<property name="cp5" refid="maven.compile.classpath"/>
							<property name="cp6" refid="maven.plugin.classpath"/>
							<echo message="maven plugin classpath is ${maven.plugin.classpath}" />
							<echo  message="java ext dirs is ${java.ext.dirs}"/>
							<echo  message="cp6 is ${cp6}"/>
							-->
								
								<property name="generated.source.dir" value="target/generated-sources/wlclientgen"/>
								
								<taskdef name="clientgen"
									classname="weblogic.wsee.tools.anttasks.ClientGenTask"
									classpathref="maven.compile.classpath" />
								
								<!--  use dynamic wsdl url 
								<clientgen
									wsdl="http://localhost:7001/serviceappv2_ws/serviceapp?wsdl"
									destDir="target/generated-sources/wlclientgen"
									packageName="com.xyz.abc.app.ws.service.delegate.serviceapp.stub.jaxrpc"
									type="JAXRPC" />
								-->
								
								<clientgen
									wsdl="serviceapp.wsdl"
									destDir="${generated.source.dir}"
									packageName="com.xyz.abc.app.ws.service.delegate.serviceapp.stub.jaxrpc"
									type="JAXRPC" 
									/>
									
								<echo message="Make directory target/classes."/>
								<mkdir dir="${basedir}/target/classes"/>
								
								<echo message="Calling javac." />

								<javac srcdir="${generated.source.dir}"
									destdir="${basedir}/target/classes" classpathref="maven.plugin.classpath"
									includes="com/xyz/abc/app/ws/service/delegate/serviceapp/stub/jaxrpc/*.java" />

								<echo
									message="Copy xml and wsdl files from generated source to class path folder" />
								<copy
									todir="${basedir}/target/classes/com/xyz/abc/app/ws/service/delegate/serviceapp/stub/jaxrpc">
									<fileset
										dir="${generated.source.dir}/com/xyz/abc/app/ws/service/delegate/serviceapp/stub/jaxrpc">
										<include name="**/*.xml" />
										<include name="**/*.wsdl" />
									</fileset>
								</copy>
							</target>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

<dependencies>
   <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.3</version>
   </dependency>
   
   <dependency>
      <groupId>javax.xml</groupId>
      <artifactId>jaxrpc-api</artifactId>
      <version>1.2.1</version>
   </dependency>
								
   <dependency>
      <groupId>weblogic</groupId>
      <artifactId>webserviceclient</artifactId>
      <version>10.3.2.0</version>
      <scope>provided</scope>
   </dependency>

   <dependency>
      <groupId>weblogic</groupId>
      <artifactId>wlfullclient</artifactId>
      <version>10.3</version>
    </dependency>			

</dependencies>
	
</project>

Notes:
  1. This pom uses a jar jaxws-rt-2.1.4.jar. There are two implementations for this jar. One is from Sun. And the other is from Glassfish. The Glassfish implementation should be used. If you use the Sun's version, you will get a build exception "An Ant BuildException has occured: java.lang.NoSuchMethodError: getEncodedURL".
  2. For the wsdl file, you can point to an active URL. You can also point to an actual wsdl file copy in your local machine.
  3. In the above example, the execution is associated to the maven life cycle "generate-sources" phase. The target also creates some folder and copies the xml and wsdl files to a directory so they are on the classpath in the packaged artifact.

Tuesday, April 26, 2011

Java Cryptography Sample Code

Java Cryptography

Create cipher text on the Client side


We will use a property file to store some parameter values. The following is a sample property file:
#############  client.properties ##############

# type of keystore file
client.keystore.type = PKCS12

# location of keystore file on filesystem or in CLASSPATH
client.keystore.file = C:/foo.p12

# password for keystore
client.keystore.password = changeme

# alias for client's key
client.keystore.key.alias = foo

# password for private key
client.private.key.password = changeme

##########################################

  1. Use java keyStore to get the private key

    1. import java.security.KeyStore;
      import java.security.PrivateKey;
      import javax.crypto.Cipher;
      import javax.security.cert.X509Certificate;  
      
    2. Create a KeyStore object based on the KeyStore type (PKCS12 in this case):
      KeyStore clientKeyStore = KeyStore.getInstance( props.getProperty( CLIENT_KEYSTORE_TYPE ) );
    3. Load the keystore file:
      clientKeyStore.load( inputFile, props.getProperty( CLIENT_KEYSTORE_PASS_PROP ).toCharArray() );
      Here the input file is the file path and the name of the keystore file.
    4. Get the password for the keystore from the user property file:
      KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection( props.getProperty( CLIENT_PRIVATE_KEY_PASS_PROP ).toCharArray() );
    5. Get the PrivateKeyEntry using the keystore key alias and the key password:
      KeyStore.PrivateKeyEntry pkEntry = ( KeyStore.PrivateKeyEntry ) clientKeyStore.getEntry( props.getProperty( CLIENT_KEYSTORE_KEY_ALIAS_PROP ), keyPassword );
    6. Check to see if key is expired
      if( !X509Certificate.getInstance( pkEntry.getCertificate().getEncoded() ).getNotAfter().after( new Date() ) )
      {
      throw new Exception("The identity certificate has expired" );
      }
    7. Get the PrivateKey:
      return pkEntry.getPrivateKey(); 
      
      The above method returns an instance of PrivateKey.
  2. Use the PrivateKey to create a java Cipher:
    1. import javax.crypto.Cipher;
    2. Create a Cipher obect with some algorithm name as input:
      final Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
    3. Initialize the cipher using the privateKey object:
      cipher.init( Cipher.ENCRYPT_MODE, getPrivateKey( clientId ) );
    4. Return the cipher:
      return cipher;
  3. Use the Cipher to generate the cipher text:
    1. import javax.crypto.Cipher;
      import sun.misc.BASE64Encoder;
    2. Use Cipher:
      final byte[] cipherBytes = cipher.doFinal( ( "some plain text" ).getBytes() );
    3. Use encoder:
      String cipherText = new BASE64Encoder().encode( cipherBytes );

Note that usually the public key is used to encrypt a message. But here it is different. The private key is used to generate the encrypted message. This is more like to sign a message using the private key.

Decipher on the Server Side

You can also have a property file for parameters used in the decipher.
  1. Use the client ID to get the Certificate of the client.
    Note that when the client sends the cipherText, he can append the plain text clientId to the cipherText using some fixed format so the server can parse the result string and get the plain text clientId from it.
       import javax.security.cert.Certificate;
       import javax.security.cert.X509Certificate;
       Certificate clientCert = getCertificate( clientId );
    
    Here the method getCertificate() is just a method you implement. For example, you can save the certificates in LDAP and retrieve them from there.
  2. Use the Certificate to get the Public key and the Cipher
            Cipher cipher = Cipher.getInstance( "RSA" );
            cipher.init( Cipher.DECRYPT_MODE, clientCert.getPublicKey() );
    
  3. Use the Cipher to decode the cipherText.
    byte[] results = cipher.doFinal( new BASE64Decoder().decodeBuffer( cipherText ) ) );
Note that the key can be loaded as a file. The following is a sample.
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;

...

private void test(){
  ...
  InputStream is = new FileInputStream(new File("C:/temp/xyz.ser"));  
  ObjectInputStream objectinputstream = new ObjectInputStream(is);
  Key key = (Key) objectinputstream.readObject();

  if (objectinputstream != null)
    objectinputstream.close();
  cipher.init(Cipher.DECRYPT_MODE, key);
  ...
}

The file xyz.ser is the key. As an example, on linux the command "file xyz.ser" gives the following output: xyz.ser: Java serialization data, version 5

The following is a sample class that encrypts and then decrypts some text.

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;

import javax.crypto.Cipher;
import javax.security.cert.X509Certificate;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class Cryptography {
 private String CLIENT_KEYSTORE_TYPE = "PKCS12";
 private String inputFile = "path/to/your/keyfile.p12";
 private String CLIENT_KEYSTORE_PASSWORD = "yourpassword";
 private String CLIENT_PRIVATE_KEY_PASSWORD = "yourpassword";
 private String CLIENT_KEYSTORE_KEY_ALIAS = "yourAlias";

 private KeyStore.PrivateKeyEntry getKeyEntry() throws Exception {
  KeyStore clientKeyStore = KeyStore.getInstance(CLIENT_KEYSTORE_TYPE);
  InputStream is = new FileInputStream(new File(inputFile));
  clientKeyStore.load(is, CLIENT_KEYSTORE_PASSWORD.toCharArray());
  KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection(
    CLIENT_PRIVATE_KEY_PASSWORD.toCharArray());
  KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) clientKeyStore
    .getEntry(CLIENT_KEYSTORE_KEY_ALIAS, keyPassword);
  if (!X509Certificate.getInstance(pkEntry.getCertificate().getEncoded())
    .getNotAfter().after(new Date())) {
   throw new Exception("The identity certificate has expired");
  }
  return pkEntry;
 }

 private PrivateKey getPrivateKey() throws Exception {
  return getKeyEntry().getPrivateKey();
 }

 private PublicKey getPublicKey() throws Exception {
  return getKeyEntry().getCertificate().getPublicKey();
 }

 public String encrypt(String text) throws Exception {
  final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey());
  final byte[] cipherBytes = cipher.doFinal(text.getBytes());
  String cipherText = new BASE64Encoder().encode(cipherBytes);
  return cipherText;
 }

 public String decrypt(String cipherText) throws Exception {
  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.DECRYPT_MODE, getPublicKey());
  byte[] results = cipher.doFinal(new BASE64Decoder()
    .decodeBuffer(cipherText));
  return new String(results);
 }

 public void test() throws Exception {
  String text = "hello world";
  String encryptedText = encrypt("test " + text);
  System.out.println("EncryptedText is: " + encryptedText);
  String decryptedText = decrypt(encryptedText);
  System.out.println("Result is: " + decryptedText);
 }

 public static void main(String[] args) {
  Cryptography p = new Cryptography();
  try {
   p.test();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

Friday, January 28, 2011

Use Maven to Build ear

The following is an example of using Maven to build a Java ear application. The ear has one web module, one ejb module, and one jar module.

The top level directory

The top directory layout is as follows:
xyz
    xyz-common
    xyz-ear
    xyz-ejb
    xyz-web
    pom.xml

The file pom.xml is the following:
<?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.foo.xyz</groupId>
      <artifactId>xyz</artifactId>
      <version>1.0</version>
      <packaging>pom</packaging>
    
      <name>xyzmaven</name>
 
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <env>dev</env>
      </properties> 

        <profiles>      
          <profile>
           <id>dev</id>
           <properties>
            <env>dev</env>
           </properties>
          </profile>
          <profile>
           <id>prd</id>
           <properties>
            <env>prd</env>
           </properties>
          </profile>
     </profiles>
      
      <modules>
        <module>xyz-common</module>
        <module>xyz-web</module>
        <module>xyz-ejb</module>
        <module>xyz-ear</module>
      </modules>
</project>

In this top directory, run "mvn clean install" will build and install all the modules. One can also go to each individual module to run "mvn clean install".

xyz-common

This is a jar module that contains common classes used by other modules.
Its content layout:
src
  main
     java
  test
     java
pom.xml

The file pom.xml is as follows.
<?xml version="1.0" encoding="UTF-8"?>
   <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <modelVersion>4.0.0</modelVersion>
     <parent>
       <artifactId>xyz</artifactId>
       <groupId>com.foo.xyz</groupId>
       <version>1.0</version>
     </parent>
     <artifactId>xyz-common</artifactId>
     <packaging>jar</packaging>
     <version>1.0</version>
     <name>xyz-common</name>
     <build>
     <plugins>
     
        <plugin>
         <inherited>true</inherited>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <configuration>
          <source>1.6</source>
          <target>1.6</target>
         </configuration>
        </plugin>
        
        <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-surefire-plugin</artifactId>
       <configuration>
               <skipTests>true</skipTests>
        <testFailureIgnore>true</testFailureIgnore>
       </configuration>
      </plugin>
      
        <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <version>2.3.1</version>
         <executions>
            <execution>
                <goals>
                  <goal>test-jar</goal>    
                </goals>
            </execution>
       </executions>
        </plugin>
     
       </plugins>
     
      </build>
      <dependencies>
       <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring</artifactId>
        <version>2.5.5</version>
       </dependency>
     
     </dependencies>
     
   </project>
   

Notes:
  1. The test files are skipped.
  2. The goal "test-jar" will generate xyz-common-1.0-tests.jar

xyz-ejb

This is the ejb module. The file structure is the following.
src
    main
        java
        resources
            META-INF
               ejb-jar.xml
               weblogic-ejb-jar.xml
pom.xml


The file pom.xml is as the following:
<?xml version="1.0" encoding="UTF-8"?>
    <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <artifactId>xyz</artifactId>
        <groupId>com.foo.xyz</groupId>
        <version>1.0</version>
      </parent>
      <artifactId>xyz-ejb</artifactId>
      <version>1.0</version>
      <packaging>jar</packaging>
      <name>xyz-ejb Maven Webapp</name>
      <build>
        <!-- <finalName>xyz-ejb</finalName> -->
        <plugins> 
             <plugin>
         <inherited>true</inherited>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <configuration>
          <source>1.6</source>
          <target>1.6</target>
         </configuration>
             </plugin>
           
           
             <plugin>
         <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ejb-plugin</artifactId> 
      <version>2.3</version> 
      <configuration>
         <ejbVersion>2.1</ejbVersion>
      </configuration>
             </plugin>
          </plugins>
        
      </build>
      <dependencies>
         <dependency>
           <groupId>com.foo.xyz</groupId>
           <artifactId>xyz-common</artifactId>
           <version>1.0</version>
        </dependency>
        
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
Notes:
  1. Just run "mvn clean package" will create the xyz-ejb-1.0.jar. It seems that you do not
    need to run "mvn ejb:ejb".
  2. In this example, the ejb version used is the old 2.1 version.

After xyz-ejb-1.0.jar is built successfully, its file layout is as follows:
com
META-INF
   ejb-jar.xml
   weblogic-ejb-jar.xml


xyz-web

This is the web module. The file structure as follows.
src
              main
                     filters
                            filter-dev.properties
                            filter-prd.properties
                     java
                     resources
                            views.properties
                            messages.properties
                     webapp
                            some_jsp_folder
                            WEB-INF
                                   flows
                                   jsp
                                   other_folders
                                   tld
                                   faces-config.xml
                                   web.xml
                                   weblogic.xml
                                   xyz-servlet.xml

       pom.xml


The file pom.xml is as follows.
<?xml version="1.0" encoding="UTF-8"?>
    <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <artifactId>xyz</artifactId>
        <groupId>com.foo.xyz</groupId>
        <version>1.0</version>
      </parent>
      <artifactId>xyz-web</artifactId>
      <version>1.0</version>
      <packaging>war</packaging>
      <name>xyz-web Maven Webapp</name>   
      
      <build>
        <!-- <finalName>xyz</finalName> -->
        <filters>
       <filter>${basedir}/src/main/filters/filter-${env}.properties</filter>
      </filters>
        <resources>
         <resource>
          <directory>${basedir}/src/main/resources</directory>
          <filtering>true</filtering>
         </resource>
    
        
        </resources>
        <plugins>
         <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <configuration>
           <source>1.6</source>
           <target>1.6</target>
          </configuration>
         </plugin>
      
         <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <configuration>
           <testFailureIgnore>true</testFailureIgnore>
          </configuration>
         </plugin>
      
        
       <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
                <webResources>
              <resource>
         <directory>${basedir}/src/main/webapp/WEB-INF</directory>
         <filtering>true</filtering>
         <targetPath>WEB-INF</targetPath>
           <includes>
             <include>xyz-servlet.xml</include>
             <include>web.xml</include>
             <include>jsp/css/xp.css</include>
             <include>jsp/shared/header_jsf.jsp</include>
             <include>jsp/shared/mainTemplate.xhtml</include>
           </includes>
              </resource>
              
              <resource>
               <directory>${basedir}/src/main/webapp</directory>
               <filtering>true</filtering>
               <includes>
                   <include>fooDir/foo.xhtml</include>
                   <include>css/xp.css</include>
               </includes>
              </resource>
              
           </webResources>
         </configuration>
       </plugin>
      
        </plugins>
     </build>
     
      <dependencies>
                    <dependency>
             <groupId>icefaces.icefaces-facelets</groupId>
             <artifactId>icefaces-facelets</artifactId>
             <version>1.6.2</version>
            </dependency>
            <dependency>
             <groupId>icefaces.icefaces-comps</groupId>
             <artifactId>icefaces-comps</artifactId>
             <version>1.6.2</version>
        </dependency>
      </dependencies>
    </project>
    

Notes:
  1. One important thing is how to filter files. Here maven-war-plugin is used.

After xyz-web-1.0.jar is built successfully, its file layout is as follows:
some_jsp_folder
      WEB-INF
            classes
                  messages.properties
                  views.properties
            flows
            jsp
            other_folders
            tld
            lib
                  icefaces-facelets-1.6.2
                  icefaces-comps-1.6.2.jar
            web.xml
            xyz-servlet.xml
            weblogic.xml
            faces-config.xml


xyz-ear


This is the ear module that is the final product to be deployed. Its file structure is as follows:
src
    main
      application
        APP-INF
          classes
            hibernate
               foo.hbm.xml
            spring
               xyzContext.xml
            log4j.properties     
        META-INF
          application.xml
      filters
          filter-dev.properties
      java
pom.xml



The file pom.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
       <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
         <modelVersion>4.0.0</modelVersion>
         <parent>
           <artifactId>xyz</artifactId>
           <groupId>com.foo.xyz</groupId>
           <version>1.0</version>
         </parent>
         <artifactId>xyz-ear</artifactId>
         <packaging>ear</packaging>
         <version>1.0</version>
         <name>xyz-ear</name>
        
         
           <build>
             <finalName>xyz</finalName>
             <filters>
              <filter>${basedir}/src/main/filters/filter-${env}.properties</filter>
             </filters>
           
             <plugins>
               <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-ear-plugin</artifactId>
                <version>2.4.2</version>
       
                 <!-- configuring the ear plugin -->
                 <configuration>
                    <filtering>true</filtering>
                   <defaultLibBundleDir>APP-INF/lib</defaultLibBundleDir>
       
                   <modules>
                     <webModule>
                       <groupId>com.foo.xyz</groupId>
                       <artifactId>xyz-web</artifactId>
                     </webModule>
                     <ejbModule>
                       <groupId>com.foo.xyz</groupId>
                       <artifactId>xyz-ejb</artifactId>
                     </ejbModule>
                     
                     <jarModule>
                         <groupId>weblogic</groupId>
                         <artifactId>weblogic</artifactId>
                         <excluded>true</excluded>
               </jarModule>
                   </modules>
                 </configuration>
               </plugin>
               
             <plugin>
         <groupId>scm.plugins</groupId>
                <artifactId>scm-wls-plugin</artifactId>
                <configuration>
         <deployName>xyz</deployName>
         <deploymentName>xyzWLdeploy</deploymentName>
         <artifactPath>C:\workshop\xyz\mavenxyz\xyz-ear\target\xyz.ear</artifactPath>
         <adminServerHostName>localhost</adminServerHostName>
         <adminServerPort>7001</adminServerPort>
         <adminServerProtocol>t3</adminServerProtocol>
         <userId>weblogic</userId>
         <password>weblogic1</password>
         <targetNames>xyzAdminServer</targetNames>
         <verbose>false</verbose>
         <debug>false</debug>
         <upload>true</upload>
         <remote>true</remote>
         </configuration>
               </plugin>
          
             </plugins>
           </build>
           
           <dependencies>
                 <!-- web and ejb modules -->
                 <dependency>
                   <groupId>com.foo.xyz</groupId>
                   <artifactId>xyz-ejb</artifactId>
                   <version>1.0</version>
                   <type>ejb</type>
                 </dependency>
                 <dependency>
                   <groupId>com.foo.xyz</groupId>
                   <artifactId>xyz-web</artifactId>
                   <version>1.0</version>
                   <type>war</type>
                 </dependency>
                 
                 <dependency>
                <groupId>com.foo.xyz</groupId>
                <artifactId>xyz-common-test</artifactId>
                <version>1.0</version>
          </dependency>
       
          <dependency>
            <groupId>antlr</groupId> 
            <artifactId>antlr</artifactId> 
            <version>2.7.6</version> 
          </dependency>
      
       </dependencies>
         
       </project>
  

The file application.xml is the following:
<?xml version="1.0" encoding="UTF-8"?>
   <application xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.4">
 
   <display-name>XYZ</display-name>
     <module>
       <ejb>xyz-ejb-1.0.jar</ejb>
     </module>
     <module>
       <web>
         <web-uri>xyz-web-1.0.war</web-uri>
         <context-root>xyz</context-root>
       </web>
     </module>
   </application>
Notes:
  1. The scm-wls-plugin plugin in the pom is a customer-made plugin.
  2. The generated ear will contain all the dependent jars in the xyz-common module and put them into the directory APP-INF/lib. If you do not want some of them to be included, use "<excluded>true</excluded>" in the jarModule as is the case for weblogic.jar in the above pom file.
  3. If additional jars are needed for the ear, just add them in <dependencies>.
  4. By configuing filtering to be true in the maven-ear-plugin, it will filter files in the
    application directory.

After the ear is built successfully, the exploded ear has the following file structure.
xyz
    APP-INF
        classes
            hibernate
                foo.hbm.xml
            spring
            xyzContext.xml
            log4j.properties
        lib
            antlr-2.7.6.jar
            other_jars from the xyz-common dependencies
    META-INF
        application.xml
    xyz-ejb-1.0.jar
    xyz-web-1.0.war

Monday, January 10, 2011

How To Show The Actual Command Line That Eclipse Uses To Launch The Java Program?

You can launch a java program in Eclipse. The console view will show the results.
Often times it will be very helpful to know the actual java command line used by Eclipse.
And I often forget how to do that. Here is the answer.
  1. In the menu bar, select Window --> Open Perspective --> Debug.
  2. In the debug view, you can see a simple line of the command you just ran.
  3. Right click on the line and select Properties. You will see the actual command line.

Windows Process Commandline

For a Windows process, you can view it in the Windows Task Manager. By default, Task Manager does not show the command line for the process. But you can go to "View"-->"Select columns..." and then check "Command Line" in the list. Task Manager will display a new column for command lines. But it seems that if the command line is very long, then only part of it will be displayed. There are the following ways to get the full command line.
  1. Download Microsoft's official "Process Explorer". This tool gives more detailed information about the processes. After launching "Process Explorer", you can right-click on a process and then select "Properties". Then click on the "Image" tab to see the full command line.
  2. Use the Windows Management Instrumentation Command-line (WMIC) tool. For example, you can execute the following directly in the Windows command line console:
    wmic path win32_process get name, commandline > commandline.txt
    
    The following will show all available attributes:
    wmic path win32_process get /format:list
    

Friday, January 7, 2011

Concept Clarification of IBM DB2, AS400, Mainframe, etc.

There are many technical names related to DB2, AS400 etc from IBM. These are confusing. Here are some clarification.

DB2 is a relational model database server developed by IBM. The name confusion mainly comes from the various platforms that DB2 runs on. On different platforms, DB2 is different. It has different features and may be even written in different languages. To differentiate products on different platforms, a formal name IBM uses is "product FOR platform". For example, DB2 for OS/390, DB2 for z/OS, DB2 for i.

AS/400 is a system that includes both an operating system (OS/400), DB2, and others.
AS/400 is now called IBM System i (iSeries ), or more recently IBM power system. And its operating system OS/400 is now called IBM i operating system.

z/OS is a 64-bit operating system for mainframe computers, produced by IBM. It is the successor to OS/390, which in turn followed a string of MVS versions.

AS/400 is not a mainframe system. The IBM System i is a midrange computer system for i users. In 2008, IBM announced its integration with the System p platform. The unified product line is called IBM Power Systems and features support for the IBM i (previously known as i5/OS or OS/400), AIX and Linux operating systems.

DB2 UDB stands for DB2 Universal Database. It used to mean DB2 for the Linux-unix-Windows version. Now it can also mean DB2 on mainframe.

At this point, the mainframe version of DB2 UDB and the server version of DB2 UDB were coded in entirely different languages(PL/S for the mainframe and C++ for the server).

DB2 UDB Version 8 for z/OS now requires a 64-bit system.

In 2006, IBM announced "Viper": DB2 9 on both distributed platforms and z/OS.
In 2009, IBM announced "Cobra": DB2 9.7 for LUW(Linux, Unix, Windows).
In 2009, IBM announced DB2 pureScale. It is a database cluster soluction for non-mainframe platforms.
In 2010, IBM announced that DB2 10 for z/OS would enter beta testing.

DB2 for i(the former DB2/400) is very closely incorporated into the operating system of the IBM System i machines.

Reference

[1] http://en.wikipedia.org/wiki/IBM_DB2
[2] http://en.wikipedia.org/wiki/Z/OS
[3]http://search400.techtarget.com/expert/KnowledgebaseAnswer/0,289625,sid3_cid414164,00.html