Annotate your ApplicationModule to persist complex objects during passivation
The ApplicationModule component is smart enough to automate the state management for your application. While ApplicationModule takes care of the state management for the ViewObjects and EntityObjects (pending transaction state) during the activation-passivation cycle, it doesn't really care about the custom business objects that you might have created during the service invocations. There may be some rare scenarios where you may need to passivate these variables to avoid the expensive instantiation each time. This blog post discusses a customized solution for the above scenario - a solution for passivating your custom business objects.
A couple of weeks back, Kavin Kumar - a colleague of mine - shared a solution (which has been used in their application) for persisting complex objects during the passivation of ApplicationModule. This post is inspired by this idea. So the credit goes to Kavin :)
Use Case Requirement
A specific business service methods defined in the ApplicationModule requires a heavy 'business object' to call some other external services, and the creation of this objective is a pretty expensive task. The requirement is to make this variable passivation safe.
Solution
Obviously, you may need to override ApplicationModuleImpl::activateState(Element parent) and ApplicationModuleImpl::passivateState(Document doc,Element parent) to get hold of the points to hook your custom code.
The method ApplicationModuleImpl::passivateState(...) allows subclasses to store custom data as XML-nodes under the given parent element, in the given document. Whereas method ApplicationModuleImpl::activateState(...) allows subclasses to retrieve custom data from an XML-node under the given parent element.
Now the real fun starts. As the above two methods deals with xml for storing custom data,how do we store binary objects there? Cool...read on...
A very generic solution is to use Base-64 encoding for the binary data. Please refer this article to learn more about this topic. Getting back to our topic of discussion, on a high level, you may need to perform following steps to make the member variables of AM passivation safe.
When the ApplicationModule passivates...
When the ApplicationModule activates...
Now, let us try to generalize the above solution so that same can be enabled for any ApplicationModules with zero/less effort. One possibility is to use Java Annotations to enable the dynamism for ApplicationModule's member variables. Please refer this article to learn more about Java Annotations. Idea is to define some marker annotation and annotate the ApplicationModule variable to mark it as passivation safe. In this sample I opted to use a custom annotation 'Persistable', to annotate member variables of the ApplicationModule. With this approach, the 'passivation safe' member variables in your ApplicationModule may look like as shown below.
To improve the re-usability, you can move the activation/passivation logic to a generic 'ApplicationModule' implementation class which may act as the base class for other ApplicationModule classes, on need basis.
You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]
A glance at the implementation
This sample is making use of a SerializableApplicationModule class (sub-classed from ApplicationModuleImpl) which holds the logic for passivating member variables. This act as a base class for my ApplicationModule. Other relevant classes are located under 'sample.common.extension' package.
How to run this sample?
Run the test.jspx. Click on the Save button. This action is bound to AppModuleImpl::saveChanges(), which requires instance of ComplexBusinessServiceObject class to service the request. Please note that, this instance is getting created only once for the user session. The custom passivation logic passivates this instance along with ApplicationModule to serve the next request.
A couple of weeks back, Kavin Kumar - a colleague of mine - shared a solution (which has been used in their application) for persisting complex objects during the passivation of ApplicationModule. This post is inspired by this idea. So the credit goes to Kavin :)
Use Case Requirement
A specific business service methods defined in the ApplicationModule requires a heavy 'business object' to call some other external services, and the creation of this objective is a pretty expensive task. The requirement is to make this variable passivation safe.
Solution
Obviously, you may need to override ApplicationModuleImpl::activateState(Element parent) and ApplicationModuleImpl::passivateState(Document doc,Element parent) to get hold of the points to hook your custom code.
The method ApplicationModuleImpl::passivateState(...) allows subclasses to store custom data as XML-nodes under the given parent element, in the given document. Whereas method ApplicationModuleImpl::activateState(...) allows subclasses to retrieve custom data from an XML-node under the given parent element.
Now the real fun starts. As the above two methods deals with xml for storing custom data,how do we store binary objects there? Cool...read on...
A very generic solution is to use Base-64 encoding for the binary data. Please refer this article to learn more about this topic. Getting back to our topic of discussion, on a high level, you may need to perform following steps to make the member variables of AM passivation safe.
When the ApplicationModule passivates...
- Get the member variable , convert this to byte array and encode the byte array to Base64
- Stores the Base64 encoded string as a XML node
When the ApplicationModule activates...
- Decode (using Base-64) the the 'stringified' binary object (which is stored in the XML during passivation), and convert back to byte array.
- Recreate the object using the byte array
@Override
protected void passivateState(Document doc, Element parent) {
super.passivateState(doc, parent);
String stringifiedValue=getBase64EncodedObject( objectTobePassivated )
// Add them to the XML
Node nodeUserData = doc.createElement("USERDATA");
Element elem = doc.createElement("AM_OBJECT");
elem.setAttribute("KEY", key);
elem.setAttribute("VALUE",
(String)base64EncodedProperties.get(key));
elem.setAttribute("TYPE", "java.lang.Object");
nodeUserData.appendChild(elem);
parent.appendChild(nodeUserData);
//...........Your code goes here.........
}
/**
* Converts object to Base64 format
* @param propertyValue
* @return
*/
private String getBase64EncodedObject(Object propertyValue) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FastByteArrayOutputStream fbos = null;
try {
fbos = new FastByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(fbos);
out.writeObject(propertyValue);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
return Base64.byteArrayToBase64(fbos.getByteArray());
}
/********************************************************/
@Override
protected void activateState(Element parent) {
if (parent != null) {
NodeList nl = parent.getElementsByTagName("USERDATA");
if (nl.getLength() > 0) {
Node n = nl.item(0);
NodeList nl2 = n.getChildNodes();
for (int i = 0; i < nl2.getLength(); i++) {
Element e = (Element)nl2.item(i);
String key = e.getAttribute("KEY");
String value = e.getAttribute("VALUE");
try {
byte[] obj = Base64.base64ToByteArray(value);
ObjectInputStream in =
new ObjectInputStream(new FastByteArrayInputStream(obj));
setValue(key, in.readObject());
in.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
super.activateState(parent);
}
A generic solutionNow, let us try to generalize the above solution so that same can be enabled for any ApplicationModules with zero/less effort. One possibility is to use Java Annotations to enable the dynamism for ApplicationModule's member variables. Please refer this article to learn more about Java Annotations. Idea is to define some marker annotation and annotate the ApplicationModule variable to mark it as passivation safe. In this sample I opted to use a custom annotation 'Persistable', to annotate member variables of the ApplicationModule. With this approach, the 'passivation safe' member variables in your ApplicationModule may look like as shown below.
public class AppModuleImpl extends SerializableApplicationModule implements AppModule {
/**
* This is a complex object, so avoid the
* destruction/recreation of the same during
* passivation/activation of AM
*/
@Persistable
ComplexBusinessServiceObject complexBusinessServiceObject;
ApplicationModule's passivateState method would be looking for fields with this annotation and provide a special treatment to make them passivation safe.To improve the re-usability, you can move the activation/passivation logic to a generic 'ApplicationModule' implementation class which may act as the base class for other ApplicationModule classes, on need basis.
You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]
A glance at the implementation
This sample is making use of a SerializableApplicationModule class (sub-classed from ApplicationModuleImpl) which holds the logic for passivating member variables. This act as a base class for my ApplicationModule. Other relevant classes are located under 'sample.common.extension' package.
How to run this sample?
Run the test.jspx. Click on the Save button. This action is bound to AppModuleImpl::saveChanges(), which requires instance of ComplexBusinessServiceObject class to service the request. Please note that, this instance is getting created only once for the user session. The custom passivation logic passivates this instance along with ApplicationModule to serve the next request.
I read your post and I found this is amazing. Your thought process is wonderful. The way you express yourself is awesome.
ReplyDeleteReally good job, this is a very approach to me and very interesting post.
ReplyDeleteI hope more different tips from your wonderful blog...!
Power BI Training in Chennai
Power BI Training Fees in Chennai
Tableau Training in Chennai
Spark Training in Chennai
Oracle Training in Chennai
Unix Training in Chennai
Oracle DBA Training in Chennai
Social Media Marketing Courses in Chennai
Pega Training in Chennai
Primavera Training in Chennai
You have provided a nice article, Thank you very much for this one. And I hope this will be useful for many people. And I am waiting for your next post keep on updating these kinds of knowledgeable things
ReplyDeleteOracle Training in Coimbatore
best oracle training institute in Coimbatore
PHP Training in Coimbatore
Selenium Training in Coimbatore
Software Testing Course in Coimbatore
Spoken English Class in Coimbatore
IELTS Coaching in Coimbatore
German Classes in Coimbatore
Java Training in Bangalore
Pretty blog, so many ideas in a single site, thanks for the informative article, keep updating more article.
ReplyDeleteDigital Marketing Training in Chennai
Digital Marketing Training in Bangalore
Digital Marketing Training in Coimbatore
Digital Marketing Course in Madurai
Thanks for posting this information. Keep updating.
ReplyDeleteSpoken English Classes in Chennai
Best Spoken English Institute in Chennai
french courses in chennai
pearson vue
Blockchain Training in Chennai
Ionic Training in Chennai
content writing training in chennai
Spoken English Classes in Velachery
Spoken English Classes in Tambaram