Multiple files upload in Liferay 6.1

Today I have found a weird bug in Liferay’s UploadServletRequestImpl in the following method

	public String getFullFileName(String name) {
		FileItem[] liferayFileItems = _fileParams.get(name);

		if ((liferayFileItems != null) && (liferayFileItems.length > 0)) {
			FileItem liferayFileItem = liferayFileItems[0];

			return liferayFileItem.getFullFileName();
		}

		return null;
	}

The intention of the above code is to return the full name of the file(s) being uploaded. But actually the above code returns the name of the first file uploaded on the form with the name field.

But what if I have multiple files uploads on my form with the same name like this

<portlet:actionURL var="uploadFileUrl" name="uploadFileAction" />

<form action="${uploadFileUrl}" method="POST" enctype="multipart/form-data">
<input name="supportingDoc" type="file"/>
<input name="supportingDoc" type="file"/>

<button type="submit" class="aca-bt finish-bt" value="Submit">Submit</button>
</form>

If you upload two files on the above form the following code will always print name of the first file

UploadPortletRequest uploadPortletRequest = PortalUtil.getUploadPortletRequest(request);
System.out.println(uploadPortletRequest.getFullFileName("supportingDoc"));

Workaround

You can use uploadPortletRequest.getMultipartParameterMap() to get all the multipart parameters for a parameter name. The following code will print the name of all the files

        UploadPortletRequest uploadPortletRequest = PortalUtil.getUploadPortletRequest(request);

        //Following code will always print the name of the first file uploaded
        System.out.println(uploadPortletRequest.getFullFileName("supportingDoc"));

        //Following code will iterate through all the files and print their names
        for(FileItem fileItem:uploadPortletRequest.getMultipartParameterMap().get("supportingDoc")){
            System.out.println(fileItem.getFullFileName());
        }

JournalVmUtil in Liferay 6.1

Tags

, ,

Disclaimer – Following is not the best or optimal solution. If you have better suggestion please write in comments

JournalVmUtil was present upto Liferay 5.2 and then deprecated in Liferay 6.0 and then completed removed in Liferay 6.1. If you are upgrading to 6.1 and make extensive use of JournalVmUtil you can do the following.

Extend VelocityTemplateParser.java. Following code example is just a sample. Feel free to add any pre-processing or post-processing as required

package com.myexamples.mypackage;

import com.liferay.portal.kernel.templateparser.TemplateNode;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portlet.journal.util.VelocityTemplateParser;

import java.util.List;

/**
 * @author parasjain
 */
public class MyVelocityTemplateParserImpl extends VelocityTemplateParser{
    public List getNodes(Element element) throws Exception {
        return getTemplateNodes(element);
    }
}

Now inject MyVelocityTemplateParserImpl in your velocity templates and just call getNodes method like this

#set( $articleTemplateNodes = $myVelocityTemplateParser.getNodes($articleXmlDocument.getRootElement()) )

No theme found for specified theme id abc_WAR_xyztheme

Tags

As far as my experience is concerned, this error means that your database is referring to theme which is not present. To make sure run the following commands

select distinct themeid from layout;
select distinct themeid from layoutset;

Now go to liferay’s Control Panel -> Plugin Configuration -> Theme Plugins tab and click on the theme in question. See the
Plugin ID of the theme. It should match what is there in layout and layoutset tables. If it doesn’t then you have to either change themeid or update database tables. If you happen to update DB don’t forget to restart or clear DB cache.

Changing Liferay Password in database

Tags

Note : Use caution while trying this for the production installation. For production, it’s better to use technics like “Forgot Password”

If you forget password for your local admin account in Liferay, then stop the server and run the following command

update user_ set passwordEncrypted=0, password_='mynewpassword', passwordReset=1 where userId=10196;

 

Where mynewpassword is your new password. Now restart the server. This time you should be able to login with your new password. As soon as you login, Liferay should prompt you for password change. Change your password and try to remember it this time ;)

How to set lower_case_table_names in MAMP

Environment – Mac OS X
I have struggled a little to set lower_case_table_names =2 for mysql using MAMP. I have unsuccessfully tried configuring /etc/my.cnf and ~/.my.cnf. Finally (with a little help) I found that they are setting this value in MAMP/bin/startMysql.sh . Location of this file might differ because in your version of MAMP.
My config file looks like this

# /bin/sh
/Applications/MAMP/Library/bin/mysqld_safe --port=3306 --socket=/Applications/MAMP/tmp/mysql/mysql.sock --lower_case_table_names=2 --pid-file=/Applications/MAMP/tmp/mysql/mysql.pid --log-error=/Applications/MAMP/logs/mysql_error_log &amp;

Change this file to set it to required value. As you might have guessed, you can use the same approach to update other params like log-error location, or port number (port number can be changed from MAMP preferences too)

Luke – Incompatible format version: 2 expected 1 or lower

Tags

, ,

I was trying to analyze my Lucene index generated by Nutch and I was getting this error when I selected Lucene index directory

Incompatible format version: 2 expected 1 or lower
And on the console it had

org.apache.lucene.index.CorruptIndexException

I got away with this using latest Luke Jar (luke-all-1.0.1). You can download it from
http://code.google.com/p/luke/downloads/detail?name=lukeall-1.0.1.jar

generate-all No domain class found for.. error in grails

Tags

, ,

Short Story: Provide fully qualified domain class name(class name with the package) to the generate-all command

Long Story:

If you have recently moved from pre-1.3 to latest grails version(1.3.2 as of today) and suddenly you have started getting this error

No domain class found for name Book. Please try again and enter a valid domain class name

on generate-all command


grails generate-all Book

then don’t panic. As of grails-1.3.2, when you create a new domain class, it is generated in a package. For example, in my case my Book.groovy is generated under mylib package(mylib is the name of my application)

generate-all command requires you provide fully qualified class names. This is true for even older versions like 1.1.1.

Issue this command instead


grails generate-all mylib.Book

I wish they made this point clear in their documentation at http://grails.org/doc/latest/ref/Command%20Line/generate-all.html

Exact Target Client in Java

Tags

, , , , ,

Disclaimer – Most of the code in this post are from the code samples provided by Exact Target. I have encountered little difficulties in using the code samples. Therefore I am writing this post to document how I made it work finally. Hope it helps.

Recently, We have implemented Grails/Java client for Exact Target .net webservices. We have use Axis 1.4 to generate the exact target client. ET provides very good samples and examples. Our implementation was derived from one of the sample project they have provided.

Important Note: Exact Target has released new version of webservices recently. If that is the case then this post may not be of much help. This post is based on the following environment. If your environment is different then YMMV.

Java 5+, Axis 1.4, Exact Target Partner API 1.0, Apache Ant

These are the steps we have followed

i) Create a new java project and have the structure similar to this

Few files to take note of.

  • build.xml
  • etframework.wsdl
  • Code generated by wsdl2java will be in src/com.exacttarget.wsdl.partnerapi package
  • com.exacttarget.samples.Axisv14.client.ClientTest is used to test the client and com.exacttarget.samples.Axisv14.client.PWCBHandler is the implementation of Password Callback Handler
  • jars in the lib folder . These jars may be required to make things work.
  • client_deploy.wsdd is used by the framework
  • Generated client jar will be put in dist/lib/ folder
  • Folder build/com will have the compiled classes.

Normal java project stuff. Shouldn’t be new to you!

Now let’s get our hands dirty

ii) Open the PWCBHandler.java and update your api username and password


/*
 * Copyright 2004,2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.exacttarget.samples.Axisv14.client;

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

/**
 * Modified WSS4J callback handler to accept user and password information from properties file via ClientTest.
 * The original class from Apache required hard-coded values for this information. This class may be further
 * modified for production usage so that this information is fetched from any external store, such as a database.
 *
 * @author Erik Gfesser
 */
public class PWCBHandler implements CallbackHandler {
 public static String user = "myusername";
 public static String password = "mypassword";

 public void handle(Callback[] callbacks) throws IOException,
 UnsupportedCallbackException {

 for (int i = 0; i < callbacks.length; i++) {
 if (callbacks[i] instanceof WSPasswordCallback) {
 WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
 String id = pwcb.getIdentifer();
 if(user.equals(id)) {
 pwcb.setPassword(password);
 }
 } else {
 throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
 }
 }
 } //end method handle
} //end class PWCBHandler

For your reference here is how client_deploy.wsdd looks like

<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/>
<globalConfiguration>
 <requestFlow>
 <handler type="java:org.apache.ws.axis.security.WSDoAllSender">
 <parameter name="action" value="UsernameToken"/>
 <parameter name="user" value="myuserid"/>
 <parameter name="passwordCallbackClass" value="com.exacttarget.samples.Axisv14.client.PWCBHandler"/>
 <parameter name="passwordType" value="PasswordText"/>
 </handler>
 </requestFlow>
</globalConfiguration>
</deployment>

And last but not the least, here is the build.xml

<project basedir=".">
 <property name="build.dir" value="build"/>
 <property name="lib.dir" value="lib"/>
 <property name="resources.dir" value="resources"/>
 <property name="src.dir" value="src"/>
 <property name="dist.dir" value="dist"/>

 <path id="axis.jaf.javamail.wss4j.xmlsec.xerces.lib.classpath">
 <fileset dir="${lib.dir}">
 <include name="*.jar"/>
 </fileset>
 </path>

 <path id="client.lib.classpath">
 <fileset dir="${dist.dir}/lib" >
 <include name="*.jar" />
 </fileset>
 </path>

 <target name="init">
 <mkdir dir="${build.dir}"/>
 <mkdir dir="${dist.dir}/lib"/>
 </target>

 <target name="generate.client" depends="init">
 <taskdef resource="axis-tasks.properties"
 classpathref="axis.jaf.javamail.wss4j.xmlsec.xerces.lib.classpath"/>
 <axis-wsdl2java url="${resources.dir}/META-INF/etframework.wsdl"
 output="${src.dir}"
 verbose="false"
 debug="false">
 <mapping namespace="http://exacttarget.com/wsdl/partnerAPI"
 package="com.exacttarget.wsdl.partnerapi" />
 </axis-wsdl2java>
 </target>

 <target name="compile.client">
 <javac destdir="${build.dir}"
 debug="true"
 failonerror="true">
 <src path="${src.dir}"/>
 <classpath refid="axis.jaf.javamail.wss4j.xmlsec.xerces.lib.classpath"/>
 </javac>
 <jar destfile="${dist.dir}/lib/mysample-exacttarget-client-1.0.jar"
 basedir="${build.dir}/">
 </jar>
 </target>

 <target name="generate.compile.client" depends="generate.client,compile.client"/>

 <target name="clean">
 <delete dir="${build.dir}"/>
 </target>
</project>

iii) Run ant generate.client to generate the client classes. This target uses wsdl2java to generate java code from wsdl. After
this target is successfully run you should see java classes under com.exacttarget.wsdl.partnerapi package

iii) Now you should try to test the generated client. We will make use of ClientTest.java for the same. Here is a part of ClientTest.java
I have. Again the basic templated was given by ET itself

package com.exacttarget.samples.Axisv14.client;

import java.io.FileInputStream;
import java.rmi.RemoteException;
import java.util.Properties;

import javax.xml.rpc.ServiceException;

import org.apache.axis.EngineConfiguration;
import org.apache.axis.configuration.FileProvider;

import com.exacttarget.wsdl.partnerapi.APIObject;
import com.exacttarget.wsdl.partnerapi.Attribute;
import com.exacttarget.wsdl.partnerapi.CreateOptions;
import com.exacttarget.wsdl.partnerapi.CreateRequest;
import com.exacttarget.wsdl.partnerapi.CreateResponse;
import com.exacttarget.wsdl.partnerapi.CreateResult;
import com.exacttarget.wsdl.partnerapi.DefinitionRequestMsg;
import com.exacttarget.wsdl.partnerapi.DefinitionResponseMsg;
import com.exacttarget.wsdl.partnerapi.Email;
import com.exacttarget.wsdl.partnerapi.List;
import com.exacttarget.wsdl.partnerapi.ListSubscriber;
import com.exacttarget.wsdl.partnerapi.ObjectDefinition;
import com.exacttarget.wsdl.partnerapi.ObjectDefinitionRequest;
import com.exacttarget.wsdl.partnerapi.Owner;
import com.exacttarget.wsdl.partnerapi.PartnerAPI;
import com.exacttarget.wsdl.partnerapi.PartnerAPILocator;
import com.exacttarget.wsdl.partnerapi.RetrieveRequest;
import com.exacttarget.wsdl.partnerapi.RetrieveRequestMsg;
import com.exacttarget.wsdl.partnerapi.RetrieveResponseMsg;
import com.exacttarget.wsdl.partnerapi.Send;
import com.exacttarget.wsdl.partnerapi.SimpleFilterPart;
import com.exacttarget.wsdl.partnerapi.SimpleOperators;
import com.exacttarget.wsdl.partnerapi.Soap;
import com.exacttarget.wsdl.partnerapi.Subscriber;
import com.exacttarget.wsdl.partnerapi.TriggeredSend;
import com.exacttarget.wsdl.partnerapi.TriggeredSendCreateResult;
import com.exacttarget.wsdl.partnerapi.TriggeredSendDefinition;

/**
 * Example to show Axis 1.4 usage pattern as a client to invoke services from
 * ExactTarget Integration Framework Web Service API endpoint.
 *
 * @author Erik Gfesser
 */
public class ClientTest {
 static String user = null;
 static String password = null;
 static String clientWSDD = null;
 static String customerKey = null;
 static String validEmailAddress = null;
 static String validSubscriberKey = null;
 static String validFromAddress = null;
 static String validFromName = null;
 static String invalidEmailAddress = null;
 static String invalidSubscriberKey = null;
 static String invalidFromAddress = null;
 static String invalidFromName = null;

 public static void main(String[] args) throws ServiceException,
 RemoteException {
 EngineConfiguration config = new FileProvider(clientWSDD);

 // Create PartnerAPI stub with ExactTarget Web Service API endpoint and
 // Axis configuration
 PartnerAPI service = new PartnerAPILocator(config);
 Soap stub = service.getSoap();

 testET( stub );

 } // end method main
}

In the testET method you can use any one of the ET API method to test the connectivity to the ET is working or not.

iv) If it works then you can generate the ET jar using compile.client ant target and you may use this jar as ET client in your target projects.

Grails EHCache Settings

Tags

, , ,

We have configured Ehcache as second level hibernate cache for our project. This post is for Grails 1.1.1 projects. In the later version of grails, the configuration can be little different. Here are the steps. (It is quite some time when I did the actual configuration. Let me know if I missed something)

i)

First of all we have put ehcache.xml in grails-app/conf directory. Our config file looks like this.  You may modify the config based on your preferences. To learn more about this settings go to http://ehcache.org/documentation/configuration.html


<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="ehcache.xsd">
 <defaultCache
    maxElementsInMemory="1000"
    eternal="false"
    timeToIdleSeconds="3600"
    timeToLiveSeconds="3600"
    overflowToDisk="false"
    diskPersistent="false"
    diskExpiryThreadIntervalSeconds="120"
    memoryStoreEvictionPolicy="LRU"
 />

 <cache name="org.hibernate.cache.UpdateTimestampsCache"
        maxElementsInMemory="10000"
        timeToIdleSeconds="300"
 />

 <cache name="org.hibernate.cache.StandardQueryCache"
        maxElementsInMemory="10000"
        timeToIdleSeconds="300"
 />

</ehcache>

ii) Modify the cache provider class in your DataSource.groovy to org.hibernate.cache.EhCacheProvider like this

hibernate {
    cache.use_second_level_cache=true
    cache.use_query_cache=true
    cache.provider_class='org.hibernate.cache.EhCacheProvider'
}

iii) Now to fine-tune your cache setting, go to individual domain classes for which you want to enable ehcache and add the following mapping closure with cache true

class Employee {
    String name
    ........
    ........
    static constraints = {
        ....
    }

    static mapping = {
        cache true
    }
}

iv) If you want your query to be cached, you can configure it similarly with cache true clause

		def employeeList = Employee.createCriteria().list() {
			or {
				......
			}
			order(".....", "...")
			cache true
		}

For further reading to to http://ehcache.org/documentation/grails.html

Follow

Get every new post delivered to your Inbox.