Guys !!! Checkout my new application. Just upload your error/log file and trace all the exceptions along with detailed output in various formats (like xml, text, json).

Want To Search Something Else? Just Google It !

Friday, June 22, 2012

Upgrading Liferay From 6.0 SP2 to 6.1.10 : Upgrade Procedure, Issues and Fixes

In this post, I will try to cover following:

1. Steps to upgrade Liferay 6.0 SP2 to 6.1.10.
2. Issues faced during the upgrade and their fixes. 

Upgrading Liferay can be divided into two steps:

1. Upgrading Plugins: 
    
    Upgrading plugins can be very easy  or complex process depending on 
    at what extend you have customized your existing liferay especially in 
    case of EXT plugins.  
    
    For regular plugins (e.g. portlets, themes, layout templates etc.) standard 
    way to upgrade is to port the source code to new Plugin SDK and try to 
    build it. Do necessary fixes and changes in order to make the build 
    successful. Once built, just deploy them to new liferay and test properly 
    to make sure everything works as expected.
    
    For EXT plugins, it's not that straight forward. Since liferay might have 
    enhanced/changes source code from it's previous version, there are 
    possibilities that your current EXT plugin may not function properly with
    new liferay version. Again, standard procedure to migrate EXT plugins 
    from one version of liferay to another version is to make sure your existing
    EXT source code is properly merged with corresponding sources files from 
    new version of Liferay, built successfully and deployed  and tested 
    thoroughly.

2. Upgrading Database Schema:

    The most critical part in upgrading Liferay is upgrading the database 
    schema. Liferay provides all the necessary upgrade scripts. We just 
    have to little bit of configuration (e.g. adding some properties into 
    portal-ext.properties file) and liferay will do the job for you. However,    
    these upgrade scripts are not 100% full-proof. They have couple of bugs
    which may or may not popup during the upgrade process based on your 

    data.


In following steps, I will try to explain how to upgrade from Liferay 6.0 SP2 Bundle with Tomcat  to Liferay 6.1.10 Bundle with Tomcat. 


1. Take a complete backup of existing system. 
    a. Existing Liferay setup (Backup entire liferay HOME directory which will 
        take care of all the things like tomcat, Data etc). 
    b. Existing database.

2. Download latest Liferay 6.1.10 bundle zip with Tomcat and expand it to   
    the location where  you would like to setup.

3. Shutdown Liferay 6.1.10 instance.

4. In the portal-ext.properties for 6.1.10, place the database settings that 

    point to the database used for 6 SP2.

5. Place any other settings from the previous 6 SP2 portal-ext.properties in 
    the 6.1.10 portal-ext.properties.
 

6. Copy old $LIFERAY_HOME/data/* folder in to new $LIFERAY_HOME/data/*
    folder.


7. Put following two entries into portal-ext.properties of Liferay 6.1.10.

        image.hook.impl=com.liferay.portal.image.FileSystemHook

        upgrade.processes=com.liferay.portal.upgrade.UpgradeProcess_6_0_12_

        to_6_1_0,com.liferay.portal.upgrade.UpgradeProcess_6_1_1

8. Start the application server for 6 SP2 and you'll see the upgrade logs.
    
9. When the portal starts up you will be notified that "This server is not    
    registered".
 

10. Drop license .xml file that you will drop into your hot deploy folder. In a 
     default bundle of Liferay, this hot deploy folder is located in 
     $LIFERAY_HOME/deploy.

11. After deploying the .xml file, refresh the browser and you will be taken to 
     the Welcome page. If you are replacing the old license file with new one 
     delete the old xml from $LIFERAY_HOME/data/ee folder, then deploy the 
     new license.
 

12. Re-index all the database indexes from Control Panel -> Server 
     Administration. 

13. Once the upgrade is done and everything looks fine, remove following 
     entry from portal-ext.properties of Liferay 6.1.10 and restart the server. 
     This is necessary to avoid running upgrade process again after the    
     upgrade is completed.

        upgrade.processes=com.liferay.portal.upgrade.UpgradeProcess_6_0_12_

        to_6_1_0,com.liferay.portal.upgrade.UpgradeProcess_6_1_1



Following are the issues which I have faced while doing LR 6.0 SP2 to LR 6.1.10 EE upgrade for couple of project which I worked upon. 



Issue#1

20:13:23,910 ERROR [MainServlet:201] com.liferay.portal.kernel.events.ActionException:
com.liferay.portal.kernel.upgrade.UpgradeException: com.liferay.portal.kernel.upgrade.UpgradeException:
java.sql.SQLException: Invalid object name 'IGFolder'.

com.liferay.portal.kernel.events.ActionException: com.liferay.portal.kernel.upgrade.UpgradeException:
com.liferay.portal.kernel.upgrade.UpgradeException: java.sql.SQLException: Invalid object name 'IGFolder'.

at com.liferay.portal.events.StartupAction.run(StartupAction.java:58)

at com.liferay.portal.servlet.MainServlet.processStartupEvents(MainServlet.java:1284)

at com.liferay.portal.servlet.MainServlet.init(MainServlet.java:198)

at javax.servlet.GenericServlet.init(GenericServlet.java:160)

at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1266)

at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1185)

at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1080)

at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5015)

at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5302)

at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)

at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:897)

at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:873)

at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:615)

at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:649)

at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1581)

at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)

at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)

at java.util.concurrent.FutureTask.run(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.lang.Thread.run(Unknown Source)

Caused by: com.liferay.portal.kernel.upgrade.UpgradeException:
com.liferay.portal.kernel.upgrade.UpgradeException: java.sql.SQLException: Invalid object name 'IGFolder'.

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:213)

at com.liferay.portal.upgrade.UpgradeProcessUtil._upgradeProcess(UpgradeProcessUtil.java:103)

at com.liferay.portal.upgrade.UpgradeProcessUtil.upgradeProcess(UpgradeProcessUtil.java:56)

at com.liferay.portal.upgrade.UpgradeProcessUtil.upgradeProcess(UpgradeProcessUtil.java:36)

at com.liferay.portal.events.StartupHelper.upgradeProcess(StartupHelper.java:81)

at com.liferay.portal.events.StartupHelperUtil.upgradeProcess(StartupHelperUtil.java:48)

at com.liferay.portal.tools.DBUpgrader.upgrade(DBUpgrader.java:119)

at com.liferay.portal.events.StartupAction.doRun(StartupAction.java:144)

at com.liferay.portal.ee.license.StartupAction.doRun(Unknown Source)

at com.liferay.portal.events.StartupAction.run(StartupAction.java:52)

... 20 more

Caused by: com.liferay.portal.kernel.upgrade.UpgradeException: java.sql.SQLException: Invalid object
name 'IGFolder'.

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:213)

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:227)

at
com.liferay.portal.upgrade.UpgradeProcess_6_0_12_to_6_1_0.doUpgrade(UpgradeProcess_6_0_12_to_6_1_0.java:56
)

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:210)

... 29 more

Caused by: java.sql.SQLException: Invalid object name 'IGFolder'.

at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:368)

at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2820)

at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2258)

at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:632)

at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQLQuery(JtdsStatement.java:477)

at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java:776)

at
com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)

at
com.liferay.portal.upgrade.v6_1_0.UpgradeImageGallery.updateIGFolderEntries(UpgradeImageGallery.java:463)

at com.liferay.portal.upgrade.v6_1_0.UpgradeImageGallery.doUpgrade(UpgradeImageGallery.java:245)

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:210)

... 32 more

 

Root Cause and Resolution:

The way upgrade code works in Liferay is, if once script fails, it will stop the upgrade process then and there. Following are steps taken to fix the issue.

1. After analyzing the above logs, it was found that issue is coming due to 

    missing/incomplete entries which are necessary for upgrading from Liferay 
    6SP2 to 6.1.10.
 

    Added following two entries into portal-ext.properties of Liferay 6.1.10.   
    (Missing entry is highlighted in bold face).

    upgrade.processes=com.liferay.portal.upgrade.UpgradeProcess_6_0_12_

    to_6_1_0,com.liferay.portal.upgrade.UpgradeProcess_6_1_1

     image.hook.impl=com.liferay.portal.image.FileSystemHook


 
Issue#2

Caused by: com.liferay.portal.kernel.upgrade.UpgradeException:
com.liferay.portal.kernel.upgrade.UpgradeException: java.sql.SQLException: Invalid column name
messageFlag.messageId.

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:213)

at com.liferay.portal.upgrade.UpgradeProcessUtil._upgradeProcess(UpgradeProcessUtil.java:103)

at com.liferay.portal.upgrade.UpgradeProcessUtil.upgradeProcess(UpgradeProcessUtil.java:56)

at com.liferay.portal.upgrade.UpgradeProcessUtil.upgradeProcess(UpgradeProcessUtil.java:36)

at com.liferay.portal.events.StartupHelper.upgradeProcess(StartupHelper.java:81)


at com.liferay.portal.events.StartupHelperUtil.upgradeProcess(StartupHelperUtil.java:48)

at com.liferay.portal.tools.DBUpgrader.upgrade(DBUpgrader.java:119)

at com.liferay.portal.events.StartupAction.doRun(StartupAction.java:144)

at com.liferay.portal.ee.license.StartupAction.doRun(Unknown Source)

at com.liferay.portal.events.StartupAction.run(StartupAction.java:52)

... 20 more

Caused by: com.liferay.portal.kernel.upgrade.UpgradeException: java.sql.SQLException: Invalid column name
messageFlag.messageId.

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:213)

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:227)

at
com.liferay.portal.upgrade.UpgradeProcess_6_0_12_to_6_1_0.doUpgrade(UpgradeProcess_6_0_12_to_6_1_0.java:59
)

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:210)

... 29 more

Caused by: java.sql.SQLException: Invalid column name messageFlag.messageId.

at net.sourceforge.jtds.jdbc.JtdsResultSet.findColumn(JtdsResultSet.java:964)

at net.sourceforge.jtds.jdbc.JtdsResultSet.getLong(JtdsResultSet.java:972)

at com.mchange.v2.c3p0.impl.NewProxyResultSet.getLong(NewProxyResultSet.java:2625)

at
com.liferay.portal.upgrade.v6_0_12_to_6_1_0.UpgradeMessageBoards.updateMessage(UpgradeMessageBoards.jav
a:88)

at
com.liferay.portal.upgrade.v6_0_12_to_6_1_0.UpgradeMessageBoards.doUpgrade(UpgradeMessageBoards.java:61
)

at com.liferay.portal.kernel.upgrade.UpgradeProcess.upgrade(UpgradeProcess.java:210)

... 32 more

 


Root Cause and Resolution: 


After analyzing the above logs, it was found that issue is coming
com.liferay.portal.upgrade.v6_0_12_to_6_1_0.UpgradeMessageBoards.java file
on Line no 88.


Following changes were made to above file.

protected void updateMessage() throws Exception {
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            con = DataAccess.getConnection();

            StringBundler sb = new StringBundler(4);

            sb.append("select messageFlag.messageId from MBMessageFlag ");
            sb.append("messageFlag inner join MBMessage message on ");
            sb.append("messageFlag.messageId = message.messageId where ");
            sb.append("message.parentMessageId != 0 and flag = 3");

            String sql = sb.toString();

            ps = con.prepareStatement(sql);

            rs = ps.executeQuery();

            while (rs.next()) {
              
//long messageId = rs.getLong("messageFlag.messageId");
    
//Changed above line to following since table alias cannot be //used to
//retrieve columns from ResultSets. That’s incorrect syntax.

long messageId = rs.getLong(“messageId ");

                updateMessageAnswer(messageId, true);
            }
        }
        finally {
            DataAccess.cleanUp(con, ps, rs);
        }
    }



Once Changes are done, copy the compiled version of the file (.class file) in 
to tomcat/webapps/ROOT/WEB-INF/classes directory under respective 
package.

1. In above case UpgradeMessageBoards.java is under
    com.liferay.portal.upgrade.v6_0_12_to_6_1_0 package. So it needs to be
    copied in tomcat/webapps/ROOT/WEBINF/classes/com/liferay/portal
    /upgrade/v6_0_12_to_6_1_0/UpgradeMessageBoards.class

2. Run the upgrade process again. 





Issue# 3

This issue is same as Issue# 2 but it’s coming because of similar error at another location in the same java file: UpgradeMessageBoards.java

Resolution:
 

Modify UpgradeMessageBoards.java as following and re-run the upgrade
procedure after replacing the new class file as described in Issue# 2.

protected void updateThread() throws Exception {
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            con = DataAccess.getConnection();

            ps = con.prepareStatement(
                "select threadId from MBMessageFlag where flag = 2");

            rs = ps.executeQuery();

            while (rs.next()) {
                long threadId = rs.getLong("threadId");

                updateThreadQuestion(threadId, true);
            }

            StringBundler sb = new StringBundler(4);

            sb.append("select messageFlag.threadId from MBMessageFlag ");
            sb.append("messageFlag inner join MBMessage message on ");
            sb.append("messageFlag.messageId = message.messageId where ");
            sb.append("message.parentMessageId = 0 and flag = 3");

            ps = con.prepareStatement(sb.toString());





            rs = ps.executeQuery();

            while (rs.next()) {
               //long threadId = rs.getLong("messageFlag. threadId ");
    
               //Changed above line to following since table alias cannot be      

               //used to retrieve columns from ResultSets. That’s incorrect syntax.
                
                long messageId = rs.getLong(“threadId ");
                updateThreadQuestion(threadId, true);
            }
        }
        finally {
            DataAccess.cleanUp(con, ps, rs);
        }
    }







Issue# 4

20:55:28,056 ERROR [NtlmPostFilter:79] com.liferay.portal.kernel.exception.SystemException:
com.ctc.wstx.exc.WstxEOFException: Unexpected end of input block in entity reference

at [row,col {unknown-source}]: [1,3995]

com.liferay.portal.kernel.exception.SystemException: com.ctc.wstx.exc.WstxEOFException: Unexpected end of
input block in entity reference

at [row,col {unknown-source}]: [1,3995]

at
com.liferay.portlet.PortletPreferencesFactoryImpl.populateMap(PortletPreferencesFactoryImpl.java:584)

at com.liferay.portlet.PortletPreferencesFactoryImpl.fromXML(PortletPreferencesFactoryImpl.java:115)

at com.liferay.portlet.PortletPreferencesFactoryImpl.fromXML(PortletPreferencesFactoryImpl.java:1)

at com.liferay.portlet.PortletPreferencesFactoryUtil.fromXML(PortletPreferencesFactoryUtil.java:56)

at
com.liferay.portal.service.impl.PortalPreferencesLocalServiceImpl.doGetPreferences(PortalPreferencesLocalServi
ceImpl.java:199)

at
com.liferay.portal.service.impl.PortalPreferencesLocalServiceImpl.getPreferences(PortalPreferencesLocalServiceI
mpl.java:105)

at
com.liferay.portal.service.impl.PortalPreferencesLocalServiceImpl.getPreferences(PortalPreferencesLocalServiceI



mpl.java:92)

at sun.reflect.GeneratedMethodAccessor607.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at
com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:112)

at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:71)

at
com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:108)

at com.liferay.portal.spring.aop.ServiceBeanAopProxy.invoke(ServiceBeanAopProxy.java:211)

at $Proxy64.getPreferences(Unknown Source)

at
com.liferay.portal.service.PortalPreferencesLocalServiceUtil.getPreferences(PortalPreferencesLocalServiceUtil.jav
a:276)

at com.liferay.portal.util.PrefsPropsUtil.getPreferences(PrefsPropsUtil.java:262)

at com.liferay.portal.util.PrefsPropsUtil.getBoolean(PrefsPropsUtil.java:52)

at com.liferay.portal.security.auth.AuthSettingsUtil.isNtlmEnabled(AuthSettingsUtil.java:44)

at com.liferay.portal.servlet.filters.sso.ntlm.NtlmPostFilter.processFilter(NtlmPostFilter.java:54)

at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:55)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:206)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:108)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)

at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:158)

at com.liferay.portal.sharepoint.SharepointFilter.processFilter(SharepointFilter.java:80)

at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:55)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:206)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:108)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)



at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDirectCallFilter(InvokerFilterChain.java
:187)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:95)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)

at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:738)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:206)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:108)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDirectCallFilter(InvokerFilterChain.java
:167)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:95)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDirectCallFilter(InvokerFilterChain.java
:167)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:95)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:116)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDirectCallFilter(InvokerFilterChain.java
:187)

at
com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:95)

at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilter.doFilter(InvokerFilter.java:71)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)



at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)

at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)

at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)

at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)

at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)

at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

at java.lang.Thread.run(Thread.java:619)

Caused by: com.ctc.wstx.exc.WstxEOFException: Unexpected end of input block in entity reference

at [row,col {unknown-source}]: [1,3995]

at com.ctc.wstx.sr.StreamScanner.throwUnexpectedEOB(StreamScanner.java:675)

at com.ctc.wstx.sr.StreamScanner.loadMoreFromCurrent(StreamScanner.java:1029)

at com.ctc.wstx.sr.StreamScanner.getNextCharFromCurrent(StreamScanner.java:786)

at com.ctc.wstx.sr.StreamScanner.fullyResolveEntity(StreamScanner.java:1464)

at com.ctc.wstx.sr.BasicStreamReader.readTextSecondary(BasicStreamReader.java:4679)

at com.ctc.wstx.sr.BasicStreamReader.readCoalescedText(BasicStreamReader.java:4124)

at com.ctc.wstx.sr.BasicStreamReader.finishToken(BasicStreamReader.java:3699)

at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1023)

at com.ctc.wstx.evt.WstxEventReader.peek(WstxEventReader.java:306)

at com.liferay.portal.xml.StAXReaderUtil.read(StAXReaderUtil.java:37)

at
com.liferay.portlet.PortletPreferencesFactoryImpl.readPreference(PortletPreferencesFactoryImpl.java:616)

at
com.liferay.portlet.PortletPreferencesFactoryImpl.populateMap(PortletPreferencesFactoryImpl.java:576)

... 64 more




Root Cause and Resolution:


After analyzing the above logs, it was found that issue is coming
com.liferay.portl.dao.orm.common.SQLTransformer.java file on Line no 215.

The reason for the error is as following:


During upgrade process, Liferay tries to upgrade the value in PortalPreferences
table to update the data according to Liferay 6.1.10.

Com.liferay.portal.upgrade.v6_1_0.UpgradeCommunityProperties.java file does
this work by generating an Generic Update Query for each an every record of
PortalPreferences table.

The generic query generated above gets passed through SQLTransformer.java
class further down the process to create actual SQL query using database specific syntax and run it.

Now Here is the issue:

The datatype of the preferences column in PortalPreferences table is NTEXT
into database (SQLServer incase of Guardian). But, SQLTransformer.java tries
to CAST the value to NVARCHAR2(4000) in the generated update query (look
through line number:214-216 which are following:

else if(_vendorQLServer) {
return matcher.replaceAll(“CAST($1 AS NVARCHAR(4000))”);
}

This is putting a limit on the length of the values in preference column of
PortalPreferences table and those records which has preference value > 4000
characters gets truncated.

This causes the preferences value (which are stored in xml format) to be mal-
formed. Hence when the portal starts, it tries to read and parse these mal-formed preferences values and throws the exception.

Solution to above problems is as following:

else if(_vendorQLServer) {
//return matcher.replaceAll(“CAST($1 AS NVARCHAR(4000))”);
//Changed above line to following. MAX is the maximum limit of
//NVARCHAR datatype which incase of SQLServer 2008 is is 2^31-1
bytes
//(2 GB). 



Once Changes are done, copy the compiled version of the file (.class file) in 
to tomcat/webapps/ROOT/WEB-INF/classes directory under respective 
package.

1. In above case SQLTransformer.java is under com.liferay.portal.dao.
   orm.common package. So it needs to be copied in tomcat/webapps
   /ROOT/WEB-INF/classes/com/liferay/portal/dao/orm/common/
   SQLTransformer.class

2. Run the upgrade process again. 



Hope this article is  helpful to you. If you face any other issues which is not listed above while doing an upgrade, do let me know at jignesh.shukla@gmail.com and I would love to help you resolving the issue. 
 

 

Tuesday, April 10, 2012

Integrating Alfresco with Liferay 6.1



Hello Friends.  It's been a long I am posting to my blog. In my previous post Liferay Alfresco Integration , I explained how to integrate Liferay 6 (CE or EE) with Alfresco 3.3(or higher).  Both the integration methods explained in the post have their own advantages and limitations (which also I have mentioned in the post). The CMISHook was being used as a means to store Liferay's document library's low-level data.  This had two limitations: (1) It was showing up all these low lever information numbers in the CMIS Repository system which are not of any use from the user perspective and (2) If we change anything in that repository, it would screw up Liferay because things were not synchronized.


With the latest version (Liferay 6.1), Liferay has come up with some really cool features which makes it very easy to integrate Liferay with alfresco and many other CMS systems (like sharepoint, documentum etc). It eliminates all the limitations of CMIS Hook as well as it let's us mount multiple repositories to one document. 


Following are the steps to configure Liferay 6.1 (with tomcat bundle) with Alfresco 3.4d. 



1. Download Alfresco(Community or Enterprise edition) and follow the installation instructions. You can download it from following URLs:

Community Edition: http://wiki.alfresco.com/wiki/Download_Community_Edition
Enterprise Edition: http://www.alfresco.com/try/    (30-Days trial version)

You can install it with an inbuilt tomcat and mysql bundle or you can install it on any existing application server and connect it to existing mysql database. I have done it with inbuilt tomcat bundle and connected to my existing mysql database. The installation wizard let's you configure all these stuff.

2. Download and install Liferay 6.1 (EE or CE). You can download it from http://www.liferay.com/downloads/liferay-portal/available-releases

3. Start Alfresco. 

4.  Liferay passes user credentials through CMIS to the alfresco in order to connect. To enable liferay to do so, we need to enter following property in portal-ext.properties which will allow liferay to store password in session. 

session.store.password=true 


4. Also one more thing we need to take into consideration is that: Liferay passes logged in user's credentials to CMIS Repository (alfresco here) as described in step 4. What this means is that userid/password in liferay must match userid/password in Alfresco. Alfresco by default uses a loginid (which is similar to screen-name in liferay) to authenticate user. So we need to make liferay also authenticate using screen name by making following entry into portal-ext.properties.

company.security.auth.type=screenName

5. Now we are good to move ahead. Let's start Liferay. 

6. Login as administrator and go to control panel. 

7. Click on Document and Media which will bring up a screen similar to following:

Liferay 6.1 Document Library
7. Click on Add -> New Repository as shown in following image. 

8. This will bring up following screen where you basically provide connection details to connect to Alfresco. 




9. Specify following details:

Name: Give any name you want to give to your repository view in liferay. For example, I will give Alfresco

Description: A brief description about it. 

Repository Type: You can connect either using AtomPub or using web services. For this example, I will use AtomPub. 

AtomPub URL: This will be the CMIS repository URL where you alfresco is running. In my case, it's http://localhost:8080/alfresco/service/api/cmis (Note: In case of Alfresco 4.0, it will be http://host:port/alfresco/cmisatom) 

Repository ID: It is not required field.  It is basically used to connect to a specific repository incase we have multiple repositories available. If we do not enter a repositoryId, then it will just look for the first repository using the given parameters and set it to that.

10. Click on Save button. Liferay will try connecting to Alfresco using information we just provided in step 9 and will show success or failure message.  If it's failure, just make sure that the connectivity information we have provided in step 9 is correct. 

11. On successful connection, you will be able to see a folder view of your Alfresco in your Liferay's document and media as following. 



Now, you will be able to upload your documents from Liferay to Alfresco by simply uploading to this folder. This is synchronized completely. It means that if you upload any document from Liferay, you will be able to see the same from Alfresco's web portal. If you delete any document from alfresco's using it's web portal, it will reflect the changes in liferay's document and media section.  Isn't it cool ?

That's it for this post. Next, I'll try to connect alfresco using web services or may be share point with liferay. 


Feel free to provide any comments/suggestions/enhancements. 

Sunday, October 2, 2011

Opening Portlet with Maximized Window in Render Mode

There is no provision in portlet API for opening a portlet with maximized window in render mode (doView() method). When a portlet gets loaded into browser for the first time, it always opens up in normal window.

I happened to come across a scenario where I had to open-up portlet in a maximized window which I achieved in following way:

javax.portlet.PortletURL object allows to set Window State. We can utilize this facility in following way to open a portlet with maximized window in render (doView() method) mode.

1. In doView method, Generate a render URL from renderResponse.
2. Add all the request parameters from renderRequest to these new URL.
3. Set window state to Maximized on this new URL.
4. Set this new URL value as renderRequest attribute and pass the control to view.jsp (your jsp file which generates output in render mode).
5. In view.jsp, retreive the URL we created in step-1 and redirect the page to this new URL using javascript by setting location.href value.

That's it. Next time, when the portlet will be rendered, it will open up in Maximized mode.

Following is the piece of code for both doView() method of Portlet class and view.jsp.

In Portlet Class,

public void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException
    {
      
        if(renderRequest.getWindowState() != WindowState.MAXIMIZED)
        {
            //Create a render URL
            PortletURL url = renderResponse.createRenderURL();
          
            //Pass all the parameters from existing request to this new URL
            Enumeration params = renderRequest.getParameterNames();
          
            while(params.hasMoreElements())
            {
                String pname = params.nextElement().toString();
                url.setParameter(pname, renderRequest.getParameter(pname));
            }
          
            //Set window state to Maximized on newly created URL
            url.setWindowState(WindowState.MAXIMIZED);
          
            //Set this URL as attribute in renderRequerst
            renderRequest.setAttribute("maximizedUrl", url.toString());
          
          
            renderRequest.setAttribute("isMaximized", "false");
          
        }
        include(viewJSP, renderRequest, renderResponse);
    }
   

protected void include(String path, RenderRequest renderRequest,RenderResponse renderResponse) throws IOException, PortletException
{
            PortletRequestDispatcher portletRequestDispatcher =
                                               getPortletContext().getRequestDispatcher(path);
            if (portletRequestDispatcher == null)
            {
                Logger.error(path + " is not a valid include");
            }
            else
            {
                portletRequestDispatcher.include(renderRequest, renderResponse);
            }
}


In view.jsp,

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>

<jsp:useBean class="java.lang.String" id="maximizedUrl"
    scope="request" />
<jsp:useBean class="java.lang.String" id="isMaximized"
    scope="request" />

<portlet:defineObjects />


<script type="text/javascript">
    var maximizedFlag = '<%=isMaximized%>';
   
    //Redirect to New Render URL only if current window is not in maximized state
    if(maximizedFlag=='false')
    {
        location.href='<%=maximizedUrl%>';  
    }
</script>

 

Wednesday, September 28, 2011

Liferay Alfresco Integration

With the time, Liferay and Alfresco have matured in terms of capabilities, both the products have their own focal point in terms of offerings. Where liferay's main focus is collaboration features, Alfresco is better in document management and record management.  With this said, there are many scenarios where need rises to integrate both the systems in order to provide better software solutions and architectures.  

There are multiple ways we can integrate alfresco with liferay. I will explain two of them which I have used along with benefits/drawbacks which I know. 

Method-1. Integrating Alfresco with Liferay using CMIS 1.0

Content Management Interoperability Services (CMIS) - is a standard protocol which consists a set of web services for sharing information among different content management systems to provide interoperability and integration for people and applications using multiple content repositories.

Liferay 6 and Alfresco 3.3 both provides CMIS support. Here I will explain how to integrate Alfresco 3.3 (or higher) with Liferay 6 (Tomcat Bundle). 

1. Download Alfresco(Community or Enterprise edition) share.war and alfresco.war (version 3.3 or higher). You can download it from following URLs.

Community Edition: http://wiki.alfresco.com/wiki/Download_Community_Edition
Enterprise Edition: http://www.alfresco.com/try/    (30-Days trial version)

2. Download and install Liferay 6 (EE or CE). ou can download it from http://www.liferay.com/downloads/liferay-portal/available-releases

3. Copy alfresco.war and share.war from $ALFRESCO_HOME/tomcat/webapps to  $LIFERAY_HOME/tomcat/webapps.

4. Create a database alfresco in MySQL. (Assuming you are using MySQL database)
drop database if exists alfresco;
create database alfresco character set utf8;
grant all on alfresco.* to 'alfresco'@'localhost' identified by 'alfresco' with grant option;
grant all on alfresco.* to 'alfresco'@'localhost.localdomain' identified by 'alfresco' with grant option;


5. Create a database lportal in MySQL. (Assuming you are using MySQL database)
drop database if exists lportal;
create database lportal character set utf8;
grant all on lportal.* to 'lportal'@'localhost' identified by 'lportal' with grant option;
grant all on lportal.* to 'lportal'@'localhost.localdomain' identified by 'lportal' with grant option;


6. Create a file named portal-ext.properties at $LIFERAY_HOME/tomcat/webapps/ROOT/WEB-INF/classes and add following lines in portal-ext.properties.
dl.hook.impl=com.liferay.documentlibrary.util.CMISHook
cmis.credentials.username=admin
cmis.credentials.password=admin
cmis.repository.url=http://localhost:8080/alfresco/service/api/cmis (NOTE: This URL will be the URL where you alfresco is running. Change the value accordingly)
cmis.repository.version=1.0
cmis.system.root.dir=Liferay Home

7. Add Database entry in portal-ext.properties (Assuming you are using MySQL database)

             ## MySQL
             jdbc.default.driverClassName=com.mysql.jdbc.Driver
             jdbc.default.url=jdbc:mysql://localhost:3306/lportal?useUnicode=true&characterEncoding=UTF- 
            8&useFastDateParsing=false (Change according to your DB settings)
            jdbc.default.username=lportal (Change according to your DB settings)
            jdbc.default.password=lportal (Change according to your DB settings)


8. That's it. Start Liferay and you are through. Whatever documents you create from Liferay Document Library will directly get stored into Alfresco. 


Advantages:

This integration method enables us to run both liferay and alfresco independently from each other and still have a nice level of integration for document management.  

Disadvantages:

a. When any document is created/uploaded in liferay document library it stores document meta-data in liferay data store and actual document in Alfresco. 

So if you store any document directly from Alfresco, it doesn't get reflected in Liferay document library. 

b. Alfresco maps the document hierarchy with it's own numeric notations: For example, if a document named MyInfo.pdf is stored under Document Library -> My Docs -> Personal Info -> MyInfo.pdf in liferay, alfresco maps it similar to following: 

Liferay Home -> 10232(this is liferay instance id) -> 10280 (this is liferay folder id) - > 1 (numerically named folder created for each document uploaded from Liferay) ->1 (Actual document named as 1)

This mapping notation makes it very difficult to track the documents directly from Alfresco.  Also since the meta-data information is stored in liferay, when we try to open document directly from alfresco, it fails. 

c. When we delete any document from liferay, it only deletes the meta-data information. The actual document remains stored in alfresco. 


Method-2. Integrating Alfresco Web Client as portlet in Liferay

This method deploys alfersco.war (web client) as portlet in liferay.  Following are the stes to achieve this:


1. Download Alfresco(Community or Enterprise edition)  alfresco.war (version 3.3 or higher). You can download it from following URLs.

Community Edition: http://wiki.alfresco.com/wiki/Download_Community_Edition
Enterprise Edition: http://www.alfresco.com/try/    (30-Days trial version)

2. Download and install Liferay 6 (EE or CE). ou can download it from http://www.liferay.com/downloads/liferay-portal/available-releases

3. Extract(Unzip) alfresco.war to any directory of your choice.

4. Update dir.root in $ALFRESCO_HOME/ WEB-INF/classes/alfresco/repository.propertes.
      
     dir.root=../../alf_data

5. Create a database alfresco in MySQL. (Assuming you are using MySQL database)

drop database if exists alfresco;
create database alfresco character set utf8;
grant all on alfresco.* to 'alfresco'@'localhost' identified by 'alfresco' with grant option;
grant all on alfresco.* to 'alfresco'@'localhost.localdomain' identified by 'alfresco' with grant option;

6. Remove the file from WEB-INF/lib/portlet-api-lib.jar 

7.  Add /WEB-INF/faces-config.xml to the faces config files list at $ALFRESCO_HOME/WEB-INF/web.xml like
     <context-param>
      <param-name>javax.faces.CONFIG_FILES</param-name>
      <param-value>/WEB-INF/faces-config.xml,/WEB-INF/faces-config-app.xml,/WEB-INF/faces-config-beans.xml,/WEB-INF/faces-config-navigation.xml,/WEB-INF/faces-config-common.xml,/WEB-INF/faces-config-repo.xml,/WEB-INF/faces-config-wcm.xml,/WEB-INF/faces-config-custom.xml</param-value>
</context-param>

8. Download and add files: faces-config.xml, liferay-display.xml, liferay-portlet.xml, portlet.xml to WEB-INF. You can
      download these files from http://liferay.cignex.com/palm_tree/0387/sso/liferay/alfresco-portlet/

9. Package all files as a WAR: alfresco.war and copy it to $LIFERAY_HOME/deploy folder.

10. Start Liferay and you are through. All the alfresco portlets will be available under Alfresco category from the Add dropdown menu. 

Advantages:



This method lets you run alfresco web client directly as portlet under liferay and removes complexity of maintaining two separate systems.   


Disadvantages:

We have to manually edit the source files of alfresco.war. 


Feel free to provide any comments/suggestions/enhancements.