My apologies for the delay in my response and for the lack of
detailed docs. We'll work on improving the documentation, but in
the meantime the basic idea is that you have a single FlexFactory
instance which gets created for each flex-enabled web application.
This instance can have its own configuration properties though in
this case, we do not have any required properties to configure the
factory. In your services-config.xml file, you'd add something like
the following:
<factories>
<factory id="spring"
class="flex.samples.factories.SpringFactory" />
</factories>
Flex will create one FlexFactory instance for each tag you
specify. Flex will use this one global FlexFactory implementation
for each destination which specifies that factory by its id using
the factory tag. For example, you might have this in your
remoting-config.xml file:
<destination id="WeatherService">
<properties>
<factory>spring</factory>
<source>weatherBean</source>
</properties>
</destination>
when this tag is encountered at startup, FDS calls the
FlexFactory.createFactoryInstance method. That method gets the
<source> and any other attributes it expects in the
configuration. Any attributes you access from the ConfigMap
parameter are marked as "expected" and will not cause a
configuration error so you can extend Flex's default configuration
in this manner. When flex wants to actually needs an instance of
the component for this destination, it calls the
FactoryInstance.lookup method to retrieve the individual instance
for that destination.
Here's a working implementation of the SpringFactory class:
-----
package flex.samples.factories;
import org.springframework.context.ApplicationContext;
import
org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.beans.BeansException;
import
org.springframework.beans.factory.NoSuchBeanDefinitionException;
import flex.messaging.FactoryInstance;
import flex.messaging.FlexFactory;
import flex.messaging.config.ConfigMap;
import flex.messaging.services.ServiceException;
/**
* This interface is implemented by factory components which
provide
* instances to the flex messaging framework. To configure
flex data services
* to use this factory, add the following lines to your
services-config.xml
* file (located in the WEB-INF/flex directory of your web
application).
*
* <factories>
* <factory id="spring"
class="flex.samples.factories.SpringFactory" />
* </factories>
*
* You also must configure the web application to use spring
and must copy the spring.jar
* file into your WEB-INF/lib directory. To configure your
app server to use spring,
* you add the following lines to your WEB-INF/web.xml file:
*
* <context-param>
*
<param-name>contextConfigLocation</param-name>
*
<param-value>/WEB-INF/applicationContext.xml</param-value>
* </context-param>
*
* <listener>
*
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
* </listener>
*
* Then you put your spring bean configuration in
WEB-INF/applicationContext.xml (as per the
* line above). For example:
*
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "
http://www.springframework.org/dtd/spring-beans.dtd"> *
* <beans>
* <bean name="weatherBean"
class="dev.weather.WeatherService" singleton="true"/>
* </beans>
*
* Now you are ready to define a destination in flex that
maps to this existing service.
* To do this you'd add this to your
WEB-INF/flex/remoting-config.xml:
*
* <destination id="WeatherService">
* <properties>
* <factory>spring</factory>
* <source>weatherBean</source>
* </properties>
* </destination>
*
* @author Jeff Vroom
*/
public class SpringFactory implements FlexFactory
{
private static final String SOURCE = "source";
/**
* This method can be used to initialize the factory itself.
It is called with configuration
* parameters from the factory tag which defines the id of
the factory.
*/
public void initialize(String id, ConfigMap configMap) {}
/**
* This method is called when we initialize the definition of
an instance
* which will be looked up by this factory. It should
validate that
* the properties supplied are valid to define an instance.
* Any valid properties used for this configuration must be
accessed to
* avoid warnings about unused configuration elements. If
your factory
* is only used for application scoped components, this
method can simply
* return a factory instance which delegates the creation of
the component
* to the FactoryInstance's lookup method.
*/
public FactoryInstance createFactoryInstance(String id,
ConfigMap properties)
{
SpringFactoryInstance instance = new
SpringFactoryInstance(this, id, properties);
instance.setSource(properties.getPropertyAsString(SOURCE,
instance.getId()));
return instance;
}
/**
* Returns the instance specified by the source
* and properties arguments. For the factory, this may mean
* constructing a new instance, optionally registering it in
some other
* name space such as the session or JNDI, and then returning
it
* or it may mean creating a new instance and returning it.
* This method is called for each request to operate on the
* given item by the system so it should be relatively
efficient.
* <p>
* If your factory does not support the scope property, it
* report an error if scope is supplied in the properties
* for this instance.
*/
public Object lookup(FactoryInstance inst)
{
SpringFactoryInstance factoryInstance =
(SpringFactoryInstance) inst;
return factoryInstance.lookup();
}
static class SpringFactoryInstance extends FactoryInstance
{
SpringFactoryInstance(SpringFactory factory, String id,
ConfigMap properties)
{
super(factory, id, properties);
}
public String toString()
{
return "SpringFactory instance for id=" + getId() + "
source=" + getSource() + " scope=" + getScope();
}
public Object lookup()
{
ApplicationContext appContext =
WebApplicationContextUtils.getWebApplicationContext(flex.messaging.FlexContext.getServletConfig().getServletContext());
String beanName = getSource();
try
{
return appContext.getBean(beanName);
}
catch (NoSuchBeanDefinitionException nexc)
{
ServiceException e = new ServiceException();
String msg = "Spring service named '" + beanName + "' does
not exist.";
e.setMessage(msg);
e.setRootCause(nexc);
e.setDetails(msg);
e.setCode("Server.Processing");
throw e;
}
catch (BeansException bexc)
{
ServiceException e = new ServiceException();
String msg = "Unable to create Spring service named '" +
beanName + "' ";
e.setMessage(msg);
e.setRootCause(bexc);
e.setDetails(msg);
e.setCode("Server.Processing");
throw e;
}
}
}
}
Let me know if you have any questions or run into any
problems. Regards,
Jeff Vroom
Flex Data Services Team