We have a lot of services that use POJO's (plain old java objects) within our EJB's (Enterprise Java Beans) and when calling an EJB through remoting we want our returned objects in flash to be of the "type" we define in the service, for example, lets suppose we have a java class Authentication response and a function on an EJB, Authenticate. We basically want to know if the users password and id are correct and if not we need to return the reasons why (status codes, messages etc..)
My EJB has the method
public AuthenticationResponse authenticate(PasswordAuthenticationRequest req)
Now I want to pass a PasswordAuthentication request via remoting to the EJB and receive a AuthenticationResponse object, I'm going to define my JAVA classes and my flash classes
JAVA:
public class PasswordAuthenticationRequest implements Serializable {
public PasswordAuthenticationRequest() {
}
protected String id;
private String password;
/**
* @return The users id.
*/
public String getId() {
return id;
}
/**
* @param Id, The Users id (currently RACF).
*/
public void setId(String id) {
this.id = id;
}
/**
* @return The password for the authentication.
*/
public String getPassword() {
return password;
}
/**
* @param password, the password for the authentication.
*/
public void setPassword(String password) {
this.password = password;
}
}
ActrionScript :
class com.nscorp.util.vo.PasswordAuthenticationRequest
{
private var id:String;
private var password:String;
public function PasswordAuthenticationRequest()
{
super();
}
public function getId():String
{
return this.id;
}
public function setId(id:String):Void
{
this.id = id;
}
public function getPassword():String
{
return this.password;
}
public function setPassword(password:String):Void
{
this.password = password;
}
}
I also need the objects that are returned from the authenticate method call (AuthenticationResponse)
JAVA :
public class AuthenticationResponse implements Serializable
{
private String statusCode = null;
private String uiMessage = null;
private String description = null;
private String passwordExpirationDate=null;
private String passwordExpirationDays=null;
/**
* @return The statusCode of the request, non zero indicates failure
* @see getUIMessage()
* @see getDecription()
*
*/
public String getStatusCode()
{
return statusCode;
}
/**
* @param The statusCode, set by the service.
* @see getStatusCode()
*/
public void setStatusCode(String statusCode){
this.statusCode = statusCode;
}
/**
* @return The message for a user interface - the human readable message that corresponds to the returned status code.
*/
public String getUiMessage(){
return uiMessage;
}
/**
* @param UIMessage, The message the server sets corresponding to the status code.
*/
public void setUiMessage(String uiMessage){
this.uiMessage= uiMessage;
}
/**
* @return The Description of the status code, usually for logging or debugging purposes and often NULL.
*/
public String getDescription(){
return description;
}
/**
* @param Description, set by the server when a non zero status code is returned
*/
public void setDescription(String description){
this.description= description;
}
/**
* Default constructor, does not perform any initialization.
*/
public AuthenticationResponse()
{
}
public String getPasswordExpirationDate(){ return passwordExpirationDate; }
public void setPasswordExpirationDate(String passwordExpirationDate){ this.passwordExpirationDate = passwordExpirationDate; }
public String getPasswordExpirationDays(){ return passwordExpirationDays; }
public void setPasswordExpirationDays(String passwordExpirationDays){ this.passwordExpirationDays = passwordExpirationDays; }
}
the actionscript version :
class com.nscorp.util.vo.AuthenticationResponse
{
private var uiMessage:String;
private var passswordExpirationDate:String;
private var passwordExpirationDays:String;
public function getPasswordExpirationDate():String
{
return this.passswordExpirationDate;
}
public function setPasswordExpirationDate(passwordExpirationDate:String):Void
{
this.passswordExpirationDate = passwordExpirationDate;
}
public function setPasswordExpirationDays(passwordExpirationDays:String):Void
{
this.passwordExpirationDays = passwordExpirationDays;
}
public function getPasswordExpirationDays():String
{
return this.passwordExpirationDays;
}
// legacy method until its refactored :
public function getUiMessage():String
{
return this.uiMessage;
}
public function setUiMessage(uiMessage:String)
{
this.uiMessage = uiMessage;
}
}
For actionscript I also need to register these classes so that openAMF can deserialize the openAMF protocol versions to my actionscript classes, this is critical if you don't do this your returned objects from remoting will be dynamic objects and trying to cast the object returned from the remoting call will end not have any of your methods on it, so :
Object.registerClass("com.nscorp.util.vo.AuthenticationResponse", com.nscorp.util.vo.AuthenticationResponse);
Object.registerClass("com.nscorp.util.vo.PasswordAuthenticationRequest", com.nscorp.util.vo.PasswordAuthenticationRequest);
(I don't have any movieClips for these classes so I don't use the _Packages prefix see :Attaching movieclip class without library symbol)
(I put these calls in a utility class that is called when my application starts)
So we now need to tell openAMF what java class is mapped to what actionscript class, in the openamf-config.xml file we need to add a custom-class-mapping tag for each class ;
<custom-class-mapping>
<java-class>com.nscorp.security.authenticationService.util.AuthenticationResponse</java-class>
<custom-class>com.nscorp.util.vo.AuthenticationResponse</custom-class>
</custom-class-mapping>
<custom-class-mapping>
<java-class>com.nscorp.security.authenticationService.util.PasswordAuthenticationRequest</java-class>
<custom-class>com.nscorp.util.vo.PasswordAuthenticationRequest</custom-class>
</custom-class-mapping>
Since I'm using actionscript 2 I also need to change another setting in the openamf-config.xml :
<amf-serializer>
<force-lower-case-keys>false</force-lower-case-keys>
</amf-serializer>
And thats it, now when you make a call like :
var request:PasswordAuthenticationRequest = new PasswordAuthenticationRequest();
request.setId("testID");
request.setPassword("12345");
var pendingCall:PendingCall =
authenticationService.authenticate(request);
pendingCall.responder = this;
and your onResult method called by the pending call receives :
public function onResult (resultObj:ResultEvent):Void
{
var response:AuthenticationResponse = AuthenticationResponse(resultObj.result);
trace("The uiMessage was " + response.getUiMessage());
trace("The status code was " + response.getStatusCode();
}
This works great, we have about 20 POJO's in our service all using this feature. I have considered using ASTranslator that lets you parameterize objects but I like the type checking of using a concrete class as we have 3 developers on the same project and need to keep each other honest :)
Cheers,
Realien.
Comments