tag:blogger.com,1999:blog-3369520762253532892024-02-20T01:01:26.282-08:00Toby's Brain Dump ...Welcome to my blog where occasional rants,
grumble and mumble about things in life expressed
as code ... <br>
... essentially my cat /dev/null ... ^_^!!Unknownnoreply@blogger.comBlogger21125tag:blogger.com,1999:blog-336952076225353289.post-38260420109411011522012-12-09T01:25:00.002-08:002012-12-09T01:25:59.958-08:00java.sql.SQLException: No suitable driver Exception <p/>
Just a quick note, if you are seeing
<pre name="code">
java.sql.SQLException: No suitable driver ...
</pre>
although you are pretty sure you have :-
<ul>
<li>
Got the jdbc connection information correct
<ul>
<li>db username</li>
<li>db password</li>
<li>db url</li>
<li>db driver class</li>
</ul>
</li>
<li>
Got the driver jar file in the classpath for your web all
</li>
<li>
You are using connection pooling such as c3p0 or commons-pool
</li>
</ul>
It might be time to try sticking that jdbc driver jar file into the servlet container's global classpath. This approach seems to work well in my case. Haven't dig into connection pooling code but this is my guess. When the connection pool starts up it tries to register the jdbc Driver using perhaps
<pre name="code">
Class.forName("... jdbc driver....");
</pre>
and for some reason seems to be loading it through system classloader hence if our jdbc driver jar file is in our webapp level, it's being missed causing this exception.
<p/>
Hopefully, this helps whoever hits this issue.
<p/>
Cheers
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-48592503759344076842012-11-21T14:52:00.000-08:002012-11-21T14:52:14.622-08:00Sitemesh, my favourite web development companionI've always like <a href="http://wiki.sitemesh.org/display/sitemesh/Home">Sitemesh</a> even those days before I was introduced to WebWork. I guess after that I just like it even more. Funny thing is not much people seems to be using Sitemesh out there though. Guess more people are familiar with Tiles thanks to Struts I guess.
<br />
This is what i know about Sitemesh and what works for me when setting up Sitemesh
<br />
<h2>
#1 Declare sitemesh filters in web.xml</h2>
<pre class="xml" name="code"><web ...="...">
<filter>
<filter-name>sitemesh
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter
</filter>
...
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*/<url-pattern>
</filter-mapping>
</web>
</pre>
<br />
<h2>
# 2 add sitemesh.xml and decorator.xml in '/WEB-INF/' directory</h2>
sitemesh.xml by default exists in sitemesh jar file and the copy in sitemesh jar file will be used if one cannot be found in /WEB-INF directory. It's really useful to have a custimizable copy of sitemesh.xml lying in your /WEB-INF directory so you can tweak and perhaps add custom parsers, mappers etc. Following is a copy of a typical sitemesh.xml file
<br />
<pre class="xml" name="code"><sitemesh>
<property name="decorators-file" value="/WEB-INF/decorators.xml">
<excludes file="${decorators-file}">
<page-parsers>
<parser class="com.opensymphony.module.sitemesh.parser.HTMLPageParser" content-type="text/html">
</parser>
</page-parsers>
<decorator-mappers>
<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
<param name="property.1" value="meta.decorator" />
<param name="property.2" value="decorator" />
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
<mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
<param name="decorator" value="printable" />
<param name="parameter.name" value="printable" />
<param name="parameter.value" value="true" />
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
<param name="config" value="${decorators-file}" />
</mapper>
</decorator-mappers>
</sitemesh>
</pre>
Couple of important things :-
<br />
<h3>
Parsers</h3>
These are sitemesh parser parsing html into sitemesh internal Page object to be used by mappers, decorators etc., we'd rarely need to ever change this
<br />
<h3>
<property> tag</h3>
These are tags so you can later refer to the property value through ${...} syntax.
<br />
<h3>
<excludes> tag</h3>
Exclude files from being parsed, we wanna exclude ${decorator-file} which points to /WEB-INF/decoratorsx.ml cause we have a mapper that specifically parse this file later.
<br />
<h3>
<mapper> tag</h3>
mappers map an incoming request to a decorator which decorates in incoming request and producing a decorated request ultimately returned to the browser. They are executed in order and <code>ConfigDecoratorMapper</code> should always be the last cause it is a 'catch all' mapper.
Following is a typical copy of <code>decorators.xml</code>
<br />
<pre class="xml" name="code">
<decorators>
<excludes>
<pattern>/bootstrap/*
</excludes>
<decorator name="error_page" page="/WEB-INF/decorators/error_page_layout.jsp">
<pattern>/error.do
</decorator>
...
<decorator name="information_panel" page="/WEB-INF/decorators/information_panel_layout.jsp">
</decorator>
</decorators>
</pre>
With the above example
<br />
<ul>
<li>'/bootstrap/*' will not be decorated</li>
<li>'/error.do' will be decorated by '/WEB-INF/decorators/error_page_layout.jsp'
</li>
</ul>
In the layout jsp, we could use the following tags :-
<br />
<pre class="xml" name="code"> <%@taglib prefix="sitemesh-decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
<%@taglib prefix="sitemesh-page" uri="http://www.opensymphony.com/sitemesh/page" %>
<sitemesh-decorator:title />
<sitemesh-decorator:head />
<sitemesh-decorator:body />
<sitemesh-decorator:getProperty property="..." default="[default value if no property found]" writeEntireProperty="[yes/no]" />
<sitemesh-decorator:usePage id="..." />
<sitemesh-page:applyDecorator name="..." title="..." page="..."/>
</pre>
<h3>
<sitemesh-decorator:title/> tag</h3>
Get the content inside html <title> tag of our original html page
<h3>
<sitemesh-decorator:head/> tag</h3>
Stick in the <head> tag content of our original html page, only the content not the enclosing tags though.
<h3>
<sitemesh-decorator:body/> tag</h3>
Stick in the <body> content of our original html page, everything in it.
<h3>
<sitemesh-decorator:usePage id="..." /></h3>
Stick sitemesh Page object into request scope under the variable name given by 'id' attribute.
<h3>
<sitemesh-page:applyDecorator page="..."/></h3>
Apply the decorator given by 'page' attribute against the body of this tag. In other words, the body of this tag is going to be decorated by the decorator given in page attribute.
<pre class="xml" name="code"> <!--
Apply decorator named 'myDecorator' on the body of this tag.
-->
<sitemesh-page:applydecorator name="myDecorator">
...
</sitemesh-page:applydecorator>
<!--
Apply decorator located at '/WEB-INF/decorators/myDecorator' on the body
of this tag overriding the title (if exists) in the body of this tag.
-->
<sitemesh-page:applydecorator page="/WEB-INF/decorators/myDecorator" title="...">
...
</sitemesh-page:applydecorator>
</pre>
<h3>
<sitemesh-decorator:getProperty /> tag</h3>
Stick in the parsed original html page's bits and pieces Eg.
<html> tag attributes are sticked in as properties without any prefix
<title> tag content are sticked in as 'title'
<body> tag attributes are sticked in with prefix 'body'
<meta> tag 'content' attributes content are sticed in with prefix 'meta'
Eg. <br />
<pre class="xml" name="code">with :-
<html myAttribute="test">
<head>
<title>my title</title>
<meta name="meta-name" content="meta-content" />
</head>
<body onload="alert('ready');">
</body>
</html>
<!--
This will gives us "test" from <html> tag's attribute
-->
<sitemesh-decorator:getProperty property="myAttribute" />
<!--
This will gives us 'my title' from the content of <title> tag
-->
<sitemesh-decorator:getProperty property="title" />
<!--
This will gives us 'meta-content' from tag with name 'meta-name'
-->
<sitemesh-decorator:getProperty property="meta.meta-name" />
<!--
This will gives us 'alert('ready');' from onload attribute in <body> tag
-->
<sitemesh-decorator:getProperty property="body.onload" />
</html></pre>
<br />
Chao ^_^Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-336952076225353289.post-83321235319328409642012-11-06T15:14:00.000-08:002012-11-06T15:20:49.265-08:00Do we need equals(...) and hashcode(...) overrides in JPA domain objects ?The idea of overriding equals(...) and hashcode(...) is such that an object can be uniquely identified through some more meaningful semantics instead of the default semantics which basically says that "object of the same class are equals if they are in the same memory location".
<p/>
With JPA implementations, the concerns we have when leaving equals(...) and hashcode(...) as defaults are :-
<ol>
<li>Composite primary Key will not work
<li>Issues with detaching and merging of domain objects
<li>Multiple copies of objects that are semantically similar can exists in our collection object</li>
<li>entityManager.persist(...)</li>
</ol>
<h3>#1 Composite Key will not work </h3>
If we are not using composite key at all, then we should be fine. Is composite key a good thing to used compared to just say running number generated off sequence by the database itself is another topic of itself. I suppose if we are doing it for an existing database with tons of data already populated with some natural composite key being already in place, we'll just have to live with it. If it's a green field project, do we really want to use natural keys as our composite key?
<ul>
<li>Natural composite primary key takes up more indexing space compared to just incremental number as primary key</li>
<li>Database might take up more time when storing natural composite key assuming the index is a BTREE, where it needs to find the slot to stick in the composite key. Incremental number is just more predictable to the db in this case and I guess most db will be coded to take advantage of this.</li>
</ul>
<h3>#2 Issues with detaching and merging</h3>
This is a major concern. I guess the question is do me really need to use the merging feature of JPA? Following are some bits we want to take into account when doing a merge.
<ul>
<li>lazy-loaded relationships aren't going to be merge even if CascadeType is MERGE unless they are triggered before detach</li>
<li>merging across a relationship that is being removed will caused an exception</li>
<li>merging across a relationship that doesn't exists in persistence context will have undefined consequences except if the CascadeType across that relationship is MERGE</li>
<li>accidently 'null'ing out a detached non-lazily loaded or a triggered lazily loaded relationship will null out its counterpart in the persistence context when merging</li>
</ul>
<p/>
It's much more convenient, in my humble opinion, to just do an DIY merge rather then relying on JPA's merging mechanisms (this comes from a web developer perspective). Say, we have forms on web pages that upon submit gets to a Spring controller where the values from the form are being populated in to a command object. We could just do a DIY merge into the domain object we do an 'entityManager.find(...)'.
<pre name="code" class="java">
@PersistenceContext
private EntityManager em;
public String submission(Command command, BindingResult bindingResult, Model model){
...
MyDomainObject domainObject = em.find(...);
domainObject.setSomeProperty(command.getSomeProperty());
...
}
</pre>
<b>But doesn't that means I'll lost my Optimistic Locking check if i have a '@Version' property in my entity?</b>
<p/>
Unfortunately I guess to a certain extend yes. So we'd probably wanna do that bit of logic ourselves.
<p/>
<h3>#3 Multiple copies of objects that are semantically similar can exists in our collection object</h3>
If we do
<pre name="code" class="java">
Set<MyDomainObject> set = ... ;
set.add(new MyDomainObject("jack"));
set.add(new MyDomainObject("jack"));
</pre>
both will be treated as different entity and will result in 2 records in the set itself. However this is arguably controllable in our application, surely we'll have some sort of validation be it in the controller or service that restrict addition that do not make any business sense.
<p/>
<h3>#4 entityManager.persist(...)</h3>
So if we have an auto-generated primary key eg.
<pre name="code" class="java">
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
</pre>
the id will only be valid after <code>entityManager.persist(...)</code> is invoked, else it'd be zero (the default value for any long primitive type). Since we did not overrides equals(...) and hashcode(...) to based on 'id' for equality, we are safe to use our domain object after <code>entityManager.persist(...)</code> is called.
<p/>
Just me 2 cents. If you have a natural business key for your domain objects that uniquely identify itself, feel free to override equals(...) and hashcode(...). If you decide not to and if you are ok with working around some restrictions, that you should be fine as well.
<p/>
CheersUnknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-3098899067671620542012-08-23T19:48:00.000-07:002012-08-23T19:48:48.588-07:00Finding a file from a bunch of jar files<p/>
Just had a need to quickly find a file eg. the super pom location in maven which was suspected to be in one of the jar files located within Maven's lib director ($MAVEN_HOME/lib).
<p/>
The following command seems to work for me, it took me some time messing around with commands to get this out, so guess it would be beneficial to put it down here just to keep myself reminded and also hopefully help some others who are googling for the same stuff.
<p/>
Eg. to find the super pom located in one of the jars within Maven's lib directory we could do
<pre name="code" class="java">
find . -iname '*.jar' | xargs -n 1 jar -tvf | grep -i '**.xml'
</pre>
This would gives us something like
<pre name="code" class="java">
...
1523 Thu Feb 24 12:34:04 EST 2011 META-INF/maven/org.sonatype.aether/aether-api/pom.xml
3908 Mon Feb 28 18:28:26 EST 2011 META-INF/maven/org.apache.maven/maven-embedder/pom.xml
2222 Mon Feb 28 18:27:48 EST 2011 META-INF/maven/org.apache.maven/maven-settings-builder/pom.xml
...
1931 Mon Feb 28 18:28:12 EST 2011 META-INF/maven/org.apache.maven/maven-repository-metadata/pom.xml
2248 Mon Feb 28 18:27:52 EST 2011 META-INF/maven/org.apache.maven/maven-model-builder/pom.xml
...
</pre>
But it doesn't tell us which jar file it's in. The simplest way I found was to
<pre name="code" class="java">
find . -iname '*.jar' | xargs --verbose -n 1 jar -tvf | grep -i '**.xml'
</pre>
<pre name="code" class="java">
jar -tvf ./aether-api-1.11.jar
1523 Thu Feb 24 12:34:04 EST 2011 META-INF/maven/org.sonatype.aether/aether-api/pom.xml
jar -tvf ./maven-embedder-3.0.3.jar
3908 Mon Feb 28 18:28:26 EST 2011 META-INF/maven/org.apache.maven/maven-embedder/pom.xml
jar -tvf ./maven-settings-builder-3.0.3.jar
....
jar -tvf ./maven-model-builder-3.0.3.jar
13206 Mon Feb 28 18:30:32 EST 2011 META-INF/plexus/components.xml
4840 Mon Feb 28 18:30:30 EST 2011 org/apache/maven/model/pom-4.0.0.xml
2248 Mon Feb 28 18:27:52 EST 2011 META-INF/maven/org.apache.maven/maven-model-builder/pom.xml
...
</pre>
Now we could tell Maven's super pom, <code>pom-4.0.0.xml</code>, is in <code>maven-model-builder-3.0.3.jar</code> file under <code>/org/apache/maven/modem/</code> directory.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-74530450952556105782012-05-30T01:30:00.007-07:002012-05-30T01:31:39.683-07:00GZip Content-Encoding and and Chunked Transfer-Encoding with Liferay 6.0.x<p/>
Liferay has a <a href="http://docs.liferay.com/portal/6.0/javadocs/com/liferay/portal/servlet/filters/gzip/GZipFilter.html">GZipFilter</a> which is turn on by default and gzip response for performance reason. Performance as in bandwidth saving and shorter download time for slow clients eg. those on dial-ups etc. This doesn't necessary means more CPU efficient, as gziping and related processing takes up CPU cycles.
<p/>
<a href="http://docs.liferay.com/portal/6.0/javadocs/com/liferay/portal/servlet/filters/gzip/GZipFilter.html">GZipFilter</a> is basically a <code>javax.servlet.Filter</code> that wraps up the <code>HttpServletResponse</code> with <a href="http://docs.liferay.com/portal/6.0/javadocs/com/liferay/portal/servlet/filters/gzip/GZipResponse.html">GZipResponse</a>
<p/>
<pre name="code" class="java">
protected void processFilter(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) {
...
if (isCompress(request) && !isInclude(request) &&
BrowserSnifferUtil.acceptsGzip(request) &&
!isAlreadyFiltered(request)) {
...
GZipResponse gZipResponse = new GZipResponse(response);
processFilter(GZipFilter.class, request, gZipResponse, filterChain);
gZipResponse.finishResponse();
...
}
...
}
</pre>
<p/>
<a href="http://docs.liferay.com/portal/6.0/javadocs/com/liferay/portal/servlet/filters/gzip/GZipResponse.html">GZipResponse</a> is just a wrapper that overrides methods related to OuputStream and Writer such that it delegates the output streaming and writing to <a href="http://docs.liferay.com/portal/6.0/javadocs/com/liferay/portal/servlet/filters/gzip/GZipStream.html">GZipStream</a> (at least for Liferay 6.0.x it is)
<pre name="code" class="java">
public class GZipResponse extends HttpServletResponseWrapper {
public GZipResponse(HttpServletResponse response) {
super(response);
_response = response;
}
public void finishResponse() {
try {
if (_writer != null) {
_writer.close();
}
else if (_stream != null) {
_stream.close();
}
}
catch (IOException e) {
}
}
public void flushBuffer() throws IOException {
if (_stream != null) {
_stream.flush();
}
}
public ServletOutputStream getOutputStream() throws IOException {
if (_writer != null) {
throw new IllegalStateException();
}
if (_stream == null) {
_stream = _createOutputStream();
}
return _stream;
}
public PrintWriter getWriter() throws IOException {
if (_writer != null) {
return _writer;
}
if (_stream != null) {
throw new IllegalStateException();
}
_stream = _createOutputStream();
_writer = new UnsyncPrintWriter(new OutputStreamWriter(
//_stream, _res.getCharacterEncoding()));
_stream, StringPool.UTF8));
return _writer;
}
private ServletOutputStream _createOutputStream() throws IOException {
return new GZipStream(_response);
}
</pre>
<p/>
<a href="http://docs.liferay.com/portal/6.0/javadocs/com/liferay/portal/servlet/filters/gzip/GZipStream.html">GZipStream</a> upon <code>close()</code> just decides to write the content-length header to the response.
<pre name="code" class="java">
public class GZipStream extends ServletOutputStream {
public void close() throws IOException {
if (_closed) {
throw new IOException();
}
_gzipOutputStream.finish();
int contentLength = _unsyncByteArrayOutputStream.size();
_response.setContentLength(contentLength);
_response.addHeader(HttpHeaders.CONTENT_ENCODING, _GZIP);
try {
flushOutToOutputStream();
}
catch (IllegalStateException ise) {
flushOutToWriter();
}
_closed = true;
}
}
</pre>
What this means is that if you want Content-Encoding to be 'gzip' and Transfer-Encoding to be 'chunked' in Liferay 6.0.x, the answer is not possible, unless you disabled GZipFilter through portal-ext.properties, and cooked up one of your own. Might want to consider Tomcat's connector which does 'gzip' content encoding as well as auto transfer-encoding as chunk when the buffer size is exceeded, if i got my facts right. It's a bit disappointing as I was hoping Liferay to handle this better. Chunked transfer-encoding is good when you have a huge content where you don't want to buffer it up cause it use up too much unnecessary memory.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-5066111512280283732012-04-06T23:14:00.000-07:002012-04-06T23:14:50.275-07:00Must read article if you are doing anything serious using GIT<p>
GIT reset explained in details in a very easy to understand manner. Even if you think you know about <b>git rest</b> already, pretty sure you'll be surprised with that subtle insight you get after ready <a href="http://progit.org/2011/07/11/reset.html">this</a> article by the author of <a href="http://www.amazon.com/Pro-Git-Scott-Chacon/dp/1430218339/ref=sr_1_1?s=books&ie=UTF8&qid=1333779243&sr=1-1">ProGit</a>
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-69097785030698240132012-03-30T21:19:00.000-07:002012-03-30T21:20:00.518-07:00Sharing Liferay's Portal ClassLoader<p>
It is possible to share Liferay Portal's <a href="http://docs.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html">ClassLoader</a> with Liferay's plugins (eg. Portlets WARs and also independent Servlets)
</p>
<p>
Say if I have a Servlet called Servlet1 that was packaged in a separate WAR that I'd like to use Liferay Portal's classloader, I'd need to declare it as a <a href="http://docs.liferay.com/portal/6.0/javadocs/com/liferay/portal/kernel/servlet/PortalClassLoaderServlet.html">PortalClassLoaderServlet</a> through the following configurations in it's web.xml
</p>
<pre name="code" class="java">
<servlet>
<servlet-name>PortalClassLoaderServlet</servlet-name>
<servlet-class>com.liferay.portal.kernel.servlet.PortalClassLoaderServlet</servlet-class>
<init-param>
<param-name>servlet-class</param-name>
<param-value>foo.bar.Servlet1</param-value>
</init-param>
<load-on-startup>100</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>PortalClassLoaderServlet</servlet-name>
<url-pattern>/servlet1/*</url-pattern>
</servlet-mapping>
</pre>
<p>
With this declaration and with Liferay deployed as a separate WAR file, Servlet1 will be registered when Liferay starts up and is aware of Liferay Portal's lifecycle, and will get initialized and destroyed (through Servlet's init(ServletConfig) and destroy() methods respectively) when Liferay Portal startup and shutdown). When a request is being made to Servlet1, PortalClassLoaderServlet will act as a proxy that swaps the current request thread's context ClassLoader with the ClassLoader that Liferay Portal is started up with and so you get all the classes that comes with Liferay Portal.
</p>
<p>
Technically, i think it is possible to take this further and having PortalServlet loaded using the same classloader as Liferay Portal through the following web.xml configuration
</p>
<pre name="code" class="java">
<servlet>
<servlet-name>MyPortal Servlet</servlet-name>
<servlet-class>com.liferay.portal.kernel.servlet.PortalClassLoaderServlet</servlet-class>
<init-param>
<param-name>servlet-class</param-name>
<param-value>com.liferay.portal.kernel.servlet.PortletServlet</param-value>
</init-param>
<init-param>
<param-name>portlet-class</param-name>
<param-value>foo.bar.portlets.MyPortlet</param-value>
</init-param>
<load-on-startup>100</load-on-startup>
</servlet>
</pre>
<p>
But care must be taken to make sure classes that was used also exists in Liferay Portal WAR or in say Tomcat's public library classpath. Messing with ClassLoader is always hazardous and best to be avoided if possible. That's my 2 cents.
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-52335457764563842162012-03-23T21:35:00.001-07:002012-03-23T21:39:58.048-07:00Liferay's 3 Servlets Musketeers (PortalActionServlet, PortalServlet and MainServlet)<b><u><a href="http://docs.liferay.com/portal/6.1/javadocs-all/com/liferay/portal/servlet/MainServlet.html">MainServlet</a></u></b>
<p>
This is the main servlet in Liferay, it handles all request directed to the portal itself, mapped to '/c/*' as in Liferay's ROOT web.xml. Together with various <a href="http://docs.liferay.com/portal/6.1/javadocs-all/com/liferay/portal/servlet/FriendlyURLServlet.html">FriendlyURLServlet</a> mappings in web.xml, they almost handle all the happenings in Liferay. FriendlyURLServlet normally analyze friendly urls and do a redirect after regenerating friendly urls back to the complex form that Liferay happens to understand through <a href="http://docs.liferay.com/portal/6.1/javadocs-all/com/liferay/portal/util/PortalUtil.html">PortalUtil</a>
<p/>
<b><u><a href="http://docs.liferay.com/portal/6.1/javadocs-all/com/liferay/portal/kernel/servlet/PortletServlet.html">PortletServlet</a></u></b>
<p>
This is the servlet that will get autogenerated during deployment of Portlet Plugins WAR file. It is really just a simple proxy pumping in resources to your portlet. Checkout <a href="http://docs.liferay.com/portal/6.1/javadocs-all/com/liferay/portal/deploy/auto/PortletAutoDeployer.html">PortletAutoDeployer</a> on how it is written to your Portlet Plugin WAR's web.xml during hot deployment. Remember that the whole Portlet framework is after all based on Servlet specs, this Servlet gives Liferay a way to push through resources to a specific portlet.
</p>
<b><u><a href="http://docs.liferay.com/portal/6.1/javadocs-all/com/liferay/portal/struts/PortletActionServlet.html">PortalActionServlet</a></u></b>
<p>
In short, forget about this Servlet, it is a legacy Servlet as far as my understanding goes. Why? All it does is make sure a copy of PortletRequestProcessor (sounds familiar? yes, its an extension of Struts's RequestProcessor) is available in ServletContext under <a href="http://docs.liferay.com/portal/6.1/javadocs-all/com/liferay/portal/util/WebKeys.html#PORTLET_STRUTS_PROCESSOR">WebKey.PORTLET_STRUTS_PROCESSOR</a>. This is now (Liferay 6.1.x) being taken care of in <a href="http://docs.liferay.com/portal/6.1/javadocs-all/com/liferay/portal/servlet/MainServlet.html#checkPortletRequestProcessor(javax.servlet.http.HttpServletRequest)">MainServlet.checkRequestProcessor</a> method. Think of it this way. Where does your portlet lives? Inside a Portal container of course. Any request to your portlet have to go through a Portal container first, and that means going through MainServlet which will make sure a copy of PortletRequestProcessor is available nicely before eventually hitting your portlet. Humbly think that this is a nicer way rather than having each Portlet WAR file declaring a PortletActionServlet, cause the following is how PortletActionServlet stick a copy of PortletRequestProcessor into ServletContext
</p>
<pre name="code" class="java">
ServletContext servletContext = getServletContext();
ModuleConfig moduleConfig =
(ModuleConfig)servletContext.getAttribute(Globals.MODULE_KEY);
PortletRequestProcessor portletRequestProcessor =
PortletRequestProcessor.getInstance(this, moduleConfig);
servletContext.setAttribute(
WebKeys.PORTLET_STRUTS_PROCESSOR, portletRequestProcessor);
</pre>
It's coupling in Struts's specific way of looking up ModuleConfig into it's code, which arguable isn't going to change much in the near future anyway but still ... I think it's tight coupling
<p>
This is how it's done in MainServlet.checkPortletRequestProcessor(...)
</p>
<pre name="code" class="java">
ServletContext servletContext = getServletContext();
PortletRequestProcessor portletReqProcessor =
(PortletRequestProcessor)servletContext.getAttribute(
WebKeys.PORTLET_STRUTS_PROCESSOR);
if (portletReqProcessor == null) {
ModuleConfig moduleConfig = getModuleConfig(request);
portletReqProcessor =
PortletRequestProcessor.getInstance(this, moduleConfig);
servletContext.setAttribute(
WebKeys.PORTLET_STRUTS_PROCESSOR, portletReqProcessor);
}
</pre>
<p>
which is doing it through <a href="http://struts.apache.org/1.x/apidocs/org/apache/struts/action/ActionServlet.html#getModuleConfig(javax.servlet.http.HttpServletRequest)">getModuleConfig(request)</a> methods relying on Struts's <a href="http://struts.apache.org/1.x/apidocs/org/apache/struts/action/ActionServlet.html">ActionServlet</a> to provide the implementation and hence abstracting it away from potential future changes in implementation
</p>
<p>
This are really just my understandings on briefly digging into Liferay's source through occasionally a VI on a terminal over a glass of red or coffee during spare times over lunch break or weekends. If you disagree in anyway, I'd love to be corrected.
</p>
<p>
Anyway Liferay looks like a promising portal solution and I would definitely be exploring further
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-77503958747113434582012-03-12T00:54:00.000-07:002012-03-12T00:54:35.465-07:00Ever wonder how Liferay keeps track of it's WAR'ed Portlets<p/>
<a href="www.liferay.com">Liferay</a> is a portlet container. With the distribution that comes with Tomcat bundled in by default, it deployed it's main portal into tomcat's ROOT. This main portal will have all the bits and pieces to manage portlets deployed subsequently as WAR files, which without much surprised gets deployed into separate webapps with it's own application context default to the war file name being dumped into Liferay's deploy directory, conveniently located one level above the tomcat home within Liferay distribution. To manage those Portlets located under different webapps, Liferay needs some way to tie the Portlet's Servlet path to it's ServletContext.
<p/>
Ever wonder how Liferay does this?
<p/>
Have the opportunity to dig around a bit with Liferay's code and guess what, this is how Liferay does it. It has a <a href="http://svn.liferay.com/repos/public/portal/branches/6.1.x/portal-service/src/com/liferay/portal/kernel/servlet/ServletContextPool.java">ServletContextPool</a> which is basically something like a static factory singleton with a bunch of public static methods accessing a single instance of itself. Servlet corresponding to a particular Portlet when initialized will just make use of those relevant static methods to stick it's context path and ServletContext into a map.
<p/>
You might wonder how is this possible when all webapps are being deployed to have it's own <a href="http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ClassLoader.html">ClassLoader</a>. Which means webapp1 will have it's own copy of ServletContextPool which will be separate instance from webapp2. Although they are accessing static methods they are still separate instance due to webapp1 and webapp2 have separate classloaders that do not allow them to see each other's classes.
<p/>
But ClassLoaders are hierarchical and most app servers will eventually inherit a global ClassLoader, Tomcat is not difference. What Liferay does is it package ServetContextPool into portal-service.jar which unsurprisingly located in Tomcat's lib/ext folder which happens to be Tomcat's glabal classpath. Jars located there will be visible to all web application.
<p/>
Interesting. Pretty simple and straight forward way of getting it done. Does this kind of implementation sounds familiar? Ring any bells? I'm guessing this is somewhat similar way <a href="www.slf4j.org">SLF4j (Standard Log4j)</a> decide which logging implementation to hook up in runtime.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-32989826656771048342012-03-09T22:10:00.000-08:002012-03-12T00:55:26.839-07:00Ouch!! ... mvn liferay:build-service hurts ...<p/>
I've been trying to generate bunch of services using
<pre name="code" class="java">
mvn liferay:build-service -P liferay-plugins-development
</pre>
where <i><b>liferay-plugins-development</b></i> profile contains properties setting of my liferay version and deployment directory, and was bumped with the following exception
<pre name="code" class="java">
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 17.172s
[INFO] Finished at: Sat Mar 10 16:50:43 EST 2012
[INFO] Final Memory: 4M/15M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal com.liferay.maven.plugins:liferay-maven-plugin:6.1.0:build-service (default-cli) on project myliferay-portlet: Execution default-cli of goal com.liferay.maven.plugins:liferay-maven-plugin:6.1.0:build-service failed: An API incompatibility was encountered while executing com.liferay.maven.plugins:liferay-maven-plugin:6.1.0:build-service: java.lang.AbstractMethodError:
com.liferay.util.sl4fj.LiferayLoggerAdapter.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljav/lang/Throwable;)V
[ERROR] -----------------------------------------------------
[ERROR] realm = plugin>com.liferay.maven.plugins:liferay-maven-plugin:6.1.0
[ERROR] strategy = org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy
[ERROR] urls[0] = file:/...../maven_repo/com/liferay/maven/plugins/liferay-maven-plugin/6.1.0/liferay-maven-plugin-6.1.0.jar
[ERROR] urls[1] = file:/...../maven_repo/com/liferay/portal/portal-impl/6.1.0/portal-impl-6.1.0.jar
</pre>
Suspect this has something to do with different version of SLF4j that is not compatible with the one that maven resolved to when running liferay-maven-plugin, so went ahead and force the SLF4j version that the plugin was using to 1.5.5
<pre name="code" class="java">
...
<build>
<plugins>
<plugin>
<groupId>com.liferay.maven.plugins</groupId>
<artifactId>liferay-maven-plugin</artifactId>
<version>${liferay.version}</version>
<configuration>
<autoDeployDir>${liferay.auto.deploy.dir}</autoDeployDir>
<liferayVersion>${liferay.version}</liferayVersion>
<pluginType>portlet</pluginType>
</configuration>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.5</version>
</dependency>
</dependencies>
</plugin>
...
</build>
...
</pre>
It seems to fix this issue, but now I'm bumped with another NullPointerException coming off liferay-maven-plugin source itself. Logged a defect with the Liferay team <a href="http://issues.liferay.com/browse/MAVEN-15">here (MAVEN-15)</a>. Will have to wait and see how this paints out.
<p/>
Liferay-maven-plugin turns out to be quite a pain in the neck for me ... :-( Guess I should be evaluating <a href="http://www.liferay.com/community/wiki/-/wiki/Main/Liferay+IDE">Liferay IDE</a> instead to see if it suits me better. It does required that the whole plugins project to be under a <a href="http://www.liferay.com/community/wiki/-/wiki/Main/Plugins+SDK">Liferay-Plugin-SDK</a> directory though.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-336952076225353289.post-16520814066528473952012-03-05T18:42:00.001-08:002012-03-05T23:25:12.097-08:00Liferay's Maven Archetypes<p/>
Been googling a bit for Liferay maven archetypes available, well typically for 6.1.0 as pre 6.1.0 does not have any maven archetypes in public repositories, and they aren't just listed in one web page. Putting them all down here in one place just so it's easier for whoever that's googling for this piece of information. This is the official <a href="http://www.liferay.com/web/mika.koivisto/blog/-/blogs/12034718">Liferay blog</a> that list down all the possible Liferay Maven archetypes, which are :-
<ul>
<li>liferay-ext-archetype</li>
<li>liferay-hook-archetype</li>
<li>liferay-layouttpl-archetype</li>
<li>liferay-portlet-archetype</li>
<li>liferay-theme-archetype</li>
<li>liferay-web-archetype</li>
</ul>
with the following properties
<pre name="code" class="java">
liferay.version
liferay.auto.deploy.dir
</pre>
through my profile settings in ~/.m2/settings.xml
<pre name="code" class="java">
<settings>
...
<profiles>
...
<profile>
<id>liferay-plugins-development</id>
<properties>
<liferay.version>...</liferay.version>
<liferay.auto.deploy>...</liferay.auto.deploy>
</properties>
</profile>
...
</profiles>
...
</settings>
</pre>
with the mvn command to invoke them as follows
<pre name="code" class="java">
mvn archetype:generate
-DarchetypeArtifactId=liferay-portlet-archetype
-DarchetypeGroupId=com.liferay.maven.archetypes
-DarchetypeVersion=6.1.0
-DarchetypeCatalog=local,remote
-DartifactId=sample-portlet
-DgroupId=com.liferay.sample
-Dversion=1.0-SNAPSHOT
</pre>
and the following mvn command just to install the whatever resultant artifacts using the 'liferay-plugins-development' profile
<pre name="code" class="java">
mvn install -P liferay-plugins-development
</pre>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-336952076225353289.post-7396540900052879872012-02-28T14:52:00.000-08:002012-02-28T14:53:14.337-08:00Bash command that save my ass over and over again<p/>
The following linux commands are really no brainer stuff that every elementary course would have taught us, and it saved my butt many times over and over again.
<p/>
<pre name="code" class="java">
find . -iname <some file name>
</pre>
To find files recursively
<p/>
<pre name="code" class="java">
find . -iname <some file name> | xargs
</pre>
To find files recursively and list them out horizontally separated by space and doing escaping when necessary
<p/>
<pre name="code" class="java">
find . -iname <some file name> | xargs <some other bash commands>
</pre>
To find files recursively and list them out as arguments such that we could perform other commands on it like rm -f (force delete) for example
<p/>
<pre name="code" class="java">
grep -ir 'some text' .
</pre>
Find all files recursively starting with the current directory
<p/>
We could do interesting stuff like
<pre name="code" class="java">
find . -iname '*.xml' | xargs grep -i "testing"
</pre>
Find all xml files recursively starting with current directory that has text 'testing' contains in it.
<p/>
Bash commands ROCKS! It's always worthwhile if you are using a windows machine to install Cygwin, it comes with bash by default so you could dig up code segment quickly rather than relying on the pathetic doggy search that comes with Windows. Just me 2 cents !Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-67852877890558523642011-12-20T21:29:00.000-08:002011-12-20T21:30:13.289-08:00Sample XiangQi (Chinese Chess) written with PlayN<p>Got a bit of time and start off writing a simple sample app of XiangQi (Chiness Chess in PlayN), following is a few screenshots of it.</P>
<p>Its a simple 2 player game, using simple json to transfer data between client and server running off servlet in GAE</p>
<p>I think PlayN is a framework with pretty good potential, just like any new framework it needs time to mature and settle in I guess. Too bad the apk generated doesn't run on an emulator, I'll need to find an actual device to try things out :-( </p>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-k494x3i42YY/TvFrc-li24I/AAAAAAAAACw/bJJ1VRxDlu0/s1600/xiangqi_pic1.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="317" src="http://1.bp.blogspot.com/-k494x3i42YY/TvFrc-li24I/AAAAAAAAACw/bJJ1VRxDlu0/s320/xiangqi_pic1.JPG" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Picture 1</td></tr>
</tbody></table>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-FkG9jDBHvFo/TvFrkxOFcWI/AAAAAAAAAC8/HPdlsbkfP-I/s1600/xiangqi_pic2.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="316" src="http://4.bp.blogspot.com/-FkG9jDBHvFo/TvFrkxOFcWI/AAAAAAAAAC8/HPdlsbkfP-I/s320/xiangqi_pic2.JPG" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Picture 2</td><td class="tr-caption" style="text-align: center;"><br /></td><td class="tr-caption" style="text-align: center;"><br /></td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-86505136799832728372011-12-20T20:18:00.000-08:002011-12-20T20:19:31.099-08:00PlayN will not run in Android Emulator :-(Tried deployed one of the simple game wrote using PlayN and was popped up with this
<pre name="code" class="java">
12-21 03:58:12.579: ERROR/AndroidRuntime(372): FATAL EXCEPTION: GLThread 10
12-21 03:58:12.579: ERROR/AndroidRuntime(372): java.lang.IllegalArgumentException: No configs match configSpec
12-21 03:58:12.579: ERROR/AndroidRuntime(372): at android.opengl.GLSurfaceView$BaseConfigChooser.chooseConfig(GLSurfaceView.java:825)
12-21 03:58:12.579: ERROR/AndroidRuntime(372): at android.opengl.GLSurfaceView$EglHelper.start(GLSurfaceView.java:981)
12-21 03:58:12.579: ERROR/AndroidRuntime(372): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1326)
12-21 03:58:12.579: ERROR/AndroidRuntime(372): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1180)
12-21 03:58:12.608: WARN/ActivityManager(75): Force finishing activity com.tmjee.playn.xiangqi.android/.XiangqiActivity
12-21 03:58:12.618: WARN/WindowManager(75): Failure taking screenshot for (216x135) to layer 21030
</pre>
Oh my god, looks like games written in PlayN cannot be tested in an emulator :-( looks like the emulator is not supporting the necessary OpenGL stuff .... Ouch !!! ....Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-69516501994819335342011-12-18T19:44:00.000-08:002011-12-18T19:44:35.387-08:00Nice article for implementing AI on gamesCame across this nice little article about implementing AI in games basically chess-like games. Worth a read, so <a href="http://www.progtools.org/games/tutorials/ai_contest/minmax_contest.pdf">here</a> it is.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-40205653569844609432011-12-12T18:33:00.001-08:002011-12-18T19:41:03.664-08:00XHR call results in browser doing an OPTIONS method requestThis issue got me bugged for a while, XHR request when inspected in firebug seems to be sending out a HTTP OPTIONS method. If this happened to you, suggest the first thing to check is if the XHR is trying to do a cross-domain request, apparently 127.0.0.1 and localhost are being treated by my firefox as being cross-domain. I always thought cross-domain was not possible with XHR but apparently things changed and it is actually possible now (that's if you have control of the server you are trying to 'cross-domain' to) cause it involves sending bunch of Accept-* headers back. In a nut shell, the browser might sent an HTTP OPTION method request to find out if that piece of resource is allowed to be 'cross-domained'. Googleling gives me the followings
<ul>
<li><a href="http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/">http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/</a></li>
<li><a href="https://developer.mozilla.org/en/HTTP_access_control">https://developer.mozilla.org/en/HTTP_access_control</a></li>
</ul>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-29432032663130712622011-12-04T17:46:00.001-08:002011-12-04T17:57:27.972-08:00mvn eclipse:eclipse failed to work<p/>I found that
<pre>
mvn eclipse:eclipse
</pre>
do not really work well when you've got multiple modules in your maven structure like <a href="http://code.google.com/p/playn">PlayN</a>, spitting out the following error
<pre>
Failed to execute goal org.apache.maven.plugins:maven-eclipse-plugin:2.8:eclipse (default-cli) on project playn-archetype
Request to merge when 'filtering' is not identical.
</pre>
After some digging and trying out, it seems that specifying a specific version of maven-eclipse-plugin seems to make it happy, guessing maven gets confused when trying to resolve which maven-eclipse-plugin to use in the process. Anyway here's the one that works for me
<pre name="code" class="java">
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.6</version>
</plugin>
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-19477072696596368532011-11-26T04:29:00.001-08:002011-11-28T04:51:11.881-08:00Ubuntu 11.10 Post installations<p/>Just got my notebook updated to Ubuntu 11.10. If you are doing so or planning to do so, then <a href="http://theindexer.wordpress.com/2011/10/22/to-do-list-after-installing-ubuntu-11-10-aka-oneiric-ocelot/">this</a> will be a good article about post-installation goodies you might be interested in apt-get'ing. Enjoy and I hope it doesn't cost you too much fuss.
<p/>Also <a href="http://askubuntu.com/questions/29553/how-can-i-configure-unity/62903#62903">this</a> if you'd like to install CompizConfig settings manager to customize how ubuntu 11.10 look.
<p/>And <a href="http://superuser.com/questions/348027/can-i-make-ubuntu-11-10s-desktop-look-like-11-04s-ubuntu-classic">this</a> to install gnome-session or gnome-session-classic if you just can't get use to the current look of Ubuntu 11.10Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-39538169731163074252011-11-24T04:18:00.001-08:002011-11-24T04:21:01.001-08:00Little Password Text Widget ... TriplePlayHack around a little bit to get a little Password Text Widget from <a href="https://github.com/threerings/tripleplay/">TriplePlay</a>, again crude but works for me ...
<pre name="code" class="java">
public class PasswordField extends Field {
@Override
protected String getLayoutText () {
String ltext = text.get();
// we always want non-empty text so that we force ourselves to always have a text layer and
// sane dimensions even if the text field contains no text
if (ltext == null || ltext.length() == 0) {
return " ";
}
StringBuffer r = new StringBuffer();
for (int a=0; a<ltext.length(); a++) {
r.append("*");
}
return r.toString();
}
}
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-49545602504327065072011-11-24T02:03:00.000-08:002011-11-24T04:26:18.660-08:00An Image based Text Widget for TriplePlay<p/>Starting to look into <a href="https://github.com/threerings/tripleplay" target="_blank">PlayN</a> for a bit and whole bunch of utilities build for it like <a href="https://github.com/threerings/tripleplay" target="_blank">TriplePlay</a> and <a href="https://github.com/threerings/react" target="_blank">React</a>. I like the way <a href="https://github.com/threerings/tripleplay" target="_blank">TriplePlay</a> struture it's widgets. You developed using <a href="https://github.com/threerings/tripleplay" target="_blank">TriplePlay</a> widgets and it works across platforms without being dependent on the platform's native machinery. Following is a crude way to implement an Text display widget that source it's text from image. Hopefully, <a href="https://github.com/threerings/tripleplay" target="_blank">TriplePlay</a> will incorporate more of such components into it's distribution. <a href="https://github.com/threerings/tripleplay" target="_blank">TriplePlay</a> is still young so there're definitely plenty of room for enhancements.
<p/>A bit crude but it works.
<pre name="code" class="java">
public abstract class AbstractImageTextWidget<T extends AbstractImageTextWidget<T>> extends TextWidget<T> {
public AbstractImageTextWidget(String text) {
this(text, null);
}
public AbstractImageTextWidget(String text, Image icon) {
this.text.update(text);
if (icon != null)
setIcon(icon);
}
protected void createTextLayer(LayoutData ldata, float tx, float ty, float twidth, float theight, float availWidth, float availHeight) {
if (twidth > 0 && theight > 0) {
tlayer = prepareCanvas(_tlayer, twidth, theight);
char[] textArray = text.get().toCharArray();
float eachTextWidth = twidth / textArray.length;
if (textArray.length > 0) {
for (int a=0 ; a<textArray.length; a++) {
Image i = getCharMap().get(Character.toLowerCase(textArray[a]));
if (i != null)
_tlayer.canvas().drawImage(i, a*eachTextWidth, 0f, eachTextWidth, theight);
}
}
tlayer.setTranslation(tx + ldata.halign.offset(twidth, availWidth), ty + ldata.valign.offset(theight, availHeight));
}
}
protected abstract Map<Character, Image> getCharMap();
}
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-336952076225353289.post-18169886221843257852011-11-23T04:08:00.000-08:002011-11-24T04:23:56.798-08:00Moving to BloggerI used to have a blog in <a href="http://tmjee.jroller.com/tmjee/">JRoller</a>, but I guess I'll be moving on now to <a href="tmjee.blogger.com">Blogger</a>. Yippie. :)Unknownnoreply@blogger.com0