tag:blogger.com,1999:blog-134162402024-03-05T10:01:28.650+05:30My Insights on TechnologiesYou never know when stuff like this comes in handyAnonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.comBlogger15125tag:blogger.com,1999:blog-13416240.post-55362769060706317082013-12-01T19:07:00.001+05:302013-12-02T11:08:30.278+05:30GAE/J: Packaging your entity classes in separate jar files<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
I enjoy designing modularized applications. It allows me to visualize the architecture and understand the links between the various modules. In addition to benefitting the code base, it helps me appreciate the existing system's design better.<br />
<br />
When using JPA (DataNucleus) as your persistence technology on top of <a href="https://developers.google.com/appengine/">Google's AppEngine</a> stack, you are most likely to end up with a single persistence.xml file and all your entity classes being bundled in the same jar.<br />
<br />
But what if you wanted to modularize your code and package groups of entity classes in their own jar files?<br />
<br />
In this article, we are going to look at writing a simple extension to the persistence provider of <a href="http://www.datanucleus.org/">DataNucleus</a> that will allow us to read our entity classes that have been packaged in to multiple jars.<br />
<br />
Let us assume that after your code refactoring & modularization you end up with a code structure that can be related to the following model:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> - project_root</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |-> framework-model (produces framework-model.jar)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |-> AttributeEntity.class // Used for storing attributes</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |-> UserEntity.class // Used for storing user entries</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |-> BinaryResource.class // Used for storing small binaries</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |-> catalog-model (produces catalog-model.jar)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |-> ProductCategoryEntity.class // The product categories.</span><br />
<span style="font-family: Courier New, Courier, monospace;"> |-> ProductEntity.class // The products</span><br />
<br />
<br />
<br />
In the above example, I have two jars that contain the entities that I wish to consume within the application. So far so good, but unfortunately, just enhancing the classes and packaging them in two separate jars will not do the trick.<br />
<br />
At this stage, to move forward we need to take a closer look at the entries that go in to the persistence.xml file. From the <a href="https://developers.google.com/appengine/docs/java/datastore/jpa/overview-dn2">documentation</a>, the only information that looks useful is the persistence provider: <span style="font-family: 'Courier New', Courier, monospace;">org.datanucleus.api.jpa.PersistenceProviderImpl.</span><br />
<br />
Here is where the beauty of open source projects shine the most. DataNucleus being open sourced, it is easy to view the source of the persistence provider implementation and understand its bootstrapping logic.<br />
<br />
Internally, the provider implementation is constructing a <span style="font-family: Courier New, Courier, monospace;">PersistenceUnitMetaData</span> object that contains information about all the entity classes that have been enhanced. This provider investigates all archives that contain a <i>"persistence.xml"</i> file, for identifying the enhanced entity definitions. Since we cannot create multiple persistence.xml files that point to the same PU name, we need to look at another way of solving the problem.<br />
<br />
<h4 style="text-align: left;">
Custom Persistence Provider Implementation</h4>
<br />
Given that the persistence provider is the application's entry point in to the JPA stack, and the fact that we are trying to bootstrap the environment with entity classes that sit in different jars, the logical solution to our problem is to write a custom persistence provider implementation.<br />
<br />
With a little bit of debugging and reading the source code, I came up with my own implementation - <a href="https://github.com/roguexz/rogue.io/blob/master/modules/gae-support/src/main/java/rogue/app/framework/support/datanucleus/GAEPersistenceProviderImpl.java">GAEPersistenceProviderImpl</a>.<br />
<br />
The basic idea behind this implementation is:<br />
<ul style="text-align: left;">
<li>Search for all jars that contain a <span style="font-family: Courier New, Courier, monospace;">META-INF/orm.xml</span> file<br /><i>The fun part is that you can have an empty orm.xml file and the system will not crib!<br /></i></li>
<li>Use <a href="https://code.google.com/p/reflections/">Reflections</a> to scan all the classes within the above identified jar files.<br /></li>
<li>When the application requests for the <i>EntityManagerFactory</i>, get all classes that have been annotated with <i>@Entity</i> and use that information for constructing the metadata that is required by DataNucleus<br /><i>This is where the Reflections project comes in handy - It can scan the classes without loading the classes</i></li>
</ul>
<br />
<h4 style="text-align: left;">
Update the persistence.xml file</h4>
<br />
The next step was to specify this custom provider in the <a href="https://github.com/roguexz/rogue.io/blob/master/modules/gae-support/src/main/resources/META-INF/persistence.xml">persistence.xml</a> file.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> <persistence xmlns="http://java.sun.com/xml/ns/persistence"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> version="2.0"></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <persistence-unit name="transactions-optional"></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <provider></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="color: red;">rogue.app.framework.support.datanucleus.GAEPersistenceProviderImpl</span></span><br />
<span style="font-family: Courier New, Courier, monospace;"> </provider></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <properties></span><br />
<span style="font-family: Courier New, Courier, monospace;"> ...</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </properties></span><br />
<span style="font-family: Courier New, Courier, monospace;"> </persistence-unit></span><br />
<span style="font-family: Courier New, Courier, monospace;"> </persistence></span><br />
<div>
<br /></div>
<br />
And voila, every jar file that contained a META-INF/orm.xml file was scanned for entities and passed along to the DataNucleus implementation.<br />
<br />
Modularization - achieved!<br />
<br />
Hope this was useful to you.</div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-77893224805628361692013-11-05T02:10:00.000+05:302013-11-05T23:31:04.260+05:30A GAE/J project template for JSF based applications<div dir="ltr" style="text-align: left;" trbidi="on">
As I built out the reproducible test case for a <a href="https://java.net/jira/browse/JAVASERVERFACES-3042">JSF bug</a>, I realised that the bare-bones project could probably help someone looking for such a starter template. So I put it up on <a href="https://github.com/roguexz/gae-java-template">GitHub</a>.<br />
<br />
Key points about this bare bones starter template:<br />
<ol style="text-align: left;">
<li>Uses Gradle as its build system (including downloading & running the GAE/J server itself)</li>
<li>Configured with JSF 2.2 & JPA 2 & CDI & PrimeFaces</li>
<li>Has basic code for Session serialization & clean up</li>
<li>Uses <a href="http://getbootstrap.com/">Bootstrap</a> for page templating.</li>
</ol>
<div>
I have a sample <a href="http://gae-java-template.appspot.com/">deployed on AppEngine</a>.<br />
<br />
There are quite a few starter templates available on the net. So if this template seems too pale, then you could try the others.</div>
<div>
<br /></div>
<div>
If you decide to play around with this project template, please do take the time to provide me your feedback.</div>
<div>
<br /></div>
<div>
Hope this was useful to you.</div>
</div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-76504311687342865922013-10-25T01:55:00.000+05:302013-11-11T22:19:12.078+05:30JSF 2: Returning a resource URL that is local to the web application<div dir="ltr" style="text-align: left;" trbidi="on">
JSF 2 introduced a standard way of serving website assets - like JavaScript, CSS, image files, etc. It also introduced features which facilitate the insertion of these resources in to a JSF page.<br />
<br />
Consider the following web application code base layout:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUlj3TIXbDw894TXq5fGgFQZ13CHNRyfMIs9i0iM-ghNQZDeYzyxnyG3rrS2GZzphKyMWFK2s-irwlaqO7XOOgWdkfr6drfnQLejppU6puH5-vJgvYpTXFEQ_LcMxZCcs5-8eESg/s1600/code-structure-layout.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUlj3TIXbDw894TXq5fGgFQZ13CHNRyfMIs9i0iM-ghNQZDeYzyxnyG3rrS2GZzphKyMWFK2s-irwlaqO7XOOgWdkfr6drfnQLejppU6puH5-vJgvYpTXFEQ_LcMxZCcs5-8eESg/s320/code-structure-layout.png" width="237" /></a></div>
<br />
<br />
This application, as you can see, uses the <a href="http://getbootstrap.com/">Bootstrap framework</a>, which requires <a href="http://jquery.com/">JQuery</a> as a prerequisite. With the new resource loading solution, you can include the above files in your XHTML template by adding the following declarations:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b> <h:head></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <h:outputStylesheet library="bootstrap" name="css/bootstrap.css"/></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <h:outputStylesheet library="bootstrap"</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> name="css/bootstrap-theme.css"/></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <h:outputScript library="jquery" name="js/jquery.min.js"/></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <h:outputScript library="bootstrap" name="js/bootstrap.min.js"/></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> </h:head></b></span><br />
<br />
<br />
Notice in the above declarations, there is no version number provided for the JQuery script, and in the code base, we are using <span style="font-family: Courier New, Courier, monospace;">'_'s</span> instead of <span style="font-family: Courier New, Courier, monospace;">'.'s</span> to separate the version numbers. In JSF 2, the <i><a href="http://docs.oracle.com/javaee/7/api/javax/faces/application/ResourceHandler.html">ResourceHandler</a></i> takes care of identifying the latest version of your <i><a href="http://docs.oracle.com/javaee/7/api/javax/faces/application/Resource.html">Resource</a></i> and renders the appropriate file. This is an extremely useful feature, where we can update our resources and JSF will ensure that the latest version is the artefact that is rendered.<br />
<div>
<br /></div>
<div>
Everything works fine, with the exception of on small glitch! Relative references inside your CSS file do not work! This has to do with the way the resources are rendered. If you are using JSF with the suffix mapping (<i>the typical scenario where you say that all .xhtml file are to be processed by JSF</i>), then the above declarations would produce the following output:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> /javax.faces.resource/css/bootstrap.min.css.xhtml?ln=bootstrap</span><br />
<span style="font-family: Courier New, Courier, monospace;"> /javax.faces.resource/js/jquery.js.xhtml?ln=jquery&v=1_10_2</span><br />
<div>
<br /></div>
<div>
, so if the <span style="font-family: Courier New, Courier, monospace;">bootstrap.min.css</span> file had a relative reference to the fonts file, via the following declaration:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> url('../fonts/glyphicons-halflings-regular.eot');</span></div>
</div>
<div>
<br /></div>
<div>
The URL that gets constructed does not make a lot of sense<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> /javax.faces.resource/fonts/glyphicons-halflings-regular.eot</span><br />
<br />
As you can see, the above URL does not exist, and since there is no .xhtml file at the end of the URL the Faces servlet doesn't handle it either.<br />
<br />
Now there are 3 ways of handling this issue:<br />
<br />
<ol style="text-align: left;">
<li>Don't use the JSF resource loading mechanics. Instead include the web resources by constructing the URL directly<br /><br /><span style="font-family: Courier New, Courier, monospace;">
<link rel="stylesheet" type="text/css"<br />
href="#{request.contextPath}/resources/bootstrap/css/bootstrap.min.css"/><br /> </span></li>
<li>Modify the CSS file and update all the relative URLs to be JSF aware<br /><br /><span style="font-family: Courier New, Courier, monospace;">url('../fonts/glyphicons-halflings-regular.eot.xhtml?ln=bootstrap');<br /></span></li>
<li>Or, you can write a custom ResourceHandler that will:</li>
<ul>
<li>Allow you to use external web assets without making any changes to them.</li>
<li>Leverage the JSF resource loading mechanics and all the goodness that comes along with it.</li>
<li>Generate a URL that looks like option 1.</li>
</ul>
</ol>
<div>
<br /></div>
</div>
<h3 style="text-align: left;">
The Custom ResourceHandler</h3>
<div>
<br /></div>
<div>
One really good feature about JSF is that you can replace / augment pretty much any part of the framework. In order to achieve our use case, we will define a new ResourceHandler and an associated Resource type.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnqaFPXzgRFzYjS7rnyzjoMXhjLPzvLj8sZMvDpqjm259WNxboI2b1ZkEf6eTTr59SbCLyCk9zVx0SOkKZEU304eR9DR3C4daCpTZJrLUGfnB0rLypginNXNged0Jj2gCfD3qrzQ/s1600/Custom+Resource+Handler.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="156" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnqaFPXzgRFzYjS7rnyzjoMXhjLPzvLj8sZMvDpqjm259WNxboI2b1ZkEf6eTTr59SbCLyCk9zVx0SOkKZEU304eR9DR3C4daCpTZJrLUGfnB0rLypginNXNged0Jj2gCfD3qrzQ/s320/Custom+Resource+Handler.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
The <i>AppResourceHandler</i> extends the <a href="http://docs.oracle.com/javaee/7/api/javax/faces/application/ResourceHandlerWrapper.html">ResourceHandlerWrapper</a>, and monitors only those method calls that create a resource object.</div>
<div>
<br /></div>
<div>
For every resource object that gets created, the URL of the resource is analyzed to determine if that resource is local to the webapp or part of some archive (jar / zip / etc.) file in the class path.</div>
<div>
<br /></div>
<div style="border: solid 1px #eeeeee; padding-left: 5px;">
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><u>AppResourceHandler.java</u></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">@Override</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">public Resource createResource(String resourceName, String libraryName) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Resource resource = super.createResource(resourceName, libraryName)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> return getWrappedResource(resource);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/**</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * If the given resource object can be rendered locally, then do so by</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * returning a wrapped object, otherwise return the input as is.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">private Resource getWrappedResource(Resource resource) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> WebAppResource webAppResource = null;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ExternalContext context = FacesContext.getCurrentInstance()</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> .getExternalContext();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> // Get hold of the webapp resources directory name</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (resourcesRoot == null) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> String resourcesRoot = context.getInitParameter(</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ResourceHandler.WEBAPP_RESOURCES_DIRECTORY_PARAM_NAME);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (resourcesRoot == null) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> resourcesRoot = "/resources";</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (resource != null) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> URL baseURL = resource.getURL();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (baseURL != null) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> String extForm = baseURL.toExternalForm();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> int idx = extForm.indexOf(resourcesRoot);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (idx != -1) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> try {</span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"> extForm = extForm.substring(idx);</span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"> URL resourceURL = context.getResource(extForm);</span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"> if (resourceURL != null) {</span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"> webAppResource = new WebAppResource(extForm,</span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"> resource);</span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> } catch (MalformedURLException e) {}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> return webAppResource != null ? webAppResource : resource;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
</div>
<div>
<br /></div>
<div>
And in the <i>WebAppResource</i> class, we just return the webapp local URL instead of a Faces one.</div>
<div>
<br /></div>
<div style="border: solid 1px #eeeeee; padding-left: 5px;">
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><u>WebAppResource.java</u></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">private Resource wrapped;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">private String path;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">public WebAppResource(String path, Resource wrapped)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">{</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> this.wrapped = wrapped;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> this.path = path;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">@Override</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">public String getRequestPath()</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">{</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> FacesContext context = FacesContext.getCurrentInstance();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> return context.getApplication().getViewHandler()</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> .getResourceURL(context, path);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
</div>
<div>
<br /></div>
<div>
Finally, we add the custom resource handler's entry in the <span style="font-family: Courier New, Courier, monospace;">faces-config.xml</span> file.</div>
<div>
<br /></div>
<div style="border: solid 1px #eeeeee; padding-left: 5px;">
<div>
<span style="font-family: Courier New, Courier, monospace;"><faces-config ...></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> <application></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> <resource-handler></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> some.package.AppResourceHandler</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> </resource-handler></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> </application></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"></faces-config></span></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
And we are done. Run your code and see the difference!<br />
<br />
Hope this was useful to you.</div>
</div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-51431350213680081962013-10-21T20:19:00.001+05:302013-10-21T22:04:10.881+05:30ADF Mobile: Working with iframes<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="http://www.oracle.com/technetwork/developer-tools/adf-mobile/overview/index.html">Oracle ADF Mobile</a>, <i>as of version 11.1.2.4.0</i>, does not provide a web browser control that you can embed and use. There is the notion of implementing an application feature as a <a href="http://docs.oracle.com/cd/E37975_01/doc.111240/e24475/remoteurl.htm">remote url</a>, but that is tied in to a connection that cannot be modified at runtime.<br />
<br />
I happened to have a need for modifying the context parameters of the target location at runtime.<br />
<br />
Here is what I was trying to do:
<br />
<ol style="text-align: left;">
<li>Fetch some data using a REST service</li>
<li>On a certain action, show the web site inside the application itself</li>
</ol>
<div>
For the second operation, all I wanted to do was construct the target URL and display it in an IFRAME. Turns out there is no easy way to do it!</div>
<div>
<br /></div>
<div>
So I ended up developing a hack that looks like this:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-B-M1_G6UmY-YaSK9LrVI388FPvZDJOMKa6j1XhzfCvio7Ps8RcAtZFA4a04sKg0ZylEb70m8SMS_PgSGAOIai5aYAvEQbaUOilw8u7kF8DKkb0hBsAW0oOG7V9XtlZQ8dTbtsA/s1600/ADF+Mobile+-+Working+with+iframes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-B-M1_G6UmY-YaSK9LrVI388FPvZDJOMKa6j1XhzfCvio7Ps8RcAtZFA4a04sKg0ZylEb70m8SMS_PgSGAOIai5aYAvEQbaUOilw8u7kF8DKkb0hBsAW0oOG7V9XtlZQ8dTbtsA/s320/ADF+Mobile+-+Working+with+iframes.png" width="318" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<h3 style="text-align: left;">
The App Browser Proxy</h3>
<div>
I added a new feature - "App Browser Proxy" - whose sole purpose was to display a URL (<i>which has been <a href="http://docs.oracle.com/cd/E37975_01/doc.111240/e24475/remoteurl.htm#BABHEHDE">white listed</a></i>). Since remote connections are out of the question, I decided to implement this feature as a <a href="http://docs.oracle.com/cd/E37975_01/doc.111240/e24475/define_features.htm#CIHHJCGJ">Local HTML</a> file instead.</div>
<div>
<br /></div>
<div>
The good thing about implementing a feature as a local HTML file is that you can add HTML elements like scripts & iframes. The only problem is how do you pass data from your business controller to the page?</div>
<div>
<br /></div>
<div>
The developer guide talks about how one can use JavaScript to get hold of the business logic code, but it is classified under "<i><a href="http://docs.oracle.com/cd/E37975_01/doc.111240/e24475/phgapfeatures.htm#BABDECEG">Using ADF Mobile APIs to Create a Custom HTML Springboard Application Feature</a></i>". Not exactly the set of keywords I am looking for, but nonetheless in here lies the solution for this hack.</div>
<div>
<br /></div>
<div>
Putting these concepts together, yielded the following code for my local HTML file:</div>
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>/Web Content/app-browser-proxy/pages/app-browser-proxy.xhtml</b></span><br />
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><script type="text/javascript"></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (!window.adf) { window.adf = {}; }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> adf.wwwPath = "../../../../../www/";</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"></script></span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"><i><!-- Take note about the number of folders that you need to skip --></i></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><script type="text/javascript" src="../../../../../www/js/base.js"></script></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><script type="text/javascript" src="../../../../../www/js/adf.el.js"></script></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><script type="text/javascript"></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> function onEvaluateSuccess(req, res) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> try {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (res) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (res[0]) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> var targetURL = res[0].value;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (targetURL) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> var ifrm = document.getElementById("app-browser-iframe");</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (ifrm) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ifrm.src = targetURL;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> catch (e) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> alert("Load Target: error occurred " + e);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> function onError(req, resp) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> alert("Error occurred " + adf.mf.util.stringify(res));</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> function loadTargetURL() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> try {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> <b><span style="color: red;">adf.mf.el.getValue("#{applicationScope.appBrowserTargetUrl}",</span></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span style="color: red;"> onEvaluateSuccess, onError)</span></b>;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> catch (e) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> alert("Caught exception: " + e);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> document.addEventListener("showpagecomplete", loadTargetURL, false);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"></script></span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"><b><iframe id="app-browser-iframe" width="100%" height="100%"</b></span></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;"><b> style="background-color:#ffffff; border: none;"></iframe></b></span></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
In the above fragment, I have achieved the following:<br />
<div>
<ol style="text-align: left;">
<li>Create an IFRAME that occupies the entire height & width of the screen</li>
<li>Using JavaScript, fetch the target URL by evaluating an EL - <span style="font-family: Courier New, Courier, monospace;">applicationScope.appBrowserTargetUrl</span></li>
<li>Set the IFRAME's source to the evaluated EL</li>
</ol>
<div>
<br /></div>
<h3 style="text-align: left;">
The App Browser Proxy Feature Listener</h3>
<div>
The thing about ADF Mobile is that once it loads a feature, it does not necessarily reload it every time you navigate between features. So, the above code will work perfectly for the first time. Second time you navigate to this page, you will continue to see the last loaded page.</div>
<div>
<br /></div>
<div>
In order to work around this issue, you need to create a <a href="http://docs.oracle.com/cd/E37975_01/doc.111240/e24475/define_features.htm#ADFMF240">Feature Listener</a>, that invokes the JavaScript function that we have defined - <span style="font-family: Courier New, Courier, monospace;">loadTargetURL()</span>.</div>
<div>
<br /></div>
<div>
In the <span style="font-family: Courier New, Courier, monospace;">activate</span> method of the feature listener, adding the following snippet will do the trick:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">AdfmfContainerUtilities.invokeContainerJavaScriptFunction(</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> AdfmfJavaUtilities.getFeatureName(), "loadTargetURL",new Object[0]);</span></div>
</div>
<div>
<br /></div>
<br />
<h3 style="text-align: left;">
The Final Piece</h3>
</div>
<div>
Finally, invoking this app browser proxy, from any other feature, is a matter of adding the following code snippet:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">// Ensure that the target URL has been set in the following EL</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">// #{applicationScope.appBrowserTargetUrl}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">// e.g.,</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">// AdfmfJavaUtilities.setELValue(</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">// "#{applicationScope.appBrowserTargetUrl}", targetURL)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">// Use the correct feature ID</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">AdfmfContainerUtilities.resetFeature("demo.AppBrowserProxy");</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">AdfmfContainerUtilities.gotoFeature("demo.AppBrowserProxy");</span></div>
</div>
<div>
<br /></div>
<div>
<i><b>Note:</b> This hack works because I store the target URL in the application scope. Any other scope will not be available across features.</i><br />
<br /></div>
<div>
Hope this was useful to you.</div>
</div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-81584732637896161912013-10-17T01:10:00.000+05:302013-10-17T01:10:20.691+05:30ADF Mobile: Listening for changes to preferences<div dir="ltr" style="text-align: left;" trbidi="on">
Lately I've been doing quite a bit of prototyping and, as is the case with such activities, I kept coming up with weird requirements that didn't have any apparent answers available .... some can be solved with a bit of ingenuity, the others leave me a few hair strands less.<br />
<br />
<a href="http://www.oracle.com/technetwork/developer-tools/adf-mobile/overview/index.html">Oracle ADF Mobile</a> is a pretty neat framework for designing cross platform mobile apps. I was tasked with creating a prototype that communicates with a REST service to fetch some data.<br />
<br />
As I went about with the exercise, I decided that I wanted to store the server configuration and user credentials in the application preferences.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfPgzKbcm4IuDgAEwzGBP-ddcu0iKgKvytQ-L2vB9TJEhfubsJU1c2E3_LpD_umTQt-zmtp7QnLY2V9B5Hz6VMYcC6HOlwDpz9GQ-vhEdRnm_ov_nWnz54afMl7vO7p0zr-h2kZw/s1600/adf-mobile-preferences.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfPgzKbcm4IuDgAEwzGBP-ddcu0iKgKvytQ-L2vB9TJEhfubsJU1c2E3_LpD_umTQt-zmtp7QnLY2V9B5Hz6VMYcC6HOlwDpz9GQ-vhEdRnm_ov_nWnz54afMl7vO7p0zr-h2kZw/s1600/adf-mobile-preferences.png" /></a></div>
<span id="goog_476178042"></span><span id="goog_476178043"></span><br />
Done. Next I wanted to refresh my controllers every time the preferences changed ... well this is where I got stumped! There is no <i>preference-change-listener</i> that I could implement.<br />
<br />
Fortunately, there is an alternative - a feature level <a href="http://docs.oracle.com/cd/E37975_01/apirefs.111240/e27204/oracle/adfmf/feature/LifeCycleListener.html">LifeCycleListener</a> - which has only two methods <i>activate() & deactivate()</i> which are invoked when the feature is displayed and hidden. Every time you access the app's settings page (on your android phone) you are forcing the <i>"Feature"</i> to <i>"deactivate"</i> and then <i>"activate"</i> when you come back.<br />
<br />
It is in this listener that you could employ a nifty hack to check if your preferences have changed or not. I chose to verify the hash codes to determine if the preferences had changed; and accordingly invalidate the required content.<br />
<br />
So I ended with the following code for my listener:<br />
<br />
<br />
<pre>public class PortalFeatureListener
implements LifeCycleListener
{
private long prefsHashCode = -1;
public void activate()
{
// Verify if the hashcode of the preferences has changed or not.
String prefs = "" +
AdfmfJavaUtilities.evaluateELExpression(
"#{preferenceScope.application.serverConfig.connUrl}") +
AdfmfJavaUtilities.evaluateELExpression(
"#{preferenceScope.application.userCredentials.username}") +
AdfmfJavaUtilities.evaluateELExpression(
"#{preferenceScope.application.userCredentials.password}");
if(prefs.hashCode() != prefsHashCode)
{
prefsHashCode = prefs.hashCode();
refreshControllers();
}
}
public void deactivate()
{
// Do nothing for now.
}
private void refreshControllers()
{
// Do something here.
}
}
</pre>
<div>
<br /></div>
<div>
<br />
, which gets configured in the <i>adfmf-feature.xml</i> file.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG_mL4YS9JADBVy9tQodt9xszUqZLgD4WpqCqxTOHxAhBut75Al8MhxBT34RO0qOQJ7UVA4nXIKJQ1WKbZikVjaLDk4BRQsQtIBhnrQY-Pwowe-dJw6n4ebG07DglR0aA4YUgC6A/s1600/adf-mobile-feature-listener.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="307" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG_mL4YS9JADBVy9tQodt9xszUqZLgD4WpqCqxTOHxAhBut75Al8MhxBT34RO0qOQJ7UVA4nXIKJQ1WKbZikVjaLDk4BRQsQtIBhnrQY-Pwowe-dJw6n4ebG07DglR0aA4YUgC6A/s640/adf-mobile-feature-listener.png" width="640" /></a></div>
<br />
<br />
Hope this was useful to you.</div>
<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-84495826882977955842013-10-08T01:01:00.000+05:302013-10-08T01:02:43.964+05:30Getting WELD working on top of GAE/J<div dir="ltr" style="text-align: left;" trbidi="on">
I have a pet project that I keep tinkering with whenever I get some free time. It is an elaborate experiment to build what I wish to call as the "Unified Model Layer". More details about it in another post. As with any experiment there are a lot of observations and learnings. One such learning was on how to get <a href="http://weld.cdi-spec.org/">WELD</a> running on top of <a href="https://developers.google.com/appengine/">Google App Engine</a>.<br />
<br />
Remember - an App Engine app <a href="https://developers.google.com/appengine/kb/java?hl=en#threads">may not spawn</a> new threads.<br />
<br />
Once you understand this rule, then all you need to do is dig through any library code that might want to spawn threads and disable it.<br />
<br />
In the case of WELD, you need to create 2 property files, with the associated content:<br />
<br />
<blockquote style="font-family: Courier New, Courier, monospace;">
<b><u>org.jboss.weld.bootstrap.properties</u></b><br />
<br />
# Custom overrides to make weld work in the GAE environment.<br />
concurrentDeployment=false<br />
preloaderThreadPoolSize=0<br />
<div>
<br /></div>
<br />
<b><u>org.jboss.weld.executor.properties</u></b><br />
<br />
# Executors should not be created on the GAE environment.<br />
threadPoolType=NONE<br />
<div>
<br /></div>
</blockquote>
<div>
Ensure that these property files end up in your <span style="font-family: Courier New, Courier, monospace;">WEB-INF/classes</span> directory. That will ensure that WELD does not spawn new threads at application startup.</div>
<div>
<br /></div>
<div>
Hope this was useful to you.</div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-11206745500535238282013-10-07T23:16:00.001+05:302013-10-07T23:16:48.695+05:30The Empty JSF Component<div dir="ltr" style="text-align: left;" trbidi="on">
JSF 2 was the much needed improvement on top of its predecessor. Most notable of its features was the Facelets view declaration language which, amongst various other things, allowed mixing HTML and JSF components together in the same file. A direct impact of this capability, was the ease with which a developer could translate HTML files in to functioning XHTML code.<br />
<br />
But then again, every now and then there would be this case where you need to set a rendered condition for a HTML element - like menu items or some thing represented using a <span style="font-family: Courier New, Courier, monospace;"><li></span> tag - which does not have any equivalent component in JSF. The most common way of handling such a situation is via the <span style="font-family: Courier New, Courier, monospace;"><c:if/></span> tags. Not a very elegant looking solution, but it works.<br />
<br />
Now if you, like me, are not a big fan of using the JSTL functions, then the chances are that you might have wondered, <i>"Why doesn't standard JSF just provide an empty JSF component that just had one attribute and only one attribute - a rendered condition!"</i><br />
<br />
Well, fret not, things are looking brighter. In the latest release, <b>JSF 2.2</b>, the <span style="font-family: Courier New, Courier, monospace;">FacesComponent</span> annotation got a make over with the addition of <a href="http://jdevelopment.nl/jsf-22/#594">3 new attributes</a>:<br />
<blockquote style="font-family: Courier New, Courier, monospace;">
<ul style="text-align: left;">
<li><b>createTag</b> - If set to true the component will be directly useable via a tag on a Facelet. </li>
<li><b>tagName</b> - Optional explicit name for the tag. If omitted, the class’ simple name with the first character in lowercase will be used. </li>
<li><b>namespace</b> - Optional explicit namespace for the tag. If omitted the namespace ‘http://xmlns.jcp.org/jsf/component’ will be used. </li>
</ul>
</blockquote>
<br />
, meaning you can create this empty JSF component with code as simple as the following:<br />
<br />
<blockquote style="font-family: Courier New, Courier, monospace;">
<div>
@FacesComponent(value = "group", createTag = true, tagName = "group")</div>
<div>
public class GroupComponent extends UIComponentBase</div>
<div>
{</div>
<div>
@Override</div>
<div>
public String getFamily()</div>
<div>
{</div>
<div>
return "Rogue.IO";</div>
<div>
}</div>
<div>
}</div>
</blockquote>
<br />
Next, you can use this new empty component in your Facelet page as shown below:<br />
<br />
<div>
<blockquote style="font-family: Courier New, Courier, monospace;">
<div>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"</div>
<div>
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"</div>
<div>
<b>xmlns:r="http://xmlns.jcp.org/jsf/component"</b>></div>
<div>
<!-- Adaptation of the bootstrap based drop down menu --></div>
<div>
<b><r:group rendered="#{menu.has.children}"></b></div>
<div>
<li class="dropdown"></div>
<div>
<a href="#" class="dropdown-toggle"</div>
<div>
data-toggle="dropdown"></div>
<div>
#{menu.name} <b class="caret"></b></div>
<div>
</a></div>
<div>
<ul class="dropdown-menu"></div>
<div>
<ui:repeat value="#{menu.children}" var="child"></div>
<div>
<li></div>
<div>
<a href="#">#{child.name}</a></div>
<div>
</li></div>
<div>
</ui:repeat></div>
<div>
</ul></div>
<div>
</li></div>
<div>
<b></r:group></b></div>
<div>
<b><r:group rendered="#{not menu.has.children}"></b></div>
<div>
<li></div>
<div>
<a href="#">#{menu.name}</a></div>
<div>
</li></div>
<div>
<b></r:group></b></div>
<div>
</ui:composition></div>
</blockquote>
</div>
<div>
<br />
No more JSTL hacks. Hope this was useful to you.</div>
<div>
<br /></div>
</div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-23588512422361184402009-02-15T17:38:00.010+05:302009-02-15T18:55:46.832+05:30A Case Study: Modularized Application Development with Struts2In today's development world, it is not uncommon for mid-to-large scaled projects to have multiple sub-modules which are then assembled for the final product deliverable.<br /><br />One of the common challenges involved with such development is pretty much the integration piece. Integration can be defined in a multitude of ways and as such there is no "one size fits all" solution. Let's scope our scenario down further. Let's say that our finished product is a web application which is composed of multiple sub-modules, where each module represents a service and this service can have an optional view layer that needs to be pulled into the finished product with all the linkages being proper. <span style="font-size:85%;"><span style="font-style: italic;">Personally I do not have a lot of work experience, but I have been faced with the same problem in two different companies, to make me believe that this could be a common scenario for quite a few other folks out there.</span></span><br /><br />In my previous project, I had a similar situation. At that time I was the architect, build-boy, source control administrator, module lead, business-analyst, client connect.... basically <span style="font-style: italic;">one-guy-fits-all-positions</span>!! And to make things worse, the technology stack for the project was already defined and the view layer would be completely written in Struts2. No offense to Struts2 what-so-ever, just that I was a Faces boy (not knowing anything about Struts except for the concepts) and here I was ... working in alien technologies :)<br /><br />Coming back to the subject, each of the sub-modules were publishing pages that needed to be integrated in the final application and linked via the menus too. During the earlier builds, the integration process was a nightmare, where we would pull in all the code, merge all the struts.xml files, update links on the menu-sections of the page - in one phrase - inefficiency at its best :)<br /><br />Just about when I was about to give up on the hopelessness of the situation, I decided to have a closer look at what Struts2 had to offer and I was pleasantly surprised that I could have the flexibility of distributed configurations (the type that I was used to with Faces) right within Struts! The key was the struts-plugin.xml file!!<br /><br />So the first thing I had to do was rewire our current modules a little bit. Let's take the following sample layout for a module:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia7R1fY7kwLnhGNAzeqlppN8oeJnCDqjOsamhvetDYmVmYWyq1KuMZ6VnV20b5BUuKyr_GMnUDgPwEDDxHGuCYCPbBK6OIQGbPoC1SxImOm_cSysrr81f0uDY5uMtYUoKYPUSi-Q/s1600-h/module-layout-1.png"><img style="cursor: pointer; width: 320px; height: 177px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia7R1fY7kwLnhGNAzeqlppN8oeJnCDqjOsamhvetDYmVmYWyq1KuMZ6VnV20b5BUuKyr_GMnUDgPwEDDxHGuCYCPbBK6OIQGbPoC1SxImOm_cSysrr81f0uDY5uMtYUoKYPUSi-Q/s320/module-layout-1.png" alt="" id="BLOGGER_PHOTO_ID_5302997278362843874" border="0" /></a><br /><br />Let's assume that each module has a DAO layer, a model / API layer, and a web layer. First thing that I had to do was ensure that my web-tier projects are creating jars instead of bundling the compiled code in the classes directory. Next, I moved over the <span style="font-style: italic;">struts.xml</span> <u>for the module</u> to <span style="font-style: italic;">src/java/struts-plugin.xml</span>. This would mean that <u><span style="font-style: italic;">my-module-view.jar</span></u> would contain the <span style="font-style: italic;">struts-plugin.xml</span> in its root directory. And anyone who has written plugins in Struts2 would know that the <span style="font-weight: bold;">all</span> <u>struts-plugins.xml</u> files available on the classpath are loaded up when the struts application starts.<br /><br />Neat. So I have one problem taken care of, which was the manual merging of the struts XML files. But I've still got one more problem to fix. The whole manual setup of the menu layouts in the application. Now why did we have to do this? 'Cause there was a need to make releases which had only a certain subset of modules available.<br /><br />This is where I got thinking ... each of my menu items opens up in to a page / view of the underlying module. And each of this menu items is pointing to an Action link ... so would it be possible to read all actions, and add a custom attribute to the action definition in the Struts xml file ... and then use this information to construct my menu??? Sounds logical, and yes ... it is absolutely doable!!<br /><br />All menu related actions were <u>augmented</u> with additional attributes in the struts xml file. So, now my struts XML files started to look as follows:<br /><br /><span style="font-size:85%;"><br /><pre><br /><struts><br /> <package name = "/mymodule/manage/"><br /> <action name = "ModuleSettings" ... ><br /> <result ...>...</result><br /> <param name="menu.id">My_Module_Settings</param><br /> <param name="menu.parent">ROOT_MENU</param><br /> <param name="menu.order">3</param><br /> <param name="menu.display.name">My Module Settings</param><br /> </action><br /> ....<br /> </package><br /></struts><br /></pre><br /></span>Once I had all the required parameters, it was now about reading these action files and setting up the menu model in memory. This can be easily achieved using the following lines of code:<br /><br /><span style="font-size:85%;"><br /><pre><br />function loadMenuItems() {<br /> Configuration configuration = Dispatcher.getInstance().getConfigurationManager().<br /> getConfiguration();<br /> Set<String> packageNames = configuration.getPackageConfigNames();<br /> for (String pName : packageNames) {<br /> parsePackages(config.getPackageConfig(pName));<br /> }<br />}<br /><br />function parsePackages(PackageConfig packageConfig) {<br /> Map<String, ActionConfig> actionConfigs =<br /> packageConfig.getActionConfigs();<br /> String namespace = packageConfig.getNamespace();<br /> for (String aName : actionConfigs.keySet()) {<br /> parseActionConfigs(namespace, aName, actionConfigs.get(aName));<br /> }<br />}<br /><br />function parseActionConfigs(String namespace, String aName,<br /> ActionConfig actionConfig) {<br /> // Check if the action config represents a menu element.<br /> Map<String, Object> params = actionConfig.getParams();<br /> if (params.containsKey(MENU_ID)) {<br /> // MenuAction found.<br /> String menuId = (String) params.get(MENU_ID);<br /> String parentId = (String) params.get(MENU_PARENT_ID);<br /> String displayName = (String) params.get(DISPLAY_NAME);<br /> String menuOrder = (String) params.get(MENU_ORDER);<br /><br /> // Now go ahead and create the menu item from the above information<br /> // and setup the menu context.<br /><br /> }<br /> }<br /><string><string,><string,><br /></string,></string,></string></pre><br /></span>Once I had the menu context initialized, then all I had to do was just rewrite the menu handling pages to use the menu context and publish information. The rest of the work of merging the wars into a single project was left to the build system =)<br /><br /><span style="font-size:85%;"><span style="font-weight: bold;">Note: </span>The above parameters are just an illustration and if you choose to leverage a similar approach, then you could potentially introduce other parameters, like security related information (ROLES / PERMISSIONS / etc).<br /><br />And obviously, due IP constraints, I will not be able to publish any of the code base, but here is something interesting... Among all the folks that I have interviewed in the past, almost all of them have no idea what Swing is all about and believe that Swing is purely for desktop. Yes, predominantly it is for the desktop, but hey... there is a <span style="font-style: italic;">javax.swing.tree </span>package and this package incidentally has a fullfledged Tree implementation!! What if I created a MenuItem that extended from DefaultMutableTreeNode ?? Don't you think that the whole effort of ordering and traversal could be completely ignored?? ;-)<br /></span><br />So this was the way I went about resolving a rather nagging problem in my development project. Do you have any interesting experiences / ideas that help solve similar situations??<br /><br />-RogueAnonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com2tag:blogger.com,1999:blog-13416240.post-35596057331570470192007-07-24T01:33:00.000+05:302013-10-22T08:30:34.638+05:30The Problem of Many<div dir="ltr" style="text-align: left;" trbidi="on">
The open source world of "Applications" is a funny & paradoxical collection of illustrations. On one hand, people unite together to get away from the clutches of those who tend to constrict users, whilst on the other petty differences in opinions leads to the creation and availability of a multitude of applications performing the same task, albeit in slightly differing shades. Some folks look at this as "the freedom to choose". I look at it as the lack of a concerting effort to amalgamate the best of features, in turn, producing the best-of-breed applications.<br />
<br />
Now, this does not mean that I am against the open-source concept or the proliferation of applications. I am just trying to explain a problem that I have noticed -- "The Problem of Many"<br />
<br />
I have Fedora 7 installed my laptop, and like most users I have installed various media related applications that are not installed/shipped by Fedora - like MPlayer, Xine, Helix, Real Player. Similarly on the audio front I have Amarok<sup>[1]</sup>, XMMS. Now these are in addition to the default set of applications - Totem, GNOME-CD, Rhythm Box, Sound Juicer, etc.<br />
<br />
Each application has its pros and cons and I definitely do not wish to get into a competitive analysis of each of these. What I would like to highlight is the cluttering of my menus. Currently my "Sound & Video" menu contains a plethora of applications (which of course I had installed) which pretty much do the same job<sup>[2]</sup>. See the following image inset for details.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs5BZJvY0_GAALE2TZKnyeAbDrJ_Xb-B2lyetgPFhlxnDE-kcO0nn_tL5MFMH7vh41BfUfgkUvTBR9uv6JnW1_XO9GzHhfboVkfHfVoCO-1ZWEUodojdPK7QBBAnt7kr89MhJn-A/s1600-h/application-clutter.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5090500772031108178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs5BZJvY0_GAALE2TZKnyeAbDrJ_Xb-B2lyetgPFhlxnDE-kcO0nn_tL5MFMH7vh41BfUfgkUvTBR9uv6JnW1_XO9GzHhfboVkfHfVoCO-1ZWEUodojdPK7QBBAnt7kr89MhJn-A/s320/application-clutter.png" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /></a><br />
Now I have been thinking, what if we could collapse all the similar applications into one <span style="font-style: italic;">extended-menu-item</span> ?<br />
<br />
What I really mean by that is, what if my "Sound & Video" menu opened into top level <span style="font-style: italic;">extended-menu-items</span>. These <span style="font-style: italic;">extended-menu-items</span> could be used to execute the <span style="font-style: italic;">user-configured</span> actions or could also be used to further drill down into options. The following images should highlight better what I have in mind.<br />
<br />
<br /><br /><br /><br /><br /><br /><table halign="center" style="width: 99%px;"><tbody>
<tr valign="top"><td><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH0STWB0xjpxe3hHOKOU8Njk07RAGnRogOhPkD1NB3F-Kw2HlOt5kjI8vj6j8-NOVaLGchKJZDDnHWoDwlCViRDQjDrZ86gehGT5V2cjS0GtX3aoBhAVawpUlfqDRBUdgfhB3raQ/s1600-h/level-1.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5090511354830525538" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhH0STWB0xjpxe3hHOKOU8Njk07RAGnRogOhPkD1NB3F-Kw2HlOt5kjI8vj6j8-NOVaLGchKJZDDnHWoDwlCViRDQjDrZ86gehGT5V2cjS0GtX3aoBhAVawpUlfqDRBUdgfhB3raQ/s320/level-1.png" style="cursor: pointer;" /></a></td><td><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZoop4bt5jTbEu8gJHSLUbrEg2qB1t8PL7sC20WrVXs6zSuhDgrvpZOCRhysoRcwz27nU-odaZJHBnUcaXWA22iT_O_TUxWAasWiMboLq-6mwoTuiQWoUBUdSQYjLBLoRtsA8dFg/s1600-h/level-2.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5090511462204707954" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZoop4bt5jTbEu8gJHSLUbrEg2qB1t8PL7sC20WrVXs6zSuhDgrvpZOCRhysoRcwz27nU-odaZJHBnUcaXWA22iT_O_TUxWAasWiMboLq-6mwoTuiQWoUBUdSQYjLBLoRtsA8dFg/s320/level-2.png" style="cursor: pointer;" /></a></td><td><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNyMFCZwC5yNC9MclY38L2TLwNkH8raVDuEhG613UVYjIPWoesnQfI9uzmoTBgCAKlUh4MeLZPAjEcC6oFMU7chD6IOevPwES5i7VPF3N7flZy0RpkV1LJBqEUZz1_59_khlrOSg/s1600-h/level-3.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5090511908881306770" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNyMFCZwC5yNC9MclY38L2TLwNkH8raVDuEhG613UVYjIPWoesnQfI9uzmoTBgCAKlUh4MeLZPAjEcC6oFMU7chD6IOevPwES5i7VPF3N7flZy0RpkV1LJBqEUZz1_59_khlrOSg/s320/level-3.png" style="cursor: pointer;" /></a></td></tr>
</tbody></table>
<br />
When I say <span style="font-style: italic;">user-configured</span> I am talking more on the lines of configuring your favorite application via one central UI -- like the current "Preferred Applications" UI in the GNOME install.<br />
<br />
I guess my idea does not <span style="font-style: italic;">really</span> solve the problem-of-many; it merely hides it, but I do believe that a solution such as the above could bring about an ease of application manageability within the desktop <span style="font-style: italic;">and of course I would happy with it :)</span><br />
<br />
What do you think about it?<br />
<br />
<hr />
[1] - Amarok though shipped with the install media is not installed by default on a GNOME desktop<br />
<blockquote>
</blockquote>
[2] - I am aware that most of the applications that I mentioned primarily target a specific media type, but my point is that this difference would soon be blurred out in the near future as each application tries to improve its support for the other media types.</div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-36035981085069399312007-05-12T15:39:00.000+05:302007-05-12T16:04:45.325+05:30Running Sun Secure Global Desktop (a.k.a. Tarantella) on your Fedora Core desktop<span style="font-family: verdana;">I have spent hours trying to understand why the Tarantella client does not work on my GNOME install. Every time I run the <span style="font-family: courier new;">ttwebtop</span> command, I would see a whole lot of warnings on the console and the end result was that I would not be able to type in anything in the login dialog.</span><br /><br /><span style="font-family: verdana;">After a lot of Googling and reading bugs, I chanced upon the possibility of a mismatch in the location of the <span style="font-family: courier new;">XKeysymDB</span> file. This file is available as part of <span style="font-family: courier new;">libX11</span> which is present on the system by default. The client tries to load up this file from the location <span style="font-family: courier new;">/usr/openwin/lib/XKeysymDB</span>, but the file is actually present at <span style="font-family: courier new;">/usr/share/X11/XKeysymDB</span>. In order for the application to pick it up, you need to define this new location as an environment variable - <span style="font-family: courier new;">XKEYSYMDB</span>. Once you set this variable, the client loads up fine, and I can start working from home again :-)</span><br /><br /><span style="font-family: verdana;">As a solution, I have this variable defined in my <span style="font-family: courier new;">~/.bashrc</span> file as follows</span><br /><br /><span style="font-family: courier new;">export XKEYSYMDB=/usr/share/X11/XKeysymDB</span><br /><br /><span style="font-family: verdana;">And I can start working from home again :-)</span><br /><br /><span style="font-style: italic;font-size:85%;" ><span style="font-family: verdana;">Note: The client in consideration is the Sun Secure Global Desktop version 4.2</span></span>Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-48685585656088772672007-01-29T23:20:00.000+05:302013-10-22T08:29:52.909+05:30Necessity is the mother of all inventions<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: verdana;">Who ever said it, couldn't have been more right. I find myself building utilities and applications everytime I don't find the right one :) .. During the past few days, I built a similar utility plugin and I thought I might as well share it with the rest of the world.</span><br />
<br />
<span style="font-family: verdana;">A little background... I work on a myriad set of applications and technologies, and this requires me to keep doing a lot of activities on different applications parallely. So off-late I have been working on providing a JSF component that pulls in a user's presence information from a backend RTC server. In this case the backend happens to be Microsoft's Live Communication Server. As you might have guessed, I have a .NET component that is doing all the talking with the LCS instance and this component exposes its features as a set of WebServices which are then consumed by the Java layer and published to the application via a JSF component. No points for anyone guessing that this can be a mess to handle all alone :-p</span><br />
<br />
<span style="font-family: verdana;">Everytime I need to perform some quick and dirty work, </span><a href="http://www.netbeans.org/" style="font-family: verdana;">Netbeans</a><span style="font-family: verdana;"> </span><span style="font-family: verdana; font-weight: bold;">is</span><span style="font-family: verdana;"> the IDE of choice. One day I was trying out something on similar lines, I needed to import only a subset of the Java classes into a project. And I knew that the IDE did not present me a feature where I could pick and choose. The only option I had was to copy the files over manually outside the IDE and then delete those that I didn't require. </span><span style="font-family: verdana; font-weight: bold;">That</span><span style="font-family: verdana;"> can be quite painful at times! I dearly wished I had an option where I could look at the files being imported in a tree structure, where I could just (un)select the files I wanted.... So I built myself one of those things :-D ... Here is a screenshot of the module in action..</span><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIsAGmdPFtbKLkEb_by47k0HV5Qh7h9DqTKHsUmGh5Ob-ibo97xY1-0U9rL5aea6N-AtZiuBQp05o5WgAMTPrLLrnEgXu9ga5pVsuFrooAMCuUT_spfav8mjfNb3nlsByvzipxSQ/s1600-h/ImportSourcesInAction.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5025517751014378226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIsAGmdPFtbKLkEb_by47k0HV5Qh7h9DqTKHsUmGh5Ob-ibo97xY1-0U9rL5aea6N-AtZiuBQp05o5WgAMTPrLLrnEgXu9ga5pVsuFrooAMCuUT_spfav8mjfNb3nlsByvzipxSQ/s320/ImportSourcesInAction.png" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /></a><br />
<span style="font-family: verdana;">As a part of my work, I ran into a hard-to-trace, intermittent bug that would cause the .NET layer to crash once in a while. One rather good thing that I did do was use Log4Net's logger within the entire .NET code. So I whipped out my IDE of choice, built the test-bed and began the debugging. Everything was fine and going smooth, except that I had to switch between two applications to keep monitoring the output. That is when I though... "How I wish I had a module that could tail this file and show me the data within the IDE itself!". I took a measure of the expected effort, realized it wasn't much, went ahead and built myself exactly what I wanted. Check it out in action....</span><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCLrGPv9dvb7XAWB_lny-7R3tNg-al-4sPkQK9ableyoMow2RkWrzK9rHv3tJHM_darqE4mJuu-SK26IPhcJTqBQziG2Tnzz8yS7Iw8fXSDc3fTpGCsaPxCYUtkEFpeKxB5AgumQ/s1600-h/TailModuleInAction.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5025522780421081858" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCLrGPv9dvb7XAWB_lny-7R3tNg-al-4sPkQK9ableyoMow2RkWrzK9rHv3tJHM_darqE4mJuu-SK26IPhcJTqBQziG2Tnzz8yS7Iw8fXSDc3fTpGCsaPxCYUtkEFpeKxB5AgumQ/s320/TailModuleInAction.png" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /></a><br />
<span style="font-family: verdana;">Like what you see? Get it </span><a href="http://roguexz.googlepages.com/netbeans" style="font-family: verdana;">here</a><span style="font-family: verdana;">.</span><br />
<br />
<span style="font-family: verdana;">Thats all for now, later!</span></div>
Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-79027203957479612702007-01-20T01:52:00.000+05:302007-01-20T03:14:02.989+05:30Java6: GroupLayout and a small gotcha<span style="font-family:verdana;"><br />The new layout manager, <span style="font-style: italic;">GroupLayout</span>, which is part of the JavaSE 6 bundle is great and coupled with Netbeans' Matisse component, makes a killer combination. Today I would like to talk about an issue that I ran into and hopefully would be able to help others running into the same issue.<br /><br />Anyways, if you try hand-coding this layout for your components, there is a rather subtle thing to remember. In Java 5, if you wanted to add a component to a container like JPanel, you would do something like:<br /><pre><br /><span style="color: rgb(102, 0, 204);"> ....</span><br /><span style="color: rgb(102, 0, 204);"> JPanel jp = new JPanel();</span><br /><span style="color: rgb(102, 0, 204);"> JButton button = new JButton(...);</span><br /><span style="color: rgb(102, 0, 204);"> jp.getContentPane().add(button);</span><br /><span style="color: rgb(102, 0, 204);"> ....</span><br /></pre><br /><br />The key point to notice is that you would explicitly get hold of the content pane and then add the component to it. Now with Java 6, the good old ways of adding a component directly to the parent are back (which internally ensures that the component is added to the content pane), i.e., the same example above could be simplified as:<br /><pre><br /><span style="color: rgb(102, 0, 204);"> jp.add(button);</span><br /></pre><br />All this fine and nice. Now when using <span style="font-style: italic;">GroupLayout</span>, the code might look as follows (in Java 5):<br /><pre><br /><span style="color: rgb(102, 0, 204);"> GroupLayout layout = new GroupLayout(jp.getContentPane());</span><br /><span style="color: rgb(102, 0, 204);"> jp.getContentPane().setLayout(layout);</span><br /><span style="color: rgb(102, 0, 204);"> ... // add the component to the layout</span><br /></pre><br />Since I was working with Java 6, I decided to use the simplified notation and did the following:<br /><pre><br /><span style="color: rgb(102, 0, 204);"> GroupLayout layout = new GroupLayout(jp);</span><br /><span style="color: rgb(102, 0, 204);"> jp..setLayout(layout);</span><br /><span style="color: rgb(102, 0, 204);"> ... // add the component to the layout</span><br /></pre><br />And was I in for a shock when I ran the code !!! I kept seeing the following stack trace on my screen :-O<br /><pre><br /><span style="color: rgb(255, 0, 0);"> Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: </span><br /><span style="color: rgb(255, 0, 0);"> GroupLayout can only be used with one Container at a time</span><br /><span style="color: rgb(255, 0, 0);"> at javax.swing.GroupLayout.checkParent(GroupLayout.java:1095)</span><br /><span style="color: rgb(255, 0, 0);"> at javax.swing.GroupLayout.invalidateLayout(GroupLayout.java:987)</span><br /><span style="color: rgb(255, 0, 0);"> ......</span><br /></pre><br />It took me a while (<span style="font-style: italic;">which involved going through the source-code of GroupLayout</span>) to figure out that the problem was actually with the way I am initializing the damn <span style="font-style: italic;">GroupLayout</span> instance! The layout instance considers that it is being applied to the container ( <span style="font-style: italic;">JPanel</span> in our case) whereas, the <span style="font-style: italic;">setLayout()</span> method delegates the call to the content pane. And <span style="font-style: italic;">GroupLayout</span> does a check to see that the host and owner are the same, if not, it throws a rather undecipherable exception like the one above. The key to getting it run was just simply to pass the content pane to the constructor of the <span style="font-style: italic;">GroupLayout</span> instance.<br /><pre><br /><span style="color: rgb(102, 0, 204);"> GroupLayout layout = new GroupLayout(jp.getContentPane());</span><br /><span style="color: rgb(102, 0, 204);"> jp..setLayout(layout);</span><br /><span style="color: rgb(102, 0, 204);"> ... // add the component to the layout</span><br /></pre><br />This experiment sure was good learning, but it would have been great if the implementation of <span style="font-style: italic;">GroupLayout</span> threw a more meaningful exception stating the obvious rather than leaving us to figure out the obscure bits!<br /><br />Thats all for now.</span>Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com15tag:blogger.com,1999:blog-13416240.post-1144272368460256622006-04-06T02:35:00.000+05:302006-04-07T13:05:30.900+05:30Getting your ZeroG installer to work on your latest and greatest Linux distroCertain versions of the ZeroG installers have a serious issue when installing software on the Linux desktops. You start seeing a variety of errors like<br /><br /><span style="font-style:italic;color:red">"/bin/ls: error while loading shared libraries: librt.so.1: cannot open shared object file: No such file or directory"</span><br /><br /> ... and many others, while you can very clearly see that the library files are present on the file system.<br /><br />I face the same issue while installing Oracle Calendar desktop client on my FC 5 Linux distro. When i started googling for the errors encountered, i started to see a lot of rather half-answered posts which did not work for me. Sufficient enough to piss me off, i started debugging the installer by setting the debug param to true.<br /><br /><span style="font-style:italic;color:red">>LAX_DEBUG=1 sh cal_linux</span><br /><br />This gave me some leads and i finally figured that there was some kind of work around being applied because the installer kept thinking that the JVM being used had a version less than 1.4, which was inturn caused by the fact that the installer was setting the LD_ASSUME_KERNEL variable to 2.2.5 ... <br /><br />The version information was pulled of from a set of variables called v_major, v_minor, etc.. Fix these values and you are good to go :)<br /><br /><span style="font-style:italic;color:red">>v_minor=4 sh cal_linux</span><br /><br />voila!! the installation goes through smoothly :)<br /><br />If you would like to further customize the installation by specifying the JDK to be used, then you could achieve the same by the following command:<br /><br /><span style="font-style:italic;color:red">>v_minor=5 sh cal_linux LAX_VM /usr/java/jdk1.5.0_06/bin/java</span><br /><br />Hope that helps you folks out there.Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-1143899053794740842006-04-01T18:34:00.000+05:302006-04-01T19:14:13.903+05:30Connecting your Nokia 2112 with your Fedora Core 5Here is a quick and dirty hack for connecting your Nokia 2112 CDMA phone to your linux box as an internet modem.<br /><br />My hardware / software details:<br />* Fedora Core 5<br />* Nokia 2112 CDMA phone<br />* CA-42 cable.<br /><br />Upon connecting your phone the usual response in the messages log is:<br /><br /><span style="font-style:italic;">drivers/usb/class/cdc-acm.c: This device cannot do calls on its own. It is no modem.</span><br /><br />None the less, register it as a modem.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1968/443/1600/modem.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/1968/443/320/modem.jpg" border="0" alt="" /></a><br /><br />Now go ahead and create a new internet connection based on this modem. Specify all the connection information (username, password, dial in number, etc.)<br /><br />Now the last step :)<br />Open up your <span style="font-style:italic;">/etc/wvdial.conf</span> file. In here you need to get rid of the +FCLASS option. Just remove this word from the init parameters, and that is it.<br /><br />Now you should be able to connect to your internet :)<br /><br />Have fun!!<br /><br />p.s.: At times the wvdial.conf file keeps getting overriden. You will notice this everytime you get an error code of 8. If you get this error code, then just repeat the last step of removing the +FCLASS statement.Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com0tag:blogger.com,1999:blog-13416240.post-1117901080254722022005-06-04T21:14:00.000+05:302005-07-03T20:17:14.196+05:30Jumpstarting your JPDK portlets with DBPreferenceStoreJPDK Portlets are easy and fun to create. All you need is a neat idea, and a feasible solution to portletize it. Not all is fun though. There are a few caveats, which may not be visible right at the beginning. To know what exactly I am talking about, consider the following case study.<br /><br /><div style="margin-left: 40px;"><br />Rogue is a very innovative developer. One fine day, he gets a brilliant idea to portletize a very popular application. He publishes his portlet, and gets a very wide appreciation. The portlet is deployed on a major production site, which has thousands of employees using and customizing it, to suit their needs. The customer comes to Rogue with a very desired enhancement, and Rogue implements it and provides the new version to the customer.<br /><br /><span style="font-weight: bold;">But</span>, Rogue had designed the portlet to use <span style="font-style: italic;">FilePreferenceStore</span> for storing the user preferences. The customer, unaware about this detail, goes ahead and re-deploys the provider on his production system, and boom..... all the user customizations have been erased!!<br /><br /><span style="font-weight: bold;">Now</span>, the customer, rather frantic, pulls the archived version, searches the web and identifies that he needs to copy the customizations folder back to the new deployment. Things finally work, and the customer realizes his folly, and learns his lesson the hard way.<br /></div><br /><br />Though the above case study is fictitious, it is a very common scenario that happens with people who are not well versed with the JPDK framework. The above scenario could be avoided if only the developer (Rogue here) had implemented the portlet solution to utilize database based preference store.<br /><br />I definitely agree that it is easier to use the file system based preference store, as there are no additional configurations to perform when deploying the provider, but a little additional effort can go a long way. Using DBPreferenceStore for storing user preferences translates to the following:<br /><br /><ul> <li>User preferences are independent of the provider deployment</li> <li>Easy upgrade / migration path – new portlet version, new container, different m/c, etc.</li> <li>Technically, you could support high-availability for these portlets, by deploying them on multiple containers, and sharing the sessions across the containers.</li> </ul><br />, And other benefits that I have missed out here.<br /><br />Setting up a DBPreferenceStore is as simple as deploying an .ear file. All you need to do is:<br /><ul><br /><li>Install the JPDK preference store schema on a database.</li><li>Create a datasource within the application server container which points to the above created schema.</li><li>Make a reference to this datasource in your portlet’s provider.xml file.<br /></li></ul><div style="margin-left: 40px;">Sample Example:<br />1. Provider.xml file configured to use FilePreferenceStore<br /><pre><br /><preferenceStore class="oracle.portal.provider.v2.preference.FilePreferenceStore"><br /> <name>EasyAccessPrefStore</name><br /> <useHashing>true</useHashing><br /></preferenceStore><br /></pre><br /><br />2. Provider.xml file configured to use DBPreferenceStore<br /><pre><br /><preferenceStore class="oracle.portal.provider.v2.preference.DBPreferenceStore"><br /> <name>EasyAccessPrefStore</name><br /> <connection>jdbc/dbprefstore2</connection><br /></preferenceStore><br /></pre><br /></div><br />I am among the few people who are skeptical about working on the database, and prefer to work as much as possible via the web-based interfaces. Hence, I came up with a utility web-application (<span style="font-style: italic;">DbPrefStoreUtil</span>), which installs the database schema required for DBPreferenceStore, on a remote database. This application is available on <a href="http://portalstudio.oracle.com/servlet/page?_pageid=2112&_dad=ops&_schema=OPSTUDIO&_mode=3">Knowledge Exchange</a> under my personal folder (Search for contributor: <span style="font-style: italic;">harsha.ramesh</span>). I have also included a detailed document on how one can setup a datasource via the OracleAS Enterprise Manager or the OC4J Admin Console on the standalone OC4J.<br /><br />So the next time you decide to implement a portlet solution, try and see if you could provide a solution based on DBPreferenceStore.<br /><br /><span style="font-style:italic;">Screenshots:</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1968/443/1600/page1.jpg"><img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/1968/443/200/page1.jpg" border="0" alt="" /></a><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1968/443/1600/page2.jpg"><img style="float:left; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/1968/443/200/page2.jpg" border="0" alt="" /></a>Anonymoushttp://www.blogger.com/profile/12226430696550842744noreply@blogger.com2