Expand my Community achievements bar.

Dive into Adobe Summit 2024! Explore curated list of AEM sessions & labs, register, connect with experts, ask questions, engage, and share insights. Don't miss the excitement.

FlexFactory Example

Avatar

Level 2
I'm wanting to use Spring for my backend for Flex Data
Services. I

found the docs on using a class that implements the
FlexFactory

interface, but the really is not enough detail in the docs to
fully

understand how to fill out the FlexFactory implementation
class.



Has anyone successfully used this class? Do I create a single

FlexFactory class for all of my destinations that I want to
use Spring

with? Or do I create a FlexFactory impl for each destination?



Thanks

Bill
29 Replies

Avatar

Level 3
I read through that piece of documentation as well (
http://livedocs.macromedia.com/flex/2/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Pa...




What I did instead is made my Spring classes
ApplicationContextAware. I then load my classes at application
start-up.



Ken

Avatar

Level 2
Thanks for the reply Ken. So are you just making your Flex
Assembler classes for each domain object ApplicationContextAware?
Or are you using Spring in some deeper level behind the Assemblers?
And have you managed to integrate Acegi security as well doing
this?



Thanks for your help.

Bill

Avatar

Level 3
I have a base class that I use for my DAO classes that is
ApplicationContextAware. I figure you could do the same with your
assembler classes, but I am not currently making them
ApplicationContextAware.



My DAO classes extends HibernateDaoSupport implements
Serializable , ApplicationContextAware. This way I have very little
code in my DAO classes.



As far as the assembler goes, pretty much the same. My base
class is a workhorse for 80% of what I have to do. I extend my base
class functionality for each assembler I need. but generally only
need to let it know what bean to load.



public class DAOAssembler implements
flex.data.assemblers.Assembler

{

private ApplicationContext ac;

private GCHibernateSupport bean;

private SessionFactory sessionFactory;



private String DAO_CLASS = "";

private String ID_COLUMN = "";

private static String CONTEXT_LOCATION =
"/spring-config.xml";

private Logger logger;



public DAOAssembler()

{

this.startLogger();

}



public DAOAssembler(String dao, String idColumn) throws
Exception

{

try

{

this.startLogger();



logger.debug("DAO: " + dao);

logger.debug("ID: " + idColumn);



this.DAO_CLASS = dao;

this.ID_COLUMN = idColumn;



this.ac = new
ClassPathXmlApplicationContext(CONTEXT_LOCATION);

bean = (GCHibernateSupport) this.ac.getBean(this.DAO_CLASS);


sessionFactory = bean.getSessionFactory();

}

catch(Exception e)

{

logger.error(e.toString(), e);

throw(e);

}

}

.

.

.

}



I extend this to something like



package com.sanclementetech.dao.flex;



import com.sanclementetech.dao.DAOAssembler;



/**

* @author Ken

*

*/

public class ContactAddressTypeAssembler extends DAOAssembler
{



private static String DAO = "ContactAddressTypeDAO";

private static String ID = "contactAddressTypeId";



public ContactAddressTypeAssembler() throws Exception

{

super(DAO, ID);

}

}



I am not a Spring expert but this works. Then I can use FDS
to access the assembler, which communicates with the my DAO's which
are already loaded because they are ApplicationContextAware.



So I guess the real idea is to use the Assemblers as POJO's
and then have your other Spring "stuff" ApplicationContextAware so
that it can be resolved.



Hope this helps.



Ken

Avatar

Level 2
This is good stuff. Thanks for the post! I'll give this a try
as an alternative to the FlexFactory since it doesn't appear to be
a well documented function yet.



:)

Thanks!

Avatar

Level 2
Update: I've been unable to find any detailed documentation
on how to use the FlexFactory and no one seems to be discussing it
much in the forums here or elsewhere. Therefore, I began playing
around with it in order to see if I could make it work. As best I
can tell, here is the basic premise:



When working with FDS and Java, you need an Assembler class
to create, update, delete, etc the Java objects on the backend that
will be displayed on the flash frontend. You can create your
assemblers manually and list them in the
data-management-service.xml file to access them from the flash
client. However, if you want to create these assemblers using
Spring as a way to create/inject them with dependencies, you need
to use the FlexFactory. At first I tried just creating the
Assemblers with hardcoded Spring applicationContexts, but I
realized I should be able to use these without Spring specific
references. So what I needed to do was create them using Spring and
inject properties into them. If you try to do this using the
ContextLoaderListener to initialize your Assemblers, you quickly
find that it backfires. Even if you use the ContextLoaderListener
to initialize the assemblers with Spring, the FDS will create them
again using its own factories, essientially creating two different
assemblers: one with spring-injected settings and one (created by
Flex) which was not injected by Spring upon creation and therefore
this instance will throw NullPointerExceptions when Flex tries to
use it.



The answer is the FlexFactory. (the docs only say this is the
way to integrate Spring into Flex; it gives no real detail as to
why, when, or how to make use of this class; nor does it explain
what the FactoryInstance class is or does; shame shame!)



The FlexFactory is used to override the basic factory that
Flex uses to create your Assemblers. By overriding the default
Factory with your own class that implements FlexFactory, you
basically prevent FDS from generating Assemblers listed in the
data-management-config.xml file on its own. What you have to do is
create this class, list it in the services-config.xml file in a
'factories' tag, and then use it to create and return your
Assemblers in the lookup method. I create an applicationContext in
the constructor of the factory and then to
applicationContext.getBean() calls for each of my assemblers. Then
in the lookup method I check the 'source' attribute being passed
into the method and return the corresponding Assembler. As for the
createFactoryInstance(String, ConfigMap) method where you have to
return a FactoryInstance object, I just create a FactoryInstance
using the passed parameters and return it. This is apparently how
Flex tracks the runtime instance of the Factory that is created
upon initialization. (at least that is what I'm guessing is the
case).



Hope this helps clear the issue of what the FlexFactory does
for those of you just getting started. If anyone else has any
clarification on this, or knows that I'm 'doing it wrong', please
chime in.



Bill

Avatar

Level 2
Hi Bill. If you haven't already found it, there is some
additional documentation on FlexFactory usage here:




http://livedocs.macromedia.com/flex/2/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Pa...



Let me know if this is useful to you.



- Mike Peterson

Adobe Flex documentation team

Avatar

Level 2
Thanks for the reply Mike. Yes, this is same documentation
that I (and Ken) have both reviewed. Unfortunately it is quite
lacking in depth. It does not describe the FactoryInstance object
in any real detail. It also fails to provide any useful examples.
It would be better if we had a link at the bottom titled "Looking
at a FlexFactory Example" that led to a page will a more complete,
real-world example similar to the "Looking at a managed association
example" found
here.

Avatar

Level 2
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).

*

* &lt;factories&gt;

* &lt;factory id="spring"
class="flex.samples.factories.SpringFactory" /&gt;

* &lt;/factories&gt;

*

* 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:

*

* &lt;context-param&gt;

*
&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;

*
&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;

* &lt;/context-param&gt;

*

* &lt;listener&gt;

*
&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;

* &lt;/listener&gt;

*

* Then you put your spring bean configuration in
WEB-INF/applicationContext.xml (as per the

* line above). For example:

*

* &lt;?xml version="1.0" encoding="UTF-8"?&gt;

* &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "
http://www.springframework.org/dtd/spring-beans.dtd"&gt;

*

* &lt;beans&gt;

* &lt;bean name="weatherBean"
class="dev.weather.WeatherService" singleton="true"/&gt;

* &lt;/beans&gt;

*

* 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:

*

* &lt;destination id="WeatherService"&gt;

* &lt;properties&gt;

* &lt;factory&gt;spring&lt;/factory&gt;

* &lt;source&gt;weatherBean&lt;/source&gt;

* &lt;/properties&gt;

* &lt;/destination&gt;

*

* @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



Avatar

Level 2
Excellent! Thanks so much Jeff. This is what I was looking
for all along. This kind of example is exactly what should find its
way into the documentation. I modified your example to work with
the data management service, replacing your service class with my
assembler. I also had to put my destination tags into the
data-management-config.xml file rather than the remote-config.xml
and I had to use the flex.data.adapters.JavaAdapter rather than the
flex.messaging.services.remoting.adapters.JavaAdapter. Now it seems
to be working and I just need to figure out how to integrate Acegi
authentication into this. (I'll make that a new post)



Thanks!



Avatar

Level 1



Hi, Can you tell me pls where to find the jar containing
flex.messaging.FactoryInstance ?

I ve put flex-messaging-common.jar already on the classpath,
but there is no sign of this inside.

Thanks

Avatar

Level 1
Hi, can you tell me pls where to find the jar containing
flex.messaging.FactoryInstance ? thanks

Avatar

Level 1
Jeff,

Thanks for posting sample code for FDS-Spring integration.
I'm trying to compile your SpringFactory class, and I'm having
issues resolving SpringFactoryInstance. It's not inside the main
spring.jar file. If you know which Spring jar the
SpringFactoryInstance class is located, pls post the reply. Thanks,



/Roman

Avatar

Level 3
Mike,



I don't think that is the right link. IT gets me "Calling
services in ActionScript".



The documentation that I have found is here -
http://livedocs.macromedia.com/flex/2/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Pa...



but it does not have any additional information. What would
be helpful is an example showing the use of the FlexFactory with
Java.

Avatar

Level 3
OK. You gusy lost me. So does this mean that my BaseAssembler
needs to not only extend flex.data.assemblers.Assembler but also
flex.messaging.FlexFactory?




NOT

public class BaseAssembler implements
flex.data.assemblers.Assembler




BUT THIS

public class BaseAssembler implements
flex.data.assemblers.Assembler, flex.messaging.FlexFactory

Avatar

Level 2
Hi Ken,



Your assembler class does not implement FlexFactory. You only
need one FlexFactory implementation for each source of Java objects
that you want to use with FDS either as remote object destinations
or data management services assembler classes.



Here's a copy of some more complete instructions I wrote on
integrating FDS with Spring. Hopefully this will help. Best,



Jeff



--- Integrating FDS with Spring









  1. Step for configuring Spring and FDS. This step only applies if
    you have

    not already installed spring in your web application.









    • Copy the spring.jar file into your WEB-INF/lib of your web
      application.




    • Add the spring context param and listener to your 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>






  2. Register the spring factory with FDS:



    a) Get a copy of flex.samples.factories.SpringFactory.java.
    Compile

    it and put it in your classpath someplace convenient. For the
    purposes of this sample,

    we'll assume it lives at
    flex.samples.factories.SpringFactory.



    b) Add the following configuration to your
    WEB-INF/flex/services-config.xml file:



    <factories>

    <factory id="spring"
    class="flex.samples.factories.SpringFactory" />

    </factories>




  3. Define your components in spring's XML file. Given the above
    spring

    configuration, they would be placed in
    WEB-INF/applicationContext.xml. This file can

    contain components which are intended to be exposed to flex
    clients as

    remote objects as well as classes to be used as Flex Data
    Management Services (FDMS)

    assembler implementations using the Java adapter.



    Just as with all FDMS destinations that use the Java adapter,
    if your class is intended to be

    used with FDMS, it either should implement the the
    flex.data.assembler.Assembler interface

    or it should have fill, get, and sync methods which are
    suitable to be configured via the

    fill-method, get-method, and sync-method tags in the FDMS
    configuration.



    To be constructed by Spring, your component should have a
    zero argument constructor so

    Spring can construct an instance. Your applicationContext.xml
    file might look like:



    <?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"/>



    <bean name="myAssembler"
    class="dev.assemblers.MyAssembler" singleton="true"/>

    </beans>




  4. Add your flex destination configuration for the components you
    want to expose to

    flex clients. Since these components use the spring factory
    we define, we add the

    additional tag <factory>spring</factory> and the
    <source> attribute is used to refer

    to the spring component's bean name, not the class name as
    with the default factory.



    a) For Remote object destinations you place your
    destinations inside of the <service> tag

    which refers to the flex.messaging.services.RemotingService,

    (by convention this may be in
    WEB-INF/flex/remoting-config.xml). For example, your

    remote destination configuration might look like:



    <destination id="WeatherService">

    <properties>

    <factory>spring</factory>

    <source>weatherBean</source>

    </properties>

    </destination>



    b) For FDMS destinations that use the Java adapter, you add
    your destinations to the

    service tag which refers to flex.data.DataService

    (which by convention may be in
    WEB-INF/flex/data-management-config.xml). Make sure you

    use the Java adapter for your destination. An example FDMS
    destination might look like:



    <destination id="MyFDMSDestination">

    ...

    <properties>

    ...

    <source>myAssembler</source>

    <factory>spring</factory>

    ...

    </properties>

    </destination>




See the FDMS documentation for more details on configuring
FDMS destinations which use the

Java adapter.

Avatar

Level 3
So if I have more than one object i would



<factories>

<factory id="Object1SpringFactory"
class="flex.samples.factories.SpringFactory" />

<factory id="Object2SpringFactory"
class="flex.samples.factories.SpringFactory" />

<factory id="Object3SpringFactory"
class="flex.samples.factories.SpringFactory" />

</factories>





<beans>

<bean name="bean1" class="dev.assemblers.MyAssembler1"
singleton="true"/>

<bean name="bean2" class="dev.assemblers.MyAssembler2"
singleton="true"/>

<bean name="bean3" class="dev.assemblers.MyAssembler3"
singleton="true"/>

</beans>





<destination id="MyFDMSDestination2">

...

<properties>

...

<source>bean2</source>

<factory>Object2SpringFactory</factory>

...

</properties>

</destination>



etc.

Avatar

Level 2
It's in WEB-INF/lib/flex-messaging.jar.

Avatar

Level 1



Thank you Tom.

Is there any licensing issue with this jar (
flex-messaging.jar ) being extracted from fds2 which is itself
licensed ?

Avatar

Level 3
Hi Roman,



SpringFactoryInstance is a nested class within
SpringFactory.java which is available as a download from the Flex
Exchange on Adobe.com (
http://www.adobe.com/cfusion/exchange/#loc=en_us&view=sn611&viewName=Flex%20Extension&authorid=70170...



Bela, I'm not in legal so I can't comment directly on the
licensing issues with extracting flex-messaging.jar from FDS2. Can
you provide some more details on what you're trying to accomplish?



Thanks,

Seth

Avatar

Level 1
Seth,



Thanks for your post. I've figured it out, but have another
question for you:

I got the SpringFactory class and all the configuration for
both Flex and Spring defined so that they can talk to each other (I
have them both as separate projects in Eclipse). Originally, I had
a new destination inside remoting-config.xml that mapped my POJO
object. Then, in my .mxml file I simply declared remoteObject
referencing POJO by the destination id, and called its methods.

Now, having this SpringFactory class, how am I going to
access my Spring bean which is also mapped to some destination id
inside remoting-config.xml? If it's the matter of simply calling
the Spring bean by its destination, then how the SpringFactory fits
in this picture.

I appreciate your reply. Thanks,



/Roman