9.4. Custom Factories

BlazeDS destinations by default hook up to simple Java classes or POJOs. These destination classes are instantiated, and their lifecycle is managed, by BlazeDS.

The creation and lifecycle management processes for objects like EJBs and Spring beans (i.e., components used by the Spring Framework) are handled by their specialized containers. Further, these objects exist in their own independent namespace. In such cases, BlazeDS needs to leverage the object-specific creation and lifecycle management policy to use it within its domain.

BlazeDS includes a factory mechanism that you can leverage to instantiate and manage EJBs, Spring beans, and other such managed objects. All you need to do is create a special factory class for your managed component. Such special factory classes need to implement the flex.messaging.FlexFactory interface. Once available, the special factory class is used to create a FactoryInstance, which is associated with a destination and is used to get a reference to the managed object.

Here, I create a simple specialized factory to use EJB3 objects as destinations. You will benefit from looking at the source code first. The source for the EJB3Factory class is shown in Listing 9-2.

Example 9.2. A Custom Factory to Use EJB3 Objects as BlazeDS Destinations
package dsadapters.remoting.factories;

import flex.messaging.FactoryInstance;
import flex.messaging.FlexFactory;
import flex.messaging.config.ConfigMap;
import flex.messaging.services.ServiceException;
import java.text.MessageFormat;
import javax.naming.Context;

import javax.naming.InitialContext;
import javax.naming.NamingException;

public class EJB3Factory implements FlexFactory
{

    /* (non-Javadoc)
     * @see flex.messaging.FlexFactory#createFactoryInstance(java.lang.String,
        flex.messaging.config.ConfigMap)
     */
    @Override
    public FactoryInstance createFactoryInstance(String id, ConfigMap configMap)
    {
        FactoryInstance factoryInstance = new FactoryInstance(this, id, configMap);
        factoryInstance.setSource(configMap.getPropertyAsString(SOURCE_CLASS,
           factoryInstance.getId()));

        return factoryInstance;
    }

    /* (non-Javadoc)
     * @see flex.messaging.FlexFactory#lookup(flex.messaging.FactoryInstance)
     */
    @Override
    public Object lookup(FactoryInstance factoryInstance)
    {
        Object ejb3Object = null;
        try
        {
            ejb3Object = locate(factoryInstance.getSource());
        }
        catch(Exception e)
        {
            throw createServiceException(MessageFormat.format("error referencing
               EJB {0}, {1}",
                    new Object[] { factoryInstance.getSource(), e.getMessage() } ),
                       e );
        }

        return ejb3Object;
    }

    /* (non-Javadoc)
     * @see flex.messaging.FlexConfigurable#initialize(java.lang.String, flex.
        messaging.config.ConfigMap)
     */
    @Override
    public void initialize(String id, ConfigMap configMap)
    {
        /**
         * No initialization required for this EJB3Factory
         */
    }

protected ServiceException createServiceException(final String message, final
       Throwable cause )
    {
         ServiceException serviceException = new ServiceException();
         serviceException.setMessage(message);
         serviceException.setRootCause(cause);
         serviceException.setDetails(message);
         serviceException.setCode(ERROR_CODE);

         return serviceException;
    }

    protected Object locate(String name) throws Exception
      {
         try
         {
            final Context ctx = new InitialContext();
            final Object reference = ctx.lookup(name);
            return reference;
         }
         catch (NamingException e)
         {
             e.printStackTrace();
            throw new Exception( MessageFormat.format(
                  "error locating local resource {0}", new Object[]
                  {name} ), e );
         }
      }

    private static final String SOURCE_CLASS = "source";
    private static final String ERROR_CODE = "EJB.Invocation";

}

The FlexFactory interface defines three methods as a part of the factory class contract. These three methods are:

  • createFactoryInstance—A method that returns a FactoryInstance object for the factory

  • lookup—A method that finds and retrieves the managed object

  • initialize—A method where any properties and initialization parameters can be set for the factory

In the preceding EJB3 factory, the lookup method merely looks up an EJB object from a JNDI (Java Naming and Directory Interface) repository and returns a reference to it. The locate method implements the specifics of how the EJB instance is looked up.

In the locate method, you create an instance of the InitialContext class and use that instance to look up an EJB object by its JNDI name. An InitialContext instance provides a starting point into the namespace from where the naming and directory service can be accessed.

In the preceding code listing, a local JNDI resource is accessed. You may be aware that JNDI is supported by Java EE application servers, for example the JBoss AS. If your JNDI repository is remote, be sure to set the URL to the JNDI repository as the PROVIDER_URL in a Hashtable instance and then pass that Hashtable to the constructor of the InitialContext instance. To illustrate this further, let jnp://someHostName:1099 be the URL to your JNDI repository; you can then bind this repository to your InitialContext as follows:

Hashtable env = new Hashtable();
....
env.put(Context.PROVIDER_URL, providerURL);
....
InitialContext initialContext = new InitialContext(env);

Now that the custom factory is ready, let's see how you could use it. First, add the custom factory within the factories property of the service-config.xml and then use the factory with a destination.

A factory could be added to the set of factories in services-config.xml as follows:

<factories>
    <factory id="myCustomFactory" class="dsadapters.remoting.factories.EJB3Factory">
        <properties>
            ....
        </properties>
    </factory>
</factories>

The custom EJB3 factory does not specify any attributes that need to be passed in to the factory instance, so you do not add any properties to the configuration. If you created a factory that accepted an attribute (say myAttribute) and you wanted to configure a value, myAttributeValue, for that attribute, then you would need to configure the factory as follows:

<factories>
    <factory id="myCustomFactory" class="dsadapters.remoting.factories.EJB3Factory">
        <properties>
            <myAttribute>
                myAttributeValue
            </myAttribute>
        </properties>
    </factory>
</factories>

Factory-specific attribute values are set to a factory using its initialize method. In the initialize method, you can access the passed-in attribute, using the getPropertyAsString method of the passed in ConfigMap object, which holds all the configured properties specified in the configuration file.

Once the factory is configured it can be used with a destination as follows:

<destination id="myDestination">
    <properties>
        <source>packageName.RemoteEJBClassName</source>
        <factory>myCustomFactory</factory>
    </properties>
</destination>

That's about it! You have learned how to extend a remoting adapter and how to create a custom factory. Next, you learn to create a custom messaging adapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.156.235