Parsley is a client-side application framework and does not require any particular server-side technology to be useful. Nevertheless in this chapter we want to describe some common scenarios when integrating remoting solutions with Parsley.
For a general discussion on how to integrate services into the application architecture see 9 Building MVC Architectures.
Of course apart from AMF based remoting solutions presented in this chapter you can also integrate HTTP Services or WebServices into your controller actions. The approach is similar to that presented in the MVC chapter: You write a controller action class that registers handlers for messages or events dispatched from the View or from Mediators, transform them into any kind of asynchronous service invocation, wait for the result, and finally dispatch an application message containing the result through Parsleys Messaging Framework.
Since our own AMF-based remoting solutions (Pimento Data Services and Cinnamon Remoting) are not built on top of the Flex RemoteObject API, we start with a separate section on RemoteObjects in case you don't want to use Pimento or Cinnamon. Note that since we eat our own dog food and build the server-side using Pimento in our own projects, we are by no means experts in using RemoteObjects. Thus the concepts presented in this section are just suggestions which might be enhanced through user feedback in the future. We are also open to offer special configuration or wiring features for Flex Remoting in future releases. If you have any suggestions or recommendations in this area feel free to post on our forum.
Configuration
Since Parsley offers MXML-based container configuration you can easily integrate the existing MXML tags for RemoteObjects with other Parsley configuration tags:
<mx:Object
xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:RemoteObject
id="loginService"
destination="loginService"
showBusyCursor="true"
/>
<!-- other object definitions -->
</mx:Object>
You can then chose to inject those RemoteObjects into controller actions. But due to the nature of RemoteObjects not being type-safe you'd need to stick with id-based injection then:
[Inject(id="loginService")]
public var service:RemoteObject;
[MessageHandler]
public function login (event:LoginEvent) : void {
service.login(event.username, event.password)
.addResponder(new Responder(loginResult, loginFault));
}
private function loginResult (result:ResultEvent) : void {
[...]
}
private function loginFault (fault:FaultEvent) : void {
[...]
}
Using BusinessDelegates
If you prefer to use delegates instead of injecting the RemoteObjects directly you could define both the RemoteObjects and the delegates in Parsley MXML:
<mx:Object
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="http://www.spicefactory.org/parsley">
<mx:Script>
<![CDATA[
import com.bookstore.services.*;
]]>
</mx:Script>
<mx:RemoteObject
id="loginService"
destination="loginService"
showBusyCursor="true"
/>
<Object id="loginDelegate" type="{LoginDelegate}">
<ConstructorArgs>
<ObjectRef idRef="loginService"/>
</ConstructorArgs>
</Object>
<!-- other objects -->
</mx:Object>
With delegates you can then return to injection by type:
[Inject]
public var loginDelegate:LoginDelegate;
[MessageHandler]
public function login (event:LoginEvent) : void {
loginDelegate.login(event.username, event.password)
.addResponder(new Responder(loginResult, loginFault));
}
private function loginResult (result:ResultEvent) : void {
[...]
}
private function loginFault (fault:FaultEvent) : void {
[...]
}
Pimento integrates JPA/Hibernate and Spring with Flex, Flash and AIR clients. It is another Open Source Project under the Spicefactory umbrella. See the Pimento Info Page for more details.
Parsley includes custom configuration tags for Pimento for MXML and XML that allow you to define the Pimento configuration and custom services.
MXML Example
<mx:Object
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:pimento="http://www.spicefactory.org/parsley/pimento">
<pimento:Config
url="http://localhost:8080/test/service/"
timeout="3000"
/>
<!-- other objects -->
</mx:Object>
This minimal setup is all that is required to be able to inject Pimentos AS3 EntityManager into any object:
[Inject]
public var entityManager:EntityManager;
[MessageHandler]
public function deleteCart (message:DeleteCartMessage) : void {
entitiyManager.remove(message.cart);
}
You can additionally configure custom services with parameters and return values managed by Pimento:
<pimento:Service
name="loginService"
type="{LoginServiceImpl}"
/>
The service interfaces and remote stubs are usually generated by Pimentos Ant task. These services can then of course be injected into other objects, too.
XML Example
<objects
xmlns="http://www.spicefactory.org/parsley"
xmlns:pimento="http://www.spicefactory.org/parsley/pimento"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.spicefactory.org/parsley
http://www.spicefactory.org/parsley/schema/2.0/parsley-core.xsd
http://www.spicefactory.org/parsley/pimento
http://www.spicefactory.org/parsley/schema/2.0/parsley-pimento.xsd"
>
<pimento:config
url="http://localhost/test/service/"
timeout="3000"
/>
<pimento:service
name="loginService"
type="com.bookstore.services.LoginServiceImpl"
/>
Since this is an XML extension it has to be initialized explicitly before using the XmlContextBuilder:
PimentoXmlSupport.initialize();
If you don't need Pimentos data management capabilities and just want to use AMF-based Flex/Flash-to-Java Remoting you can stick with Cinnamon instead. See the Pimento/Cinnamon Info Page for more details.
Parsley includes custom configuration tags for Cinnamon for MXML and XML that allow you to define the channel and services.
MXML Example
<mx:Object
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:cinnamon="http://www.spicefactory.org/parsley/cinnamon">
<mx:Script>
<![CDATA[
import com.bookstore.services.*;
]]>
</mx:Script>
<cinnamon:Channel
url="http://localhost:8080/test/service/"
timeout="3000"
/>
<cinnamon:Service
name="loginService"
type="{LoginServiceImpl}"
/>
<cinnamon:Service
name="cartService"
type="{CartServiceImpl}"
/>
<!-- other objects -->
</mx:Object>
If you define only a single channel (like in most use cases) you don't have to explicitly refer to it in the service definitions. Parsley will automatically wire the single channel to all services then. In case of multiple channels you'd have to set the id property for the channel and reference it in service definitions:
<cinnamon:Channel
id="mainChannel"
url="http://localhost:8080/test/service/"
timeout="3000"
/>
<cinnamon:Service
name="loginService"
type="{LoginServiceImpl}"
channel="mainChannel"
/>
You can then inject services into your actions:
[Inject]
public var loginService:LoginService;
[MessageHandler]
public function login (event:LoginEvent) : void {
loginService.login(event.username, event.password);
}
With Cinnamon there is no need for BusinessDelegates: The remote services implement business interfaces themselves, so you can directly inject them into actions. These interfaces are usually generated by Cinnamons Ant Task, automatically porting existing Java service interfaces to AS3.
XML Example
<objects
xmlns="http://www.spicefactory.org/parsley"
xmlns:pimento="http://www.spicefactory.org/parsley/cinnamon"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.spicefactory.org/parsley
http://www.spicefactory.org/parsley/schema/2.0/parsley-core.xsd
http://www.spicefactory.org/parsley/cinnamon
http://www.spicefactory.org/parsley/schema/2.0/parsley-cinnamon.xsd"
>
<cinnamon:channel
url="http://localhost:8080/test/service/"
timeout="3000"
/>
<cinnamon:service
name="loginService"
type="com.bookstore.services.LoginServiceImpl"
/>
<cinnamon:service
name="cartService"
type="com.bookstore.services.CartServiceImpl"
/>
Since this is an XML extension it has to be initialized explicitly before using the XmlContextBuilder:
CinnamonXmlSupport.initialize();