Showing posts with label jee. Show all posts
Showing posts with label jee. Show all posts

Tuesday, July 29, 2014

Locales in Liferay

I wanted to configure the languages available in Liferay 6.2 runtime interface site settings (Site Administration → Configuration → Site Settings → Display Settings → Language) to include Russian and Azerbaijani — but these were not even listed among available languages. From portal source I verified that language pack for Russian indeed exists (not for Azerbaijani though!).

Having had a look at portal.properties gives a hint that interface languages in Liferay runtime depend on locales.enabled setting, which can be overriden in one of the Liferay configuration files (reading order: portal.properties, portal-bundle.properties, portal-ext.properties & portal-setup-wizard.properties). So e.g. locales.enabled=en_US,ru_RU in portal-ext.properties will do the trick for making Russian locale available, for Azerbaijani, one would need to start translating.

And later I found that available locales can also be set from Control Panel → Configuration → Portal Settings → Display Settings → Available Languages :)

Friday, July 18, 2014

Liferay 6.2 archetypes

Maven (build tool and a Trickster) provides several Liferay specific archetypes with com.liferay.maven.archetypes archetypeGroupId. Some of these are tied to MVC frameworks to be used in Liferay portlet (e.g liferay-portlet-jsf-archetype), others assembled for more generic functionality. Sample command line to generate Liferay portlet project structure without any MVC specifics added:

mvn archetype:generate \
     -DarchetypeGroupId=com.liferay.maven.archetypes \
     -DarchetypeArtifactId=liferay-portlet-archetype \
     -DarchetypeVersion=6.2.10.6 \
     -DgroupId=thecompany.com \
     -DartifactId=company-portlet-one \
     -Dversion=0.1-SNAPSHOT \
     -DinteractiveMode=false

The list of all available Maven archetypes can be seen with: mvn archetype:generate command. Following MVC agnostic archetypes are available in com.liferay.maven.archetypes group.

  1. liferay-ext-archetype — for creating customizations as Liferay extension, also called ext plugin. With ext plugins Liferay core functionality can be replaced with modifications separate from Liferay's code. Jamie L Sammons writes: Liferay Ext Plugins are often considered a last resort in the Liferay Plugin world due to the complexity and the lack of hot deploy as well as the inability to remove them once they are deployed.

  2. liferay-hook-archetype — for Liferay customization, a hook has advantage of hot deploy. Web resources, JSPs, portal services, etc can be overridden with hooks. Hooks can also be defined in portlets.

  3. liferay-layouttpl-archetypelayout templates allow definition of new page layouts, embedding commonly used portlets in layouts, specifying CSS, etc.

  4. liferay-portlet-archetype — minimalistic Liferay portlet to be deployed in portal.

  5. liferay-servicebuilder-archetype — to generate a basic service layer. It comes with promise of CRUD and SOAP all in place for the entities.

  6. liferay-theme-archetype — Liferay theme plugin archetype for user interface customization of sites in Liferay.

  7. liferay-web-archetype — creates a minimal web application skeleton, Liferay specific addition being WEB-INF/liferay-plugin-package.properties file, allowing to manage that application from Liferay Control Panel.

Wednesday, July 15, 2009

Coincidental Eagerness

I had web application crashing on me with org.hibernate.LazyInitializationException on certain web application page.

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

Everyone who has ever used Hibernate instantly recognizes the problem. Smart proxy that Hibernate uses to load child entities of an entity on-demand could not perform its duty as the entity instance had already escaped the data layer and session had been closed. Child objects could be loaded eagerly in the data layer to make problem go away.

I examined the code and clearly child objects whose attempted retrieval resulted in the exception were never loaded. Weirdly, no-one else received exception on that page. The web layer code where exception occurred was roughly as this:
// Q, QLabel & Language are Hibernate entities
private String getQTitleInLang(Q q, String langCode) {
for (QLabel ql: q.getLabels()) {
// QLabel's Language is uninitialized, getCode() fails
if(langCode != null && ql.getLanguage().getCode().equals(langCode)){
return ql.getDescription();
}
}
return null;
}
The data layer code that loaded the main entity was bad Hibernate usage, manually forcing the n+1 selects. Actually it was worse. It had 2 nested for loops, each calling Hibernate.initialize() on many child entities. But that is besides the point, I cleaned it up a bit for the sake of example.
private void initQ(Set<q> qs) throws HibernateException {
for (Q q: qs) {
Hibernate.initialize(q.getLanguages());
Hibernate.initialize(q.getLabels());
}
}
Correct but bad fix is to add the nasty loop that initializes QLabels:
private void initQ(Set<q> qs) throws HibernateException {
for (Q q: qs) {
Hibernate.initialize(q.getLanguages());
Hibernate.initialize(q.getLabels());
// The ugly fix. In real code that brings 3rd nested for loop.
for (QLabel ql: q.getLabels()) {
Hibernate.initialize(ql.getLanguage());
}
}
}
So why did the code work for everyone else? It was just that they happened to work with different database. In their databases all the Language entities that QLabels' owned coincided with those that Q itself had as its child Languages.

As Hibernate Session holds a mandatory first-level cache of persistent objects that are used when navigating the object graph or looking up objects by identifier, that made the "unloaded" entities accessible under certain conditions.

Session-level caching just happens to work so well that code coincidentally works sometimes :)