Profile

Recent Bloggers

Neil Griffin Posts: 20
Stars: 59
Date: 7/30/10
Jorge Ferrer Posts: 34
Stars: 157
Date: 7/30/10
Alice Cheng Posts: 155
Stars: 13
Date: 7/29/10
Ronald Sarayudej Posts: 118
Stars: 275
Date: 7/29/10
Stephen Wilburn Posts: 1
Stars: 3
Date: 7/28/10
Samuel Liu Posts: 3
Stars: 2
Date: 7/27/10
Juan Fernández Posts: 8
Stars: 22
Date: 7/26/10
Ray Augé Posts: 46
Stars: 201
Date: 7/24/10
Brian Chan Posts: 33
Stars: 214
Date: 7/23/10
Nate Cavanaugh Posts: 33
Stars: 115
Date: 7/20/10

Blogs

OpenSocial Gadgets: Custom Preferences UI

 In an earlier post I demonstrated how to add OpenSocial Gadgets as first-class citizens within Liferay. In this post I'd like to show you how  we have created a custom preferences UI.

This sample gadget has three preferences: pref1, pref2, and pref3.

 

<?xml version="1.0" encoding="UTF-8" ?>

<Module>

<ModulePrefs title="Multiple SetPref - Iframe">

  <Require feature="setprefs"/>

</ModulePrefs>

<UserPref name="pref1"

          datatype="string"

          default_value="0" />

<UserPref name="pref2"

          datatype="string"

          default_value="0" />

<UserPref name="pref3"

          datatype="string"

          default_value="0" />

<Content type="html">

...

</Content>

</Module>

To access our custom preference UI, go to "Configuration" :

 

Liferay 6: OpenSocial Gadgets

 Liferay 6 will feature an OpenSocial container based on Shindig. OpenSocial Gadgets present as first-class citizens via the "Add Application" menu, just like portlets.

To configure a Gadget in Liferay, all you need is the Gadget URL. In the screenshots below I've configured three gadgets:

  1. http://www.labpixies.com/campaigns/todo/todo.xml
  2. http://www.google.com/ig/modules/horoscope.xml
  3. http://localhost:8080/opensocial-portlet/gadgets/files/samplecontainer/examples/SocialHelloWorld.xml (this is a sample Shindig gadget)

 

 

Migrating SVN Servers for Everyone

Back in Nov 2008 we migrated SVN servers for committers. We pushed our commits to the Sourceforge SVN server on a regular basis, and that worked well for some time. Recently we discovered that large commits could not be synced and we've had an outdated Sourceforge repository for a couple weeks.

Now that our new SVN servers are quite stable and we've completed the migration for all committers, we've opened anonymous read access for everyone.

To migrate your local source code to the new servers, simply issue a relocate command, like this:

svn switch --relocate https://lportal.svn.sourceforge.net/svnroot/lportal svn://svn.liferay.com/repos/public

or

svn switch --relocate https://lportal.svn.sourceforge.net/svnroot/lportal http://svn.liferay.com/repos/public

 

 

Fisheye Server

One of the benefits of having our own dedicated SVN servers is that we have been able to set up a Fisheye server at http://svn.liferay.com. We tried to set up Fisheye against our Sourceforge.net servers, but because of the size of our repository and remote connection we could never get the initial index to complete.

We've also set up the Fisheye plugin for JIRA so that you can view the changelog associated with every issue.

A big thank you to Atlassian for granting us open source licenses.

Liferay Read-Write Database Splitting

The Beauty of Sponsored Development

As a company that likes to work very closely with our community, we're often given the opportunity to work on some very interesting (and many times very challenging) features. The following is one such feature being sponsored by one of our marquee partners: Read-Write database splitting. They are planning a Liferay deployment that scales to several millions of users

Because of the dynamic data-intensive nature of this deployment, they've identified that they're likely to to database-bound during peak load.  In order to scale database throughput they wanted to us to implement a mechanism within Liferay that would direct transactional (write) and read-only operations to separate data sources.

How was this done?

First, by using one of lesser-known features of the Spring Framework, target sources, we implmented a custom DynamicDataSourceTargetSource to do the job (if you're not familiar with target sources, one of the nifty things you can do is hot-swap a dynamic proxy's target object at runtime). This DynamicDataSourceTargetSource allows us to switch between read and write data sources at the appropriate time.

Secondly, we wanted to take advantage of Spring's transactional boundaries to help us decide when to use the appropriate data source. Before we did that, there were a couple items that needed cleanup and refactoring:

1) Use @Transactional in favor of xml transaction configuration. Annotations are a better fit for transactions because they allow better fine-grained control of transaction rules. Luckily this transition was very easy because all of our services are autogenerated via ServiceBuilder, so very little coding was needed.

2) We created our own @Transactional interface free of Spring dependencies so that it can be used in our plugins environment. This is virtually a mirror of Spring's @Transactional. We decomposed Spring's <tx:annotation-driven /> and replaced it with our own:

<bean id="transactionAdvice" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="liferayTransactionManager" />
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource">
<constructor-arg>
<bean class="com.liferay.portal.spring.annotation.PortalTransactionAnnotationParser" />
</constructor-arg>
</bean>
</property>
</bean>

As you can see we had to implement our own PortalTransactionAnnotationParser to read our custom @Transactional annotation.

3) Now that we have the annotations in place, it's very simple to add additional logic to swap data sources. We created a DynamicDataSourceTransactionInterceptor (subclass of Spring's TransactionInterceptor). This interceptor piggybacks spring's transaction boundary logic to help us decide when to use read or write data sources:

<bean id="transactionAdvice" class="com.liferay.portal.dao.jdbc.aop.DynamicDataSourceTransactionInterceptor">
<property name="dynamicDataSourceTargetSource" ref="dynamicDataSourceTargetSource" />
<property name="transactionManager" ref="liferayTransactionManager" />
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource">
<constructor-arg>
<bean class="com.liferay.portal.spring.annotation.PortalTransactionAnnotationParser" />
</constructor-arg>
</bean>
</property>
</bean>

Enabling Read-Write Database Splitting

1) Set up your database for master / slave replication. All major databases support at least a master / slave setup. See some sample instructions for the mysql database. Hint: Make sure you create a read-only user for the slave database so that no one can write directly to the slave.

2) Configure your app server / servlet container for each the master and slave databases. Sample ROOT.xml for Tomcat:

<Resource
name="jdbc/LiferayReadPool"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3308/lportal..."
username="read_only"
password="password"
maxActive="20"
/>


<Resource
name="jdbc/LiferayWritePool"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3307/lportal..."
username="root"
password="password"
maxActive="20"
/>

3) Set portal-ext.properties to enable the Spring configuration for dynamic data sources:

  spring.configs=\
META-INF/base-spring.xml,\
\
META-INF/hibernate-spring.xml,\
META-INF/infrastructure-spring.xml,\
META-INF/management-spring.xml,\
\
META-INF/util-spring.xml,\
\
META-INF/jcr-spring.xml,\
META-INF/messaging-spring.xml,\
META-INF/scheduler-spring.xml,\
META-INF/search-spring.xml,\
\
META-INF/counter-spring.xml,\
META-INF/documentlibrary-spring.xml,\
META-INF/lock-spring.xml,\
META-INF/mail-spring.xml,\
META-INF/portal-spring.xml,\
META-INF/portletcontainer-spring.xml,\
\
META-INF/mirage-spring.xml,\
\
META-INF/ext-spring.xml, \
META-INF/dynamic-data-source-spring.xml

You now have read-write data source setup. Over the next several months we'll post an update with some performance numbers on a read-write configured set up.  Enjoy :)

Showing 1 - 5 of 12 results.
Items: 5
Page: of 3