Thursday, December 06, 2012

Why Liferay ?


So why is Liferay Portal the best portal product in our opinion?
  1. Liferay has the lowest Total Cost of Ownership (TCO) compared to its competitors starting with its licensing and getting it up and running through development costs, operational costs, and training/support costs (from the perspective of infrastructure, developers, administrators, and end users).
  2. Second-to-none rich out-of-the-box (OOTB) functionality around core portal, content management, collaboration, social, mobile, security and more; check out http://www.liferay.com/products/liferay-portal/features/portal for more information.
  3. All portal products typically need extensions and/or additions to deliver requisite functionality – with Liferay you can simply do more within a specific budget.
  4. Product innovation – leader in introducing new capabilities whether it be AJAX or friendly URLs or mobile or social
  5. Improved business agility – it is lightweight in nature; you can quickly get it up and running, and it is easier to develop on/manage.
  6. A mature Enterprise Open Source (fully supported) product – 24x7x365 platinum support with 1 hour response time SLA; this includes access to all service packs, hot fixes, notifications of security alerts, phone and web based support.
  7. Liferay’s open architecture and its open source nature help you avoid lock-in to a single proprietary vendor.
  8. Liferay’s hook and extension plugin model allows you to tailor product behavior to your needs without rewriting from scratch and without creating upgrade hell.
  9. Liferay offers opportunities for product feature sponsorship to enable contributions back into the core product for key customizations – this allows you to offload responsibility of maintaining and enhancing your custom features back to Liferay.
  10. Liferay offers you a full choice of application servers, databases, and operating systems to run on, thereby allowing you to leverage your infrastructure and skills investment.
References:




Wednesday, December 05, 2012

Part 3: Custom Liferay Plugin JSON Web Services

Go to Previous post Part 2: Custom Liferay Plugin JSON Web Services
Below is the step by step setup to expose and consume a plugin portlet service as JSON web service.

Step 1: Create a liferay plugin portlet

Step 2: Create a custom service

Using Liferay Service builder create a service. For example

The service.xml will look like below:
<service-builder package-path="com.rdg.api">
 <author>rishidev.gupta</author>
 <namespace>ServiceAPI</namespace>

 <entity name="Bridge" remote-service = "true" local-service="true" human-name="Bridge">
  <reference package-path="com.liferay.counter" entity="Counter"></reference>
  <reference package-path="com.liferay.portal" entity="User"></reference>
  <reference package-path="com.liferay.portlet.journal" entity="JournalArticle"></reference>
 </entity>
</service-builder>

Step 3: Build the service using liferay service builder 

Step 4: Writing a custom method to be exposed

public class BridgeLocalServiceImpl extends BridgeLocalServiceBaseImpl {

 public String getBridge(String str) throws PortalException {
  System.out.println("You have successfully requested for: " + str);
  return "You have successfully requested for: " + str;

 }
}
public class BridgeServiceImpl extends BridgeServiceBaseImpl {
 public String getBridge(String str) throws PortalException {
  return bridgeLocalService.getBridge(str);
 }
}
Now rebuild the service.

Step 5: Configuring web.xml 

To make sure that your custom portlets can be scanned, and their service can become part of the JSON API. For this you must add the following in portlets web.xml:


     <servlet>
        <servlet-name>JSON Web Service 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.jsonwebservice.JSONWebServiceServlet</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>JSON Web Service Servlet</servlet-name>
        <url-pattern>/api/jsonws/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>JSON Web Service Servlet</servlet-name>
        <url-pattern>/api/secure/jsonws/*</url-pattern>
    </servlet-mapping>

This enables the servlet that is responsible for scanning JSON web services configuration. Now deploy the plugin portlet in a running tomcat server.

Step 6: Consuming JSON Web Service

 To list registered services on portlet, 
http://localhost:8080/<portlet-context>/api/jsonws
 
To access service using browser
http://localhost:8080//service-api-portlet/api/jsonws/bridge/get-bridge?&str=rishidev.gupta 

Saturday, November 10, 2012

Part 2: Accessing and Using Liferay JSON Web Services

In previous post, I have worked on introducing all basics about JSON Web Services.
In this post the focus is on accessing and consuming the the services and example

To Restrict a method from being exposed as service, just annotate the method with:
@JSONWebService(mode = JSONWebServiceMode.IGNORE)

To define custom HTTP method name instead of using the default, just annotate the method with:
@JSONWebService(value = "get-user", method = "GET")
public User getUserById( ...

Thus above service will be exposed and accessed as

http://localhost:8080/api/jsonws/user/get-user

instead of 

http://localhost:8080/api/jsonws/user/get-user-by-id

To further customize the URL and remove the serviceClassname, just annotate the method with:
@JSONWebService("/get-user")
public User getUserById(..

Thus above service will be exposed and accessed as

http://localhost:8080/api/jsonws/get-user

instead of 

http://localhost:8080/api/jsonws/user/get-user-by-id

Portal Configuration

JSON Web Services can be enabled or disabled by setting the below portal property:
json.web.service.enabled=true
by default the services are enabled and the property is set to true.

Enabling/Disabling particular HTTP methods
jsonws.web.service.invalid.http.methods=DELETE,POST,PUT
causes portal to accept only GET requests and ignore the HTTP methods specified above.

Below is the comma separated list of public service methods that can be accessed by unauthenticated user:
For all methods as unauthenticated use below
jsonws.web.service.public.methods=*  
For is methods as unauthenticated use below

jsonws.web.service.public.methods=is*

Accessing service via HTML form


<form action="http://localhost:8080/api/jsonws/user/get-user-by-id" method="GET">
        <input type="hidden" name="userId" value="10172"/>
        <input type="submit" value="submit"/>
</form>
When submitted will result in response consisting of User object as JSON string.

Accessing service via Java based Apache HttpClient API 

Below is the example to access the Liferay services using the Apache HTTPClient API
public static void get() throws Exception {
  HttpHost targetHost = new HttpHost("localhost", 8080, "http");
  DefaultHttpClient httpclient = new DefaultHttpClient();
  httpclient.getCredentialsProvider().setCredentials(
    new AuthScope(targetHost.getHostName(), targetHost.getPort()),
    new UsernamePasswordCredentials("test", "test"));

  // Create AuthCache instance
  AuthCache authCache = new BasicAuthCache();
  // Generate BASIC scheme object and add it to the local
  // auth cache
  BasicScheme basicAuth = new BasicScheme();
  authCache.put(targetHost, basicAuth);

  // Add AuthCache to the execution context
  BasicHttpContext ctx = new BasicHttpContext();
  ctx.setAttribute(ClientContext.AUTH_CACHE, authCache);

  HttpPost post = new HttpPost(
    "/api/jsonws/user/get-user-by-id"); 
  List<NameValuePair> params = new ArrayList<NameValuePair>();
  params.add(new BasicNameValuePair("userId", "10172"));
  
  UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
  post.setEntity(entity);
  HttpResponse resp = httpclient.execute(targetHost, post, ctx);
  System.out.println(resp.getStatusLine());
  resp.getEntity().writeTo(System.out);
  httpclient.getConnectionManager().shutdown();
 }


When submitted will result in response consisting of User object as JSON string.

Go to  Next post Part 3: Custom Liferay Plugin JSON Web Services

References:
The article is my summarized view while working on the topic and references have been taken from Liferay community and documentation

Part 1: Introduction Liferay JSON Web Services

JSON Web Services provide convenient way access to portal service layer methods by exposing them as JSON HTTP API. This makes services methods easily accessible using HTTP requests, not only from JavaScript within the portal, but also from any JSON-speaking client.

Registering JSON web services


While using Service Builder to build services via service.xml append each entity definition with remote-service="true" to create and enable web services for the entity.  By doing this All remote-enabled services (i.e. entities with remote-service="true" in service.xml) are exposed as JSON Web Services.

When Service Builder creates each -Service.java interface for a remote-enabled service, the @JSONWebService annotation is added on the class level of that interface. Therefore, all of the public methods of that interface become registered and available as JSON Web Services.

On server startup a restricted scanning is done on portal and service jar files for the classes that uses @JSONWebService annotation. Post this the annotation are loaded and service methods are exposed as JSON based API.

For example UserService looks as below:
@JSONWebService
public interface UserService{
...
}

 Accessing Services

Below is the convention used to access any service exposed by default Liferay bundle
http://[server]:[port]/api/jsonws/[service-class-name]/[service-method-name] 
service-class-name is the name generated from service class name, 
by removing the Service or ServiceImpl suffix and converting it to a 
lowercase name.
service-method-name is generated from the service method name, 
by converting the camel-case method name to a lowercase separated-by-dash name
For example UserService can be accessed as:
@JSONWebService
public interface UserService{

 public User getUserById(long userId) {...}
}


http://localhost:8080/api/jsonws/user-service/get-user-by-id

All methods prefixed with get, has, is are pre assumed to be readonly and thus are exposed as GET methods, leaving rest as POST methods.

Non-public service methods require the user to be registered before invoking the method and accessed as

http://[server]:[port]/api/secure/jsonws/[service-class-name]/[service-method-name]http://localhost:8080/api/jsonws/user-service/get-user-by-id

Viewing list of default liferay bundle service

You can view all the registered and available service listing ay accessing the below url
http://localhost:8080/api/jsonws
 
In my next post, I have further detailed about configuring and 
accessing the JSON Web services 
 
References:
The article is my summarized view while working on the topic and references have been taken from Liferay community and documentation

Wednesday, October 10, 2012

Java Concurrency / Multithreading: Part 3

In Previous post (Java Concurrency / Multithreading :Part 2) learn how to initialize and use ExecutorService.

There are numerous problem domains where while designing the application you will need to implement the thread pool and each thread after completing the task, based on inputs should return a value. Futures and Callables exist exactly to solve this area.

Till now we have implemented the thread pool (in previous post) using the Runnables which do not return any value. In case a thread should return a value based on computation or work done as part of task you can use java.util.concurremt.Callable. Callable return value after execution. Callable returns an object of java.util.concurrent.Future. Future is used to check the status of task and return some value. Below is the example to use Callable and return a value

public class MyRunnable implements Callable<Long> {  
     @Override  
     public Long call() throw Exception {  
       return 5L;  
     }  
   } 

Using the Executor Framework

public class Example {

    public static void main(String[] args) {



        ExecutorService executor = Executors.newFixedThreadPool(5);

        List<Future<Long>> fList = new ArrayList<Future<Long>>();

        for (int i = 0; i < 999; i++) {

            Callable<Long> worker = new MyRunnable();

            Future<Long> submit = executor.submit(worker);

            fList.add(submit);

        }

        long sum = 0;



        for (Future<Long> future : fList) {

            try {

            sum += future.get();

            } catch (InterruptedException e) {

            e.printStackTrace();

            } catch (ExecutionException e) {

            e.printStackTrace();

            }

        }

        System.out.println("Final Sum is : " + sum);

        executor.shutdown();

    }

} 

Java Concurrency / Multithreading: Part 2

See my earlier post (Java Concurrency / Multithreading :Part 1) related to basics about java threads and concurrency.

Executor Framework

ThreadPools is the way to manage the pool of working threads and limit the creation of thread as creating a thread have resource overhead associates with it. Thus thread pools contains a work queue waiting for their turn to get executed.

In thread pool, the thread are constantly running and checking the queue for new work. As soon as the pool have a idle thread the work is assigned to one of the threads.

With Java 5 came Executor Framework under java.util.concurrent package, so that you do not need to create and manage your own pool e.g java.util.concurrent.Executor can be initialized as Executors.newfixedThreadPool(n) to create n worker threads. 

Like wise Executors.newSingleThreadExecutor(); will create a single thread pool with only one worker thread.

Example:
Creating a Runnable class
public class MyRunnable implements Runnable {
    private final long count;
    MyRunnable(long count) {
        this.count = count;
    }
    @Override
    public void run() {
        long mySum = 0;
        for (long i = 1; i < count; i++) {
            mySum = mySum + i;
        }
        System.out.println(mySum);
    }
}

Using the Executor Framework
public class Example {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 100; i++) {

            Runnable myworker = new MyRunnable(99999999L + i);

            executor.execute(myworker);

        }

        executor.shutdown();

        while (!executor.isTerminated()) {



        }

        System.out.println("Completed processing the work queue");

    }

} 


ExecutorService executor = Executors.newFixedThreadPool(5); creates a new pool of 5 worker threads.

executor.execute(myworker); adds new work in the queue for thread pool to complete.

executor.shutdown(); waits till all the work in the queue is completed. After calling this method the ExecutorService will not take any new task but once all the current tasks in the queue are complete the ExecutorService will shutdown.

To stop the ExecutorService immediately call shutdownNow() method.This will attempt to stop all executing tasks right away, and skips all submitted but non-processed tasks. There are no guarantees given about the executing tasks. Perhaps they stop, perhaps the execute until the end. It is a best effort attempt.

 executor.isTerminated() checks if the service is terminated or not.

Till now we have submitted the tasks to ExecutorService and never waited to get a return value after . Thus in case the threads should return some value then you should use java.util.concurrent.Callable. See my next post (Java Concurrency / Multithreading: Part 3) summarizing the above concept.

Tuesday, October 09, 2012

Java Concurrency / Multithreading :Part 1

Goal:

How to execute the tasks in background using Java concurrent programming. It also covers the concepts of threads, parallel programming, java.util.concurrent.Executor, java.util.concurrent.Future, java.util.concurrent.Callable framework.

Details:

What is Concurrency?

In computer world, concurrency means executing several programs simultaneously or in parallel and these programs may or may not interact with each other. Running several programs in parallel or asynchronously can add to over all performance of the task.

Process vs Threads

Both thread and process are methods of parallelizing the application. Below are the key points highlighting the differences between Process and Thread.

Process: are independent execution units. Applications are typically divided into various processes during the design phase. It cannot directly access shared data in other processes.However this is done by inter-process mechanism managed by operating system. A process might contain multiple threads.

Thread: are light weight processes and is the basic unit to which the operating system allocates processor time. A thread can execute any part of the process code, including parts currently being executed by another thread. . Every thread have its own memory cache.

Why Concurrency

  •  Efficient utilization of resources
  • Increased application throughput
  • High responsiveness
  •  Programs becomes simpler: as some of the problem domains are well suited to be represented as concurrent tasks

Disadvantages

  • With increased complexity the program design becomes more complex
  • Context Switching between threads, too many open threads will lead to context switching overheads causing the performance degrade

 Threads in Action

Threads are the core of all concurrent or parallel programing. There are 2 ways to implement thread in java.
The First one is extending java.lang.Thread class. Below is the way to create a thread:
Thread myThread =  new Thread();
Now after initialization , to start thread
myThread.start();

Create a subclass of Thread
public class CustomThread extends Thread{

 public void run(){
 System.out.println("Hello Thread");
}
}

Using the above class
CustomThread thread1 = new CustomThread();

thread1.start()
The second way is to implement the java.lang.Runnable interface.
public class MyRunnable implements Runnablee{
public void run (){

System.out.println("Hello Runnable"); 

} 

}
Using the above class
Thread thread1 =  new Thread(new MyRunnable);

thread1.start();
Next>>> Java Concurrency / Multithreading: Part 2


Linux/Unix: Handy Commands

To change the timezone on linux server use the below command


ln -sf /usr/share/zoneinfo/America/New_York  /etc/localtime

 To create an archive

tar -czf my_archive.tar.gz /usr/local/jeff/docs

To change or update the date

date -s "09 OCT 2012 12:19:00"

MySQL: Backup and Restore

In the past I have always tried to take database backup and followed by restoration process using the various client tools like SQLYog or HeidiSQL. As I have worked on community version of these tools thus always faced restrictions or got errors while working with larger database.

With experience I switched to MYSQL in built library function which came to my rescue and never let me down: Below are the details for the same:

For Windows:

  • Open a command prompt DOS window by typing in "cmd" in Start>>Run Menu
  • Now navigate to the bin directory of the MySQL installation say
    cd c:/Program Files/MySQL/MySQL Server 5.0/bin
  • For backup
    mysqldump.exe -u root -pabc123 se_alfresco > d:\backup.sql
  • For restore
    mysql.exe -u root -pabc123 se_alfresco < d:\backup.sql

For Linux/Unix:

  • Go to linux shell prompt
  • Use the below command for back up and restoration
  • For backup
    mysqldump -u root -pabc123 se_alfresco > d:\backup.sql
  • For restore
    mysql -u root -pabc123 se_alfresco < d:\backup.sql

MySQL: Grant permission to a user

Create a new user

 CREATE USER 'c'@'localhost' IDENTIFIED BY 'mypass';

Grant all permission on all database

grant all privileges on *.* to 'v'@'localhost' identified by 'mypass' with grant option;

Grant all permission on a database


grant all privileges on appDB.* to 'v'@'localhost' identified by 'mypass' with grant option;

References:

For complete details see MySQL Manual.


Wednesday, October 03, 2012

Why C3P0 over Commons DBCP?

What is Connection pool?
Connection pool is good for performance, as it prevents Java application create a connection each time when interact with database and minimizes the cost of opening and closing connections. The purpose is to reuse the connections and manage the process of opening, closing efficiently.

The shortcomings/disadvantages of Commons DBCP are very clearly documented over Tomcat 7.0 JDBC connection pool  documentation.

  1. commons-dbcp is single threaded, in order to be thread safe commons-dbcp locks the entire pool, even during query validation.
  2. commons-dbcp is slow - as the number of logical CPUs grow, the performance suffers, the above point shows that there is not support for high concurrency Even with the enormous optimizations of the synchronized statement in Java 6, commons-dbcp still suffers in speed and concurrency.
  3. commons-dbcp is complex, over 60 classes. tomcat-jdbc-pool, core is 8 classes, hence modifications for future requirement will require much less changes. This is all you need to run the connection pool itself, the rest is gravy.
  4. commons-dbcp uses static interfaces. This means you can't compile it with JDK 1.6, or if you run on JDK 1.6/1.7 you will get NoSuchMethodException for all the methods not implemented, even if the driver supports it.
  5. The commons-dbcp has become fairly stagnant. Sparse updates, releases, and new feature support.
  6. It's not worth rewriting over 60 classes, when something as a connection pool can be accomplished with as a much simpler implementation.
  7. Tomcat jdbc pool implements a fairness option not available in commons-dbcp and still performs faster than commons-dbcp
  8. Tomcat jdbc pool implements the ability retrieve a connection asynchronously, without adding additional threads to the library itself
  9. Tomcat jdbc pool is a Tomcat module, it depends on Tomcat JULI, a simplified logging framework used in Tomcat.
  10. Retrieve the underlying connection using the javax.sql.PooledConnection interface.
  11. Starvation proof. If a pool is empty, and threads are waiting for a connection, when a connection is returned, the pool will awake the correct thread waiting. Most pools will simply starve.


See my other post (Tomcat 7: C3P0 Datasource Pool) summarizing how to Configure C3P0 in Tomcat 7.

Tomcat 7: C3P0 Datasource Pool

Goal:

To configure C3P0 datasource pool in tomcat 7

Detail: 

Till now I was using DBCP JDBC connection pooling for my applications. Considering that the library seems to be out of date now and is not meant for production grade system with heavy load on them, I looked towards the other free open source connection pooling library C3P0.

C3P0 is an easy-to-use library for making traditional JDBC drivers "enterprise-ready" by augmenting them with functionality defined by the jdbc3 spec and the optional extensions to jdbc2.
Below are the steps to configure C3P0 pool in tomcat. 
  1. Download the latest c3p0-{version}.jar from http://sourceforge.net/projects/c3p0/.
  2. Copy the c3p0-{version}.jar to tomcat/lib directory.
  3. Open the tomcat/conf/context.xml in edit mode and add the below lines inside <Context> element.
    <Resource auth="Container" description="DB Connection" driverClass="com.mysql.jdbc.Driver" maxPoolSize="50" minPoolSize="10" acquireIncrement="10" name="jdbc/MyDBPool" user="root" password="abc123" factory="org.apache.naming.factory.BeanFactory" type="com.mchange.v2.c3p0.ComboPooledDataSource" jdbcUrl="jdbc:mysql://localhost:3306/lportal?autoReconnect=true" />
     
  4.  For  more on configuring various attributes of the connection pool, see http://www.mchange.com/projects/c3p0/#configuration

Environment:

Java 6
Tomcat 7
MySQL 5

Reference:

See my other post (Why C3P0 over Commons DBCP?) for more on DBCP vs C3P0 

Monday, October 01, 2012

Liferay 6.1: Documents And Media CMIS: Install & Configure Xuggler

Goal: 


Installation and Setup:

  • Install Xuggler 3.4 from http://www.xuggle.com/xuggler/downloads/
  • Configure Xuggler environment variables in setenv.sh
    export XUGGLE_HOME=/usr/local/xuggler
    export LD_LIBRARY_PATH=$XUGGLE_HOME/lib:$LD_LIBRARY_PATH
    export PATH=$XUGGLE_HOME/bin:$PATH
  • Start the tomcat
  • Go to Control Panel -> Server Administration->External Services. Select the version of Xuggler binary library compatible with your environment and follow the instructions.
  • You will need to restart the tomcat after above step as per the installation process.
  • To Enable Xuggler in portal
    Control Panel -> Server Administration->External Services -> Enable Xuggler
  • Now you are ready to play audio/video files uploaded in Documents And Media portlet.

Environment:

  • Linux 64 bit (libc version 6)
  • Liferay 6.1 GA2
  •  Tomcat 7
  • Java 1.6.0.20

Reference :

Friday, September 28, 2012

Liferay 6.1: Documents And Media CMIS: Integrating External Repository

Adding repositories in Documents and Media portlet is a new. Documents and Media allows to connect to multiple third-party repositories that support CMIS 1.0 via AtomPUB or Web Services protocols.
To add new repositories from the web click the Add button from the Home folder. Repositories can only be mounted in the Home folder.
Need to make sure that same credentials are being used  in liferay and external repository for authentications. In order to authenticate and make it working you need to enable the following in portal.properties.
session.store.password=false
company.security.auth.type=screenName

Example 

  1. External Repository is Alfresco 4.
  2. Once the  Liferay and Alfresco are up and working either both on same tomcat or separate (i have deployed on same tomcat).
  3. Goto Document and Media portlet >> Click on Add >> select "Repository"
  4. Enter Name, Description.
  5. Select type as Atompub.
  6. For AtomPub URL enter "http://localhost:8080/alfresco/service/cmis" and click Save.
  7. You will see a new entry on left side and now you will be able to browse and search the Alfresco repository.

Environment:

References:

    • User guide of http://www.liferay.com
    • http://www.liferay.com/es/community/wiki/-/wiki/Main/CMIS+Repository#section-CMIS+Repository-Mounting+a+Repository

Thursday, September 27, 2012

Organizations or Communities, which one should I use?

The concept of Organization, Community, groups have been extended in Liferay 6.1, providing a greater flexibility and customization. Below is the link from Liferay official site which explains this in a simple yet practical manner.
Organizations or Communities, which one should I use? The final answer

Thursday, July 12, 2012

Liferay: Disable portlet border

Aim: Disable border for all portlets

Solution:

The easiest way to do this is using theme. Open liferay-look-and-feel.xml  add to it below line to achieve the purpose by default for all portlets.

<theme id="myTheme" name="myTheme">
       <settings>
            <setting key="portlet-setup-show-borders-default" value="false" />
        </settings>
</theme>

Liferay: Inter portlet service access


Friday, June 22, 2012

Liferay: Invoke a servlet from portlet

Goal: 

To call a servlet from portlet deployed in liferay 6.

Solution:

 Step 1: Create a servlet

 public class myServlet extends HttpServlet {
  public void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
     System.out.println ("inside servlet");
     response.sendRedirect(portal_url); //url of portal page
  }
}

myServlet.java is a simple servlet class in which service() method serves the purpose of redirecting the control back to portal page. portal_url is the actual absolute URL where the servlet should redirect after processing.

Step 2: Configuring web descriptor

Go to portlet web.xml and make an entry like below:
<servlet>
        <servlet-name>myAction</servlet-name>
        <servlet-class>com.liferay.portal.kernel.servlet.PortalDelegateServlet</servlet-class>
        <init-param>
            <param-name>servlet-class</param-name>
            <param-value>com.rdg.portlet
.myServlet</param-value>
        </init-param>
        <init-param>
            <param-name>sub-context</param-name>
            <param-value>
myAction</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>


In the above web descriptor com.liferay.portal.kernel.servlet.PortalDelegateServlet serves to redirect any request coming to "http://localhost:8080/myAction" to service() method of com.rdg.portlet.myServlet and will redirect back to the liferay portal url.

Step 3: Creating portlet action class to redirect to the servlet

public class myPortletAction extends MVCPortlet {
  public void redirectMe(ActionRequest actionRequest,
            ActionResponse actionResponse) throws IOException, PortletException {


    actionResponse.sendRedirect("http://localhost:8080/myAction");
 }
}

So when a form is submitted to the action and control is sent to redirectMe() method, it redirects the request to "http://localhost:8080/myAction" for further processing.



Monday, June 18, 2012

AUI: Refresh on popup close button

To referesh the parent window while closing a AUI pop in liferay, use the following code:
window.myDialog = new A.Dialog(
            {
     on: {
      close: function() {
      document.location.href='<%=oncloseURL%>';
     }

    },
                title: title,
                centered: true,
    resizable: false,
    draggable: false,
    modal: true,
    width: 800,
    height:550,
   
       
            }
        )

Friday, June 15, 2012

Inter Portlet Coordination with JSR 286

JSR 168 (Potlet 1.0) specification doesn't clearly suggest any mechanism for the inter-portlet communication i.e. communication between two portlets. This was regarded as one of the major short-comings for JSR 168. Though most of the vendors had their own extensions to JSR 168 for managing inter-portlet communication, use of any of those methods defeat the very purpose of JSR 168. In absence of any well defined sophisticated mechanism, JSR 168 developer had to rely upon either PortalContext or Application Scope of Session for sharing information between the protlets.

JSR 286 has come up with a well defined model to achieve inter-portlet communication. There are two primary ways by which inter-portlet communication can achieved as follows -

  1. public render parameters in order to share render state between portlets.
  2. portlet events that a portlet can receive and send.


There are pros and cons of each method. Though the biggest advantage with Portlet Events method is that an object can be passed from one portlet to another as opposed to merely "String" in case of "Public Render Parameters" method.

Below are the steps to get it going:

Step 1:

Open portlet.xml and add the following entries

<portlet-app ...>
<portlet> ... </portlet>
<public-render-parameter>
<identifier>user-id</identifier> <qname xmlns:x="http://abc.com/userId">x:userId</qname>

</public-render-parameter>

</portlet-app>

Note:
  1. A developer can declare a list of public paramters for a portlet application in portlet.xml.
  2. Parameter names are namespaced to avoid naming conflict.

Step 2:

Portlet must declare which public param they want to use. e.g.

After adding declaration portlet.xml will look something like this.

<portlet-app ......>
<portlet>
<portlet-name>test1</portlet-name> <display-name>test1</display-name>
........ ........

<supported-public-render-parameter> user-id</supported-public-render-parameter>
</portlet>
<public-render-parameter>
<identifier>user-id</identifier> <qname xmlns:x="http://abc.com/userId">x:userId</qname>

</public-render-parameter>

</portlet-app>

Note: 
  1. Public params are available in all lifecycle method like processAction , processEvent, render and serveResource.

Step 3: 

We can set render parameter in the processAction() method by using the defined public render parameter identifier as the key. e.g.

public void processAction(ActionRequest request, ActionResponse response)

throws IOException, PortletException {
 ........ 
response.setRenderParameter("user-id", userId);
 }

Step 4: 

A portlet can read public render parameter using follwing method

request.getPublicParameterMap()

Note: 
  1. Public render parameters are merged with regular parameters so can also be read using

request.getParameter(name) or request.getParameterMap()

Step 5: 

A portlet can remove a public render parameter by invoking following methods.

response.removePublicRenderParameter(name)

or

portletURL.removePublicRenderParameter(name) 

References

http://blog.xebia.com/2009/04/19/inter-portlet-coordination-with-jsr-286/

Thursday, June 07, 2012

Liferay Tomcat Performance

Motive

To get performance improvement in terms of time taken by liferay tomcat to start.

Solution

Tomcat's core libraries are available in Java Byte code normally. Apache Tomcat Native Library is a Java Native Interface that provide most of the core functionality in native code. Using these libraries only mean one thing to you and i.e. SPEED.
 For Windows
  1. Download http://archive.apache.org/dist/tomcat/tomcat-connectors/native/1.1.15/binaries/win64/x64/
  2. Copy tcnative-1-ip4.dll to %TOMCAT_HOME%/bin
  3. Restart Tomcat and check the tomcat startup performance.




Tuesday, May 15, 2012

Liferay: Working with model listeners

What 

Model Listener - as the name specifies that there is some class that in continuously looking to a entity model in liferay. More technically its a call back class which is called when some operation happens on the model (operation can be add/edit/delete).

Model Listener

public interface ModelListener<T> {
 public void onAfterAddAssociation(Object classPK, String associationClassName, Object associationClassPK) throws ModelListenerException;

public void onAfterCreate(T model) throws ModelListenerException;

public void onAfterRemove(T model) throws ModelListenerException;

public void onAfterRemoveAssociation(Object classPK, String associationClassName,  Object associationClassPK) throws ModelListenerException;

public void onAfterUpdate(T model) throws ModelListenerException;

public void onBeforeAddAssociation(Object classPK, String associationClassName, Object associationClassPK) throws ModelListenerException;

public void onBeforeCreate(T model) throws ModelListenerException;

public void onBeforeRemove(T model) throws ModelListenerException;

public void onBeforeRemoveAssociation(Object classPK, String associationClassName, Object associationClassPK) throws ModelListenerException;

public void onBeforeUpdate(T model) throws ModelListenerException;
}
 

How

To implement own listener on some Model (for example User) yin your portlet you need:
<hook>
 <portal-properties>portal.properties</portal-properties>
</hook>
 
Make an entry in file WEB-INF/src/portal.properties to define hook for specific model:
value.object.listener.com.liferay.portal.model.User=my.hook.UserListener 

Implement class by inheriting it from BaseModelListener<T> in our case BaseModelListener<User> and implementing only
  method we want to call-back:

    public class GroupListener extends BaseModelListener<Group> {
@Override public void    onAfterUpdate(User u) throws ModelListenerException { // do something here } }



Rounded



Use firebug and check the style of this below black background to get the css for making corners rounded.
 
 

Thursday, March 29, 2012

End of Version Announcement for Liferay 5.2 EE

On February 29, 2012, Liferay announces the End of Version for Liferay 5.2 EE. The last date to order Liferay 5.2 EE (Last Ship Date) is May 31, 2012.

For more details see the original post