Introduction

Flash is a lightweight cross-platform runtime for rich media, enterprise applications and mobile applications, as well as an integrated development environment. Flash can be programmed in ActionScript 1/2/3.

Monday, May 22nd, 2006 at 3:46 pm

IoC Container for Flash

After taking a closer look at dependency injection and discussing some theory about inversion of control containers in the previous articles, we are now going to examine the As2lib Inversion of Control Container which is largely inspired by the Spring Framework.

Note that I use the name bean to refer to application objects managed by bean factories (they may be defined by a bean definition and may provide setters and getters to access properties).

Bean Wrapper (org.as2lib.bean.BeanWrapper): Bean wrappers are used by bean factories to access properties on beans. They provide methods to check whether properties with a given name are readable and/or writable, to set property values or to get property values and to convert property values to required types.

Bean Factory (org.as2lib.bean.factory.BeanFactory): The bean factory is a central registry for application objects. It holds bean definitions identified by unique names. If a bean is requested the bean factory will either create a new bean on each request with the information provided by the bean definition (prototype beans) or create the bean once and return always the same shared bean (singleton beans). The bean factory invokes lifecycle callbacks on a bean during its creation and destruction; creation involves instantiating the bean, populating it (setting property values) and resolving bean references. Most bean factories also support bean post-processors which can modify new beans before they are returned.

Factory Bean (org.as2lib.bean.factory.FactoryBean): Factory beans can be used as any other bean in a bean factory; but the bean returned by a bean factory on a bean request is not the factory bean itself, but the bean it creates. This mechanism can be used to retrieve constants that shall be used as property values or to create typed proxies for remoting or web services.

Runtime Bean Reference (org.as2lib.bean.factory.config.RuntimeBeanReference): Placeholder holding information to resolve bean references at run-time (dependency injection).

Bean Definition Parser (org.as2lib.bean.factory.parser.BeanDefinitionParser): Parses bean definitions which may for example be described with a XML dialect.

Application Context (org.as2lib.context.ApplicationContext): Application contexts build on the functionalities provided by bean factories and add some new ones that are typically needed by applications. These additional functionalities are: message sources for internationalization, application events, aspect oriented programming support and process support to execute asynchronous processes on start-up.

Let’s take a look at the applicationContext.xml file of the As2lib Chat sample.

  1. <beans xmlns="*.xml">
  2.    
  3.     <bean class="org.as2lib.bean.factory.config.StyleSheetConfigurer">
  4.         <property name="styleSheetUri">style.css</property>
  5.     </bean>
  6.    
  7.     <bean id="smartFoxClient" class="it.gotoandplay.smartfoxserver.SmartFoxClient"/>
  8.    
  9.     <Login id="login" width="800" height="600" ip="127.0.0.1" port="9339" zone="simpleChat"
  10.             class="org.as2lib.context.support.AsWingApplicationContext">
  11.         <property name="smartFoxClient"><ref local="smartFoxClient"/></property>
  12.         <property name="chat"><ref local="chat"/></property>
  13.     </Login>
  14.    
  15.     <Chat id="chat" width="800" height="600" visible="true"
  16.             class="org.as2lib.context.support.AsWingApplicationContext">
  17.         <property name="smartFoxClient"><ref local="smartFoxClient"/></property>
  18.     </Chat>
  19.    
  20.     <bean id="localeManager" class="org.as2lib.lang.LocaleManager" factory-method="getInstance">
  21.         <property name="defaultLocale">en</property>
  22.         <property name="locales">
  23.             <array>
  24.                 <bean class="org.as2lib.lang.GermanLocale"/>
  25.                 <bean class="org.as2lib.lang.EnglishLocale"/>
  26.             </array>
  27.         </property>
  28.     </bean>
  29.    
  30.     <bean id="messageSource" class="org.as2lib.context.support.ResourceBundleMessageSource"
  31.             depends-on="localeManager">
  32.         <property name="baseName">messages</property>
  33.     </bean>
  34.    
  35. </beans>

Beans are defined with bean elements. Every bean element must at least provide the information needed to instantiate it. This is in the simplest case just a bean class. Properties are defined with property elements. They have a name attribute and optionally a type attribute to convert the property value to. The definition of the message source bean can be interpreted as (the depends-on attribute forces the locale manager to be instantiated prior to the message source):

  1. var messageSource:ResourceBundleMessageSource = new ResourceBundleMessageSource();
  2. messageSource.setBaseName("messages");

The instantiation can also be done by a per-class or per-instance factory method. This approach is used by the locale manager whose declaration can be interpreted as:

  1. var localeManager:LocaleManager = LocaleManager.getInstance();
  2. localeManager.setDefaultLocale("en");
  3. var locales:Array = new Array();
  4. locales.push(new GermanLocale());
  5. locales.push(new EnglishLocale());
  6. localeManager.addLocales(locales);

While beans can be defined with bean and property elements, such a notation is too verbose and inconvenient to use for defining whole user interfaces. There is thus also another XML dialect which you can see a glimpse of in the above example: The definition of the login and chat beans. We’ll take a closer look at this more convenient dialect in the next article. Let’s now think about what the beans are doing.

The message source loads properties files for the target locale with the base name “messages” on start-up: messages_de.properties, messages_en.properties, … . After the properties files have been loaded, the message source can be used to get internationalized messages by name (”title.welcome”, “button.submit”, … ).

The locale manager defines a default locale and a list of available locales. If the language of the operating system does not match one of the available locales, the default locale will be used as target locale, whose properties file is loaded by the message source.

The unnamed style sheet configurer loads the cascading style sheet style.css to format the user interface with.

The smart fox client is used to log-in, create rooms and send messages.

The two beans login and chat are user interface screens. Their definition is done in separate xml files: Login.xml and Chat.xml respectively; these files are loaded and parsed on start-up.

We now know what the bean definitions mean, but how can the application be started? The main.Mtasc class is responsible for starting the application in the As2lib Chat sample. It first specifies the parser to use, then creates a new loading application context with the parser and a bean definition URI, adds a listener to the application context to be notified if the application context has finished loading and at the end starts the loading process.

  1. var beanDefinitionParser:BeanDefinitionParser = new UiBeanDefinitionParser();
  2. applicationContext = new LoadingApplicationContext(APPLICATION_CONTEXT_URI, beanDefinitionParser);
  3. applicationContext.addListener(this);
  4. applicationContext.start();

As soon as the application context has finished loading and parsing the Mtasc class gets the login screen from the application context and shows it.

  1. try {
  2.     var login:Login = applicationContext.getBean("login");
  3.     login.show();
  4. }
  5. catch (exception) {
  6.     trace("Initializing chat failed with error:\n" + StringUtil.addSpaceIndent(exception.toString(), 2));
  7. }

The last question that remains is: How do we get the needed classes into the swf? This is actually quite problematic in Flash; every needed class must be referenced for example in the first frame which is quite inconvenient. When you are free to compile your application with MTASC things are much more convenient: use Ant build scripts in combination with As2ant to compile the application. With As2ant you have the option to specify the application context as XML source. The SWF task steps through the XML file and compiles all needed classes into the swf.

  1. <swf src="${as2lib.dir}/org/as2lib/app/conf/MtascApplication.as" dest="${chat.swf}"
  2.         header="800:600:31" version="8" trace="org.as2lib.env.log.logger.DebugItLogger.trace">
  3.     <classpath>
  4.         <pathelement path="${lib.dir}"/>
  5.         …
  6.     </classpath>
  7.     <srcxml>
  8.         <pathelement path="${context.dir}/applicationContext.xml"/>
  9.         …
  10.     </srcxml>
  11. </swf>

If you use Eclipse or another development environment with integrated Ant support, compiling everything requires just one click.

Download the As2lib Chat sample application with all needed libraries: As2lib Chat

As already mentioned previously, the XML dialect for user interfaces will be presented in the next article (but you can of course take a look at it in the As2lib Chat sample application if you can’t wait).

4 Responses to “IoC Container for Flash”

  1. Reynold

    Hi:Simonwacker,very good for your as2lib,
    i love it ,i have download the as2lib_chat,but how could i built it with eclipse,and when i open the chat.swf,IT’S ERROR,and the error is that”
    14:47:06.984 main.Mtasc.init():43 - Initializing.
    14:47:07.062 main.Mtasc.onBatchStart():52 - Batch started.
    Error opening URL “file:///E|/build/messages_en_undefined.properties”
    14:47:10.484 main.Mtasc.onBatchFinish():61 - Batch finished.
    i don’t know what to do ,please!!!Thank you

  2. Reynold

    Sorry,i didn’t see the readme.txt
    http://www.gotoandplay.it/_articles/multiplayerCentral/download.php

  3. Simon Wacker

    Hi Reynold,

    thanks! I’m glad that it works now. I’m nevertheless wondering why you got a “Error opening URL ‘file:///E|/build/messages_en_undefined.properties’” error. I’ll check this.
    To make a build yourself just right click the build.xml file and choose Run As -> Ant Build. Further builds can then be done by just clicking the green arrow with the briefcase.

    Greetings,
    Simon

  4. Reynold

    HI,Simonwacker,yeah,i have done it well,very good,Thank you