Thread question

Hello, i have a portlet very basic, so i would like to test a threads but it did’t work which may be, if i run it with the method run it work but if i run it with the method start it don’t. I paste the code so if anyone can help to know why it doesn’t work.

package com.webmethods.caf.prueba_threads;


class hil extends com.webmethods.caf.faces.bean.BasePageBean implements Runnable{ //class runnable to start threads
    private com.webmethods.caf.is.wsclient.ws.log.Log1 log = null;
    public com.webmethods.caf.is.wsclient.ws.log.Log1 getLog()  {
        if (log == null) {
            log = (com.webmethods.caf.is.wsclient.ws.log.Log1)resolveExpression("#{Log}");
        }
    
        resolveDataBinding(LOG_PROPERTY_BINDINGS, log, "log", false, false);
        return log;
    }
    private static final String[][] LOG_PROPERTY_BINDINGS = new String[][] {
        {"#{Log.authCredentials.authenticationMethod}", "1"},
        {"#{Log.authCredentials.requiresAuth}", "true"},
        {"#{Log.autoRefresh}", "false"},
        {"#{Log.socketTimeout}", "#{environment[\"wsclient-socketTimeout\"]}"},
        {"#{Log.authCredentials.userName}", "#{environment[\"wsclient-username\"]}"},
        {"#{Log.authCredentials.password}", "#{environment[\"wsclient-password\"]}"},
        {"#{Log.endpointAddress}", "#{environment[\"wsclient-endpointAddress\"]}/ws/ws:log"},
    };
    
    public void run() {
        error("ok");
        getLog().refresh();
        
    }
}

public class PruebaThreadsDefaultviewView  extends   com.webmethods.caf.faces.bean.BasePageBean {
    private static final long serialVersionUID = 1L;
    private static final String[][] INITIALIZE_PROPERTY_BINDINGS = new String[][] {
    };
    private com.webmethods.caf.prueba_threads.PruebaThreads pruebaThreads = null;
    private com.webmethods.caf.is.wsclient.ws.log.Log1 log = null;
    private static final String[][] LOG_PROPERTY_BINDINGS = new String[][] {
        {"#{Log.authCredentials.authenticationMethod}", "1"},
        {"#{Log.authCredentials.requiresAuth}", "true"},
        {"#{Log.autoRefresh}", "false"},
        {"#{Log.socketTimeout}", "#{environment[\"wsclient-socketTimeout\"]}"},
        {"#{Log.authCredentials.userName}", "#{environment[\"wsclient-username\"]}"},
        {"#{Log.authCredentials.password}", "#{environment[\"wsclient-password\"]}"},
        {"#{Log.endpointAddress}", "#{environment[\"wsclient-endpointAddress\"]}/ws/ws:log"},
    };
    /**
     * Initialize page
     */
    public String initialize()  {
        try {
            
            Thread a = new Thread(new hil()); //NEW THREADS
            a.start();//NOT WORK?????
            a.run();//WORK FINE
            
            resolveDataBinding(INITIALIZE_PROPERTY_BINDINGS, null, "initialize", true, false);
            
            return OUTCOME_OK;
        } catch (Exception e) {
            error(e);
            log(e);
            return OUTCOME_ERROR; 
        }    
    }

    public com.webmethods.caf.prueba_threads.PruebaThreads getPruebaThreads()  {
        if (pruebaThreads == null) {
            pruebaThreads = (com.webmethods.caf.prueba_threads.PruebaThreads)resolveExpression("#{PruebaThreads}");
        }
        return pruebaThreads;
    }

    public com.webmethods.caf.is.wsclient.ws.log.Log1 getLog()  {
        if (log == null) {
            log = (com.webmethods.caf.is.wsclient.ws.log.Log1)resolveExpression("#{Log}");
        }
    
        resolveDataBinding(LOG_PROPERTY_BINDINGS, log, "log", false, false);
        return log;
    }

    
}

The FacesContext is tied to the thread that is processing the http request. If you spawn another thread, you will have to create a new FacesContext in that new thread before any of the JSF related code will work in that thread.

So your options are to:

  • Don’t use any JSF related APIs in the code running inside your thread. (preferred)
  • Wrap the code in the run() method of your thread with code that creates a private FacesContext for your worker thread. This can be tricky since JSF generally assumes it is running inside a thread that is processing an http request so you have to mock the request/response objects to make it function.

Thanks you Eric Norman:
I think that is very complicate to make a thread inside a portlet, and i don’t understand very well your technique to make a thread that you post here, please if you have any example, i would like to see it. Thanks you.

I haven’t tried this in a real application, but the code would look something like this in the run() method of your thread:


public void run() {
    javax.faces.context.FacesContext facesContext = null;
    try {
        //create a local FacesContext for this thread using a fake http request/response/session
        facesContext = com.webmethods.portal.framework.faces.context.PortalFacesContextFactory.createContext("wm_your_app_name_here");

        //TODO: errors reported via the error API would not make it back to
        // the end user.
        /* 
        error("ok");
        */

        //NOTE: if you need to convey errors or other data back the the 
        // browser, you would need some other technique.  Since the http
        // request/response will be gone while this thread is running.
        // eg. Something like raising an OpenAjax event in this thread and 
        //  an OpenAjax Script in the portlet that listens for those events.
            
        //do the work
        getLog().refresh();          
    } finally {
        if (facesContext != null) {
            //release the context when done.
            facesContext.release();
        }
    }
}      

Thanks you Eric, i will try it. Don’t you have a email if you dont mind so in a future i can write you directly to you, thanks you very much.