Developing JPA application for use in WebSphere

In the Developing JPA application for use in Java SE entry i blogged about how to develop a simple JPA application using RAD and execute it outside the application server. But the more common use case for JPA would be how to use it inside Application Server.

I wanted to learn how to develop an JPA application that runs inside WebSphere Application Server so i build this simple HelloJPA1Portlet application which is essentially same as that of the HelloJPA1 application that i built in the In the Developing JPA application for use in Java SE , with difference that this one runs inside in application container.

Follow these steps to add support for JPA inside a portlet

  1. First create a HelloJPA1Portlet in RAD and deploy it in the WPS 7.0. Once the basic thing is working you can right click on the project and click on Properties. Select Project Facets like this

    Select JPA and version 1.0

  2. Next configure a JDBC Datasource connecting to the same database that we used in the last project and use jdbc/hellojpa as the JNDI name for the data source make sure the database actually works


  3. Follow the same steps that i mentioned in Developing JPA application for use in Java SE for generating entities accessing Customer table or you might want to simply copy the code from there.

  4. One step that is different is change persistence.xml to use the data source configured at jdbc/hellojpa JNDI location instead of directly connecting to database. You can do that by right clicking on project and then selecting JPA Tools -< Configure project for JDBC Deployment


    As you can see i am using the JNDI name of the data source instead of database properties

  5. When you click on the Finish button, your persistence.xml file will get updated to look like this

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="HelloJPA1" >
    <jta-data-source>jdbc/hellojpa</jta-data-source>
    <class>com.webspherenotes.jpa.Customer</class>
    <properties>
    <property name="openjpa.jdbc.Schema" value="ADMIN"/>
    </properties>
    </persistence-unit>
    </persistence>


  6. Your portlet code would be same as that of the standalone client like this

    package com.webspherenotes.jpa;

    import java.io.*;
    import java.util.List;

    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;
    import javax.portlet.*;

    import com.webspherenotes.jpa.controller.CustomerManager;

    /**
    * A sample portlet
    */
    public class HelloJPA1Portlet extends javax.portlet.GenericPortlet {
    /**
    * @see javax.portlet.Portlet#init()
    */
    public void init() throws PortletException{
    super.init();
    }

    /**
    * Serve up the view mode.
    *
    * @see javax.portlet.GenericPortlet#doView(javax.portlet.RenderRequest,
    javax.portlet.RenderResponse)
    */
    public void doView(RenderRequest request, RenderResponse response)
    throws PortletException, IOException {
    // Set the MIME type for the render response
    response.setContentType(request.getResponseContentType());

    EntityManagerFactory entityManagerFactory = Persistence
    .createEntityManagerFactory("HelloJPA1");
    CustomerManager manager = new CustomerManager(entityManagerFactory);

    List customerList = manager.getCustomers();
    for(Customer c : customerList){
    System.out.println(c);
    }

    super.getPortletContext().getRequestDispatcher("/index.jsp").include(request, response);

    }
    }




Now when you try to access the portlet you should be able to see list of customers being printed in the SystemOut.log file

Developing JPA application for use in Java SE

These are the steps that i followed to create a JPA project using Rational Application Developer 8.0 and executing it. I am executing this project outside application server. In the next entry i will blog about how to use JPA in J2EE application running inside the WebSphere Application Server.

I am assuming that you already have a CUSTOMER table in your database and now you want to use JPA to work with that table. If you dont have Customer table you can use this DDL to create it

CREATE TABLE CUSTOMER (
CUST_ID INTEGER NOT NULL ,
FIRST_NAME VARCHAR(50) NOT NULL,
LAST_NAME VARCHAR(50),
STREET VARCHAR(50),
APPT VARCHAR(20),
CITY VARCHAR(25),
ZIP_CODE VARCHAR(10) NOT NULL,
CUST_TYPE VARCHAR(10) NOT NULL ,
WEBSITE VARCHAR(100),
LAST_UPDATED_TIME TIMESTAMP
);


ALTER TABLE CUSTOMER ADD CONSTRAINT CUSTOMER_PK Primary Key (CUST_ID);

Follow these steps to create JPA project and execute it.

  1. Open RAD and click on Create new Project -< JPA -< JPA Project. On the next screen enter HelloJPA as project name and click on next next. Make sure to select value of Configuration to Minimal JPA 1.0 Configuration


  2. Next on the JPA Facet dialog box, you can select the existing database connection that you have in RAD. In my case i dont have the connection to the Apache Derby Sample database configured so i need to click on Add Connection


  3. Use the steps provided in Accessing Database using Eclipse/ Rational Application Developer for configuring connection to the database

  4. Once your database connection is configured it will bring you back to the Create JPA Project screen like this, In my case name of the connection that i just configured is "New Connection"


  5. With this your JPA project will be ready, the project generated by RAD does not have anything but the persistence.xml.

  6. In my case i already have a database table that i want to interact with. Now i want to generate JPA code for working with project. So right click on the project and click on JPA Tools -< Generate Entities from table. It will open a dialog box like this. As you can see the New Connection is selected in the Connection select box and you can see the tables in that database. I am only interested in CUSTOMER table so select it.


  7. On the next screen it will ask you few more options for generating entity. Change value of Key Generation to auto and change package name to com.webspherenotes.jpa and click next


  8. In the last screen it will ask you for some information related to customer table things like what should be name of the entity class,.. Keep default values like this


  9. If you look at the HelloJPA project you will notice that RAD has generated a Customer.java class which is entity class (Java object representing Customer table) like this

    'package com.webspherenotes.jpa;

    import java.io.Serializable;
    import javax.persistence.*;
    import java.sql.Timestamp;

    /**
    * The persistent class for the CUSTOMER database table.
    *
    */
    @Entity
    public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "CUST_ID")
    private int custId;

    private String appt;

    private String city;

    @Column(name = "CUST_TYPE")
    private String custType;

    @Column(name = "FIRST_NAME")
    private String firstName;

    @Column(name = "LAST_NAME")
    private String lastName;

    @Column(name = "LAST_UPDATED_TIME")
    private Timestamp lastUpdatedTime;

    private String street;

    private String website;

    @Column(name = "ZIP_CODE")
    private String zipCode;

    public Customer() {
    }

    public int getCustId() {
    return this.custId;
    }

    public void setCustId(int custId) {
    this.custId = custId;
    }

    public String getAppt() {
    return this.appt;
    }

    public void setAppt(String appt) {
    this.appt = appt;
    }

    public String getCity() {
    return this.city;
    }

    public void setCity(String city) {
    this.city = city;
    }

    public String getCustType() {
    return this.custType;
    }

    public void setCustType(String custType) {
    this.custType = custType;
    }

    public String getFirstName() {
    return this.firstName;
    }

    public void setFirstName(String firstName) {
    this.firstName = firstName;
    }

    public String getLastName() {
    return this.lastName;
    }

    public void setLastName(String lastName) {
    this.lastName = lastName;
    }

    public Timestamp getLastUpdatedTime() {
    return this.lastUpdatedTime;
    }

    public void setLastUpdatedTime(Timestamp lastUpdatedTime) {
    this.lastUpdatedTime = lastUpdatedTime;
    }

    public String getStreet() {
    return this.street;
    }

    public void setStreet(String street) {
    this.street = street;
    }

    public String getWebsite() {
    return this.website;
    }

    public void setWebsite(String website) {
    this.website = website;
    }

    public String getZipCode() {
    return this.zipCode;
    }

    public void setZipCode(String zipCode) {
    this.zipCode = zipCode;
    }

    public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("custId : " + custId);
    sb.append(" First Name : " + firstName);
    sb.append(" Last Name : " + lastName);
    sb.append(" customer type : " + custType);

    return sb.toString();
    }
    }

    I copied the toString() method. You can also get RAD to generate the toString() method for you

  10. Now next step will be to configure database connection properties. For that right click on the HelloJPA project say JPA tools -< Configure Project for JDBC Deployment and select "Set Connection Directly Via properties" radio box. This will copy the connection properties that you used for connecting to DB inside your persistence.xml file like this

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="HelloJPA1">
    <class>com.webspherenotes.jpa.Customer</class>
    <properties>
    <property name="openjpa.ConnectionDriverName"
    value="org.apache.derby.jdbc.ClientDriver"/>
    <property name="openjpa.ConnectionURL"
    value="jdbc:derby://localhost:1527/C:/work/webspherenotes/db;create=true"/>
    <property name="openjpa.ConnectionUserName" value="admin"/>
    <property name="openjpa.ConnectionPassword" value="admin"/>
    </properties>
    </persistence-unit>
    </persistence>


  11. Now your JPA code is ready you can use it directly. But you can also ask RAD to create Managed Bean which will generate basic JPA methods for performing CRUD operation on the table. FOr that right click on the HelloJPA project -< JPA Tools -< Add JPA Managed Beans it will open a screen like this

    This list the entities in your project. In my case i have only Customer table so select that and click on next.

  12. Here it will allow you to create few more methods like this


  13. Once you click on finish the RAD will generate CustomerManager.java class like this

    package com.webspherenotes.jpa.controller;

    import java.util.List;

    import com.ibm.jpa.web.JPAManager;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Query;

    import com.ibm.jpa.web.Action;
    import com.webspherenotes.jpa.Customer;

    @SuppressWarnings("unchecked")
    @JPAManager(targetEntity = com.webspherenotes.jpa.Customer.class)
    public class CustomerManager {

    private EntityManagerFactory emf;

    public CustomerManager() {

    }

    public CustomerManager(EntityManagerFactory emf) {
    this.emf = emf;
    }

    public void setEntityManagerFactory(EntityManagerFactory emf) {
    this.emf = emf;
    }

    private EntityManager getEntityManager() {
    if (emf == null) {
    throw new RuntimeException(
    "The EntityManagerFactory is null.
    This must be passed in to the constructor or
    set using the setEntityManagerFactory() method.");
    }
    return emf.createEntityManager();
    }

    @Action(Action.ACTION_TYPE.CREATE)
    public String createCustomer(Customer customer) throws Exception {
    EntityManager em = getEntityManager();
    try {
    em.getTransaction().begin();
    em.persist(customer);
    em.getTransaction().commit();
    } catch (Exception ex) {
    try {
    if (em.getTransaction().isActive()) {
    em.getTransaction().rollback();
    }
    } catch (Exception e) {
    ex.printStackTrace();
    throw e;
    }
    throw ex;
    } finally {
    em.close();
    }
    return "";
    }

    @Action(Action.ACTION_TYPE.DELETE)
    public String deleteCustomer(Customer customer) throws Exception {
    EntityManager em = getEntityManager();
    try {
    em.getTransaction().begin();
    customer = em.merge(customer);
    em.remove(customer);
    em.getTransaction().commit();
    } catch (Exception ex) {
    try {
    if (em.getTransaction().isActive()) {
    em.getTransaction().rollback();
    }
    } catch (Exception e) {
    ex.printStackTrace();
    throw e;
    }
    throw ex;
    } finally {
    em.close();
    }
    return "";
    }

    @Action(Action.ACTION_TYPE.UPDATE)
    public String updateCustomer(Customer customer) throws Exception {
    EntityManager em = getEntityManager();
    try {
    em.getTransaction().begin();
    customer = em.merge(customer);
    em.getTransaction().commit();
    } catch (Exception ex) {
    try {
    if (em.getTransaction().isActive()) {
    em.getTransaction().rollback();
    }
    } catch (Exception e) {
    ex.printStackTrace();
    throw e;
    }
    throw ex;
    } finally {
    em.close();
    }
    return "";
    }

    @Action(Action.ACTION_TYPE.FIND)
    public Customer findCustomerByCustId(int custId) {
    Customer customer = null;
    EntityManager em = getEntityManager();
    try {
    customer = (Customer) em.find(Customer.class, custId);
    } finally {
    em.close();
    }
    return customer;
    }

    public List getAllCustomers(){
    List customerList = null;
    EntityManager em = getEntityManager();
    try {
    Query q= em.createQuery("SELECT x from Customer x");
    customerList =(List)q.getResultList();
    System.out.println(customerList.size());
    } finally {
    em.close();
    }
    return customerList;
    }

    @Action(Action.ACTION_TYPE.NEW)
    public Customer getNewCustomer() {

    Customer customer = new Customer();

    return customer;
    }

    }


  14. Now you want to create your own class to test your JPA configuration so create a CustomerTest.java class like this

    package com.webspherenotes.jpa;

    import java.util.List;

    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;

    import com.webspherenotes.jpa.controller.CustomerManager;

    public class CustomerTest {

    /**
    * @param args
    */
    public static void main(String[] args) {
    try {
    EntityManagerFactory entityManagerFactory = Persistence
    .createEntityManagerFactory("HelloJPA1");

    CustomerManager manager = new CustomerManager(entityManagerFactory);
    Customer customer = new Customer();
    customer.setFirstName("James");
    customer.setLastName("Bond");
    customer.setStreet("845 JB Ave");
    customer.setAppt("153");
    customer.setCity("JBCity");
    customer.setZipCode("007");
    customer.setCustType("test");
    customer.setWebsite("http://www.webspherenotes.com");
    manager.createCustomer(customer);

    System.out.println("Customer with id 1 " + manager.findCustomerByCustId(0));

    } catch (Exception e) {
    e.printStackTrace();
    }

    }

    }

    In this class i am using JPA code to get the EntityManagerFactory but after that i am delegating control to CustomerManager for creating new record in CUSTOMER table

  15. Since we want to execute this code outside application server we will have to make one change, At the runtime you will have to make one configuration change which is to set the value of javaagent to the JPA implementation provided by WebSphere Application server like this
    -javaagent:C:/IBM/WebSphere/AppServer/runtimes/com.ibm.ws.jpa.thinclient_7.0.0.jar


Java Persisence API in WebSphere

Starting from J2EE 5, the Java Persistence API is part of the J2EE specification. The basic idea is you develop data access application by creating POJO classes like Hibernate and then the container specific implementation takes care of interacting with the database.

The WebSphere Application Server V7.0 has support for JPA (I believe JPA 1.0) and i remember reading that WebSphere Application Server V8.0 supports JPA 2.0 and also provides second level caching. Since IBM will provide as well as support JPA i think WebSphere customer's might move towards it so i started spending some time learning about it and i am planning to blog about my experiences with JPA

The Rational Application Developer has support for developing JPA applications. You can execute JPA applications both inside and outside the container.



Uploading file to particular directory

You can configure the File Upload support in servlet specification 3.0 so that it uploads files to particular directory on your server.


package com.webspherenotes.j2ee6.servlet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Iterator;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

/**
* Servlet implementation class HelloFileUploadAnnotationServlet
*/
@WebServlet("/hellofileupload")
@MultipartConfig(location="c:/temp/upload")
public class HelloFileUploadAnnotationServlet extends HttpServlet {
private static final long serialVersionUID = 1L;


protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Entering HelloFileUploadAnnotationServlet.doPost()");
response.setContentType("text/html");
response.getWriter().println("Hello from FileUploadServlet");
Collection fileParts = request.getParts();
Iterator filePartIt = fileParts.iterator();
while(filePartIt.hasNext()){
Part filePart = filePartIt.next();
System.out.println("File Name " + filePart.getName());
System.out.println("File Size " + filePart.getSize());

System.out.println("File Content ");
BufferedReader fileReader =
new BufferedReader(new InputStreamReader(filePart.getInputStream()));
String line = null;
while(( line = fileReader.readLine()) != null){
System.out.println(line);
}
}
System.out.println("Exiting HelloFileUploadAnnotationServlet.doPost()");
}

}


In my case i am setting value of location to c:/temp/upload and then i tried uploading couple of files and now i can see that every time i upload a file a .tmp file gets created in c:/temp/upload

Setting limit on filesize to be uploaded

When your handling the file upload you might want to set limit on the file size that can be uploaded you can do that by setting value of maxFileSize. The value of maxFileSize is in bytes,

@WebServlet("/hellofileupload")
@MultipartConfig(maxFileSize=1000 )
public class HelloFileUploadAnnotationServlet extends HttpServlet {
private static final long serialVersionUID = 1L;


protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Entering HelloFileUploadAnnotationServlet.doPost()");
response.setContentType("text/html");
response.getWriter().println("Hello from FileUploadServlet");
Collection fileParts = request.getParts();
Iterator filePartIt = fileParts.iterator();
while(filePartIt.hasNext()){
Part filePart = filePartIt.next();
System.out.println("File Name " + filePart.getName());
System.out.println("File Size " + filePart.getSize());

System.out.println("File Content ");
BufferedReader fileReader =
new BufferedReader(new InputStreamReader(filePart.getInputStream()));
String line = null;
while(( line = fileReader.readLine()) != null){
System.out.println(line);
}
}
System.out.println("Exiting HelloFileUploadAnnotationServlet.doPost()");
}

}


So in my sample application if i try to upload a file bigger than 1000 bytes it will throw a java.lang.IllegalStateException exception like this

[12/19/10 20:24:23:765 PST] 00000019 servlet E com.ibm.ws.webcontainer.servlet.ServletWrapper service
SRVE0068E: An exception was thrown by one of the service methods of the servlet [com.webspherenotes.j2ee6.servlet.HelloFileUploadAnnotationServlet]
in application [HelloServletAnnotationEAR]. Exception created : [java.lang.IllegalStateException:
SRVE8021E: The file being uploaded is too large.
at com.ibm.ws.webcontainer.srt.SRTServletRequest.parseMultipart(SRTServletRequest.java:3504)
at com.ibm.ws.webcontainer.srt.SRTServletRequest.prepareMultipart(SRTServletRequest.java:3413)
at com.ibm.ws.webcontainer.srt.SRTServletRequest.getParts(SRTServletRequest.java:3394)
at com.webspherenotes.j2ee6.servlet.HelloFileUploadAnnotationServlet.doPost(HelloFileUploadAnnotationServlet.java:31)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1133)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:708)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:435)
at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1012)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3598)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:303)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:950)
at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1624)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:197)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:445)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:504)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:301)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:275)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1618)
]

Handling file upload in Servlet 3.0

Ability to handle file upload is one of the common requirements for web application. Before Servlet Specification 3.0 if you wanted to handle file upload you would have to use external library such as Apache Commons File upload to handle the file upload.

But starting from Servlet Specification 3.0 you dont need external library instead there is a native support. I wanted to try this so i followed these steps


  1. First i did create a index.jsp file like this

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <%@page
    language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <html>
    <head>
    <title>index</title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    </head>
    <body>
    <form action="hellofileupload" method="post" enctype="multipart/form-data" >
    <table>
    <tr>
    <td>File</td>
    <td><input type="file" name="samplefile" /></td>
    </tr>
    <tr><td><input type="submit"></td></tr>
    </table>
    </form>

    </body>
    </html>


    If you want to upload a file to the server you will have to set form encoding type to multipart/form-data. The index.jsp will submit form to the hellofileupload url and thats where our HelloFileUploadAnnotationServlet will come in

  2. Next create a HelloFileUploadAnnotationServlet like this

    package com.webspherenotes.j2ee6.servlet;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Collection;
    import java.util.Iterator;

    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;

    /**
    * Servlet implementation class HelloFileUploadAnnotationServlet
    */
    @WebServlet("/hellofileupload")
    @MultipartConfig
    public class HelloFileUploadAnnotationServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;


    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    System.out.println("Entering HelloFileUploadAnnotationServlet.doPost()");
    response.setContentType("text/html");
    response.getWriter().println("Hello from FileUploadServlet");
    Collection fileParts = request.getParts();
    Iterator filePartIt = fileParts.iterator();
    while(filePartIt.hasNext()){
    Part filePart = filePartIt.next();
    System.out.println("File Name " + filePart.getName());
    System.out.println("File Size " + filePart.getSize());

    System.out.println("File Content ");
    BufferedReader fileReader =
    new BufferedReader(new InputStreamReader(filePart.getInputStream()));
    String line = null;
    while(( line = fileReader.readLine()) != null){
    System.out.println(line);
    }
    }

    System.out.println("Exiting HelloFileUploadAnnotationServlet.doPost()");
    }
    }

    In order to use the file upload first you will have to mark the Servlet using MultipartConfig annotation, indicating that instances of the Servlet expect requests that conform to the multipart/form-data MIME type.
    Then inside the doPost() method you can use the method of HttpServletRequest to get access to the uploaded file.

Whats new in Servlet Specification 3.0

The Servlet Specification 3.0 has lot of new features such as


  1. Annotations

  2. Web Fragments

  3. Defining new servlet/filter using ServletContext API

  4. Async Servlet support



I want to try some of the features and i am planning to blog about them

Create profile in WAS 8 (Problem in creating profile as part of installation )

In the How to install WebSphere Application Server 8.0 Beta entry i blogged about the steps to install WebSphere Application Server 8.0 beta. On the last page of the WAS 8 installation wizard it asks you to create profile and it can launch profile creating wizard for you. I did select "Profile management tool to create an application server profile for development environment", but that profile management tool never came up. So i had to follow these steps to create application server profile



  • I went to the "\WebSphere\AppServer\bin\ProfileManagement" directory and executed the PMT.exe tool to start the profile management tool


  • On the next screen select Profile Management Tool and click on Launch tool and it will show you a profiles dialog box like this


  • On this dialog box click on Create button to get Create profile dialog box like this select Application Server as profile and click on Next button and follow next few screens to finish the creation of wizard









How to install WebSphere Application Server 8.0 Beta

It seems that there are quite a few new features in Java EE 5 and Java EE 6 and i wanted to start trying some of them. So i decided to install WebSphere Application Server 8 -Beta, which implements Java EE 6, in addition to many new IBM specific features. These are the steps that i used to install WAS 8 on my machine

  • Download WAS 8.0 Beta installable from IBM WebSite.I had to download 3 .zip from IBM website

  • After downloading the .zip file i did extract them in the same folder. I could see following folder structure


  • After unzipping the files i tried searching for launchpad.exe/setup.exe in all the three folders but i could not find it, so it took me some time to figure out that the procedure for installing the WAS 8.0 is changed. Now we have to use the Installation Manager(Same component that we use for installing Rational Application Developer) for installing the product using GUI

  • Since i use Rational Application Developer 8.0 on my machine i do have the installation manager for it. I decided to use the same installation manager. If you dont have the installation manager already on your machine, you can download it as part of WAS 8.0 installable

  • After starting the IBM Installation Manager and on the first screen click on Install button


  • Since the Installation Manager does not know about the location of your WAS 8 repository, it will open a screen like this, click on the Repository link


  • It will open a Repository preference dialog box like this


  • On this dialog box click "Add Repository" button, it will open a Add a Repository dialog box, use this to select the repository.config file that you unzipped from the WAS 8 installable like this and click Ok


  • Once the new repository is configured Installation Manager will show you WebSphere Application Server 8.0 as installation package, select it and click on Next to start the installation wizard

  • Go through the wizard and at the end select the packages that you want to install like this




The installation manager will take few minutes and once the installation is done it will show a dialog box for creating profile like this

Test LOT-915: IBM WebSphere Portal 7.0 Solution Development

Architecting a Portal Solution



  • Demonstrate familiarity with WebSphere Portal Web 2.0 features

  • Demonstrate knowledge of WebSphere Portal Platform features

  • Identify supported portlet frameworks/APIs

  • Identifying scope for custom portlets

  • Understand communications between portlets and widgets

  • Understand how portal features and portlets use user identity to personalize

  • Understand patterns and methods for application integration with WebSphere Portal

  • Understand portal page aggregation modes

  • Use out-of-the-box portlets



Install, Setup and Configuration of a Developer Environment



  • Compile, packaging, and deploying portal artifacts using Rational Application Developer
  • Create portlets in Rational Application Developer

  • Diagnose problems with the development environment installation

  • Optimize the development environment



Portal Frameworks and Portlet Services



  • Apply the Tagging and rating SPI

  • Creating a custom Portlet Service

  • Develop Login, Logout, and Session validation filters

  • Understand key Service Programming (SPI) and Application Programming Interfaces (API) #Controller SPI

    #Login Service SPI
    #Portal Model SPI
    #Portal User Management SPI (PUMA)
    #Property Broker SPI
    #Resource Addressability Framework (SPI)
    #Step Up Authentication SPI

  • Use Remember Me API to provide anonymous portlet content personalization +Use REST protocol to access SPI's



Portlet Development



  • Create cooperative portlets using live text Click-2-Action and Event broker

  • Demonstrate knowledge of core Java Portlet Objects in the JSR 286 spec

  • Demonstrate the differences between, events, render parameters, public render parameters, and scoped attributes

  • Describe the portlet life cycle for JSR-286

  • Effectively use JSPs to render portlet markup

  • Have knowledge of WSRP for JSR-286 portlets

  • Identify supported portlet modes and custom portlet modes

  • Implement portlet actions and events with Java 5 annotations

  • Understand portlet descriptor files for each portlet type and utilize WebSphere Portal extend features

  • Understand the use of Standard Portlet APIs

  • Use AJAX to update state and trigger actions with JSR-286 portlets

  • Use the portlet client model

  • Utilize client profile information (JSR-188)

  • Utilize of standard portlet cascading style-sheet classes



Testing, Debugging and Performance Monitoring of Portlets




Theme Development



  • Create a custom layout template and adding it to the shelf

  • Create a new style and add it to the shelf

  • How to register an iWidget and use in the shelf

  • How to use client side logging and tracing

  • How to use the Context menu framework

  • How to use the DND configuration object and add a custom DND source

  • Understand OneUI basics

  • Understand the bootstrapping process

  • Understand the theme.html

  • Use Dynamic Content Spots in theme templates

  • Use the DecorationsManager and understand the creation of a skin.html template

  • Use the navigation widgets and understand how to extend that widget

  • Use WebDAV to create and update themes



Additional Development Concepts



  • Assembling Composite Application Templates

  • Creating custom portal search interfaces

  • Developing Personalization Resources

  • Have knowledge of Portlet Bridge Frameworks

  • Search the Business Solutions catalog

  • Use the collaborative API

  • Using and extending the Credential Vault

  • Using the widgets for blogs and wikis

  • Using Web Content Management API's

  • Writing Personalization and Visibility Rules

Test LOT-910: IBM WebSphere Portal 7.0 Deployment and Administration Update

Architecting a Portal Solution



  1. Planning security and authentication concept - using step-up authentication and remember me cookie

  2. Understand management implications of setting up wikis and blogs

  3. Understand management implications of tagging and rating

  4. Understand new installation and topology options

  5. Multiple profiles

  6. Portal farms

  7. Portal in the cloud environment

  8. VMWare support



Understand the differences and advantages between Client Side Aggregation (CSA) and Server Side Aggregation (SSA)



  1. Customization and Administration

  2. Understand Portal usage analysis capabilities

  3. Use Portal search

  4. Utilize tagging and rating

  5. Working with WebDAV



Installation and Configuration



  1. Configure Portal light mode

  2. Setup portal farms

  3. Setup/configure (options) for wikis and blogs

  4. Understand portal coexistence (mixed versions) and install options

  5. Understand improvements to the installation wizard and when to use the wizard instead of commands

  6. Understand new ConfigEngine Options

  7. Understand where files are located after installation ( e.g, theme files in a new location)



Integrating Your Business



  1. Configure mashup integration including Understand how iWidgets are added to a page

  2. Understand options for backend application integration (Unified task list portlet, for example)



Maintain and Monitor



  1. Understand changes/enhancements in site management



Migration and Other Concepts



  1. Understand how to leverage feeds using WebSphere Portal including Configuring a proxy environment for feed syndication

  2. Understand WebSphere Portal migration concepts



Portal Content



  1. Understand changes in Customized Web Content authoring (Configure the authoring portlet)

  2. Understand changes in working with Web Content Libraries (Import/Export)

  3. Understand uses of Web content integration (WCI)

  4. Understanding how tagging and rating interacts with WebSphere Content Management
    Utilize Authortime Search



Security



  1. Understand Impersonation



Troubleshooting and Serviceability



  1. Understand conditions for which Portal will use Client Side Aggregation

  2. Understand conditions for which Portal will use Server Side Aggregation

WebSphere Portal 7.0 Application Developer certification is out

I was checking the IBM's certification web site and it looks like the certifications for IBM WebSphere Portal 7.0 are out now. You can find the objectives for developer test at Test LOT-915: IBM WebSphere Portal 7.0 Solution Development


It seems that now if you want to be IBM Certified WebSphere Portal Administrator and you dont have Admin certification for 6.1 version then you will have to clear following two certifications



But if your already IBM Certified Administrator for 6.1 like me then you can take Test LOT-910: IBM WebSphere Portal 7.0 Deployment and Administration Update

I already have some information about some of the objectives, you can find it here

Applying Global filter to all the portlets running in WPS

The WebSphere Application Server makes use of OSGi model for tying different pieces of application server together. One advantage of this approach is that even you can use the extension points to extend functionality of websphere application server

Before few days i was trying to build a Portlet Filter that can be applied to existing WebSphere Portlet Filter and Jerome suggested that i should use portlet global filter, that way i don't have to touch the existing portlet. So i tried that and it worked, to me it seems that Global Filter can be one of the most powerful tool in the portlet developers toolbox

I built this sample HelloGlobalFilter while i was trying to learn how to use Global Filter. This filter is very simple only thing that it does is calculate time spent in render() method of every portlet and prints that time along with WindowId, you can easily change it to create generic performance monitoring filter. You can download sample code from here

This is how my HelloGlobalFilter.java looks like

package com.webspherenotes.portlet.filter;

import java.io.IOException;

import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.filter.FilterChain;
import javax.portlet.filter.FilterConfig;
import javax.portlet.filter.RenderFilter;

public class HelloGlobalFilter implements RenderFilter{
public void destroy() {
System.out.println("Inside HelloGlobalFilter.destroy()");

}
public void init(FilterConfig arg0) throws PortletException {
System.out.println("Inside HelloGlobalFilter.init()");
}

public void doFilter(RenderRequest request, RenderResponse response,
FilterChain filterChain)
throws IOException, PortletException {
System.out.println("Entering HelloGlobalFilter.doFilter()");
long beginTime = System.currentTimeMillis();
filterChain.doFilter(request, response);
System.out.println("Window ID " + request.getWindowID() +" Time to execute render() "
+ (System.currentTimeMillis() - beginTime));
System.out.println("Exiting HelloGlobalFilter.doFilter()");

}

}


Developing HelloGlobalFilter is like developing any other standard compliant Portlet Filter. In this case i am implementing RenderFilter interface and then inside the doFitler() method i am calculating time spent by the portlet in executing. Once the HelloGlobalFilter is developed i had to copy it in the shared library so that it can be accessed by portal across application.

Last step is to create plugin.xml file like this

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin id="com.webspherenotes.hello.filter" name="WS_Server"
provider-name="IBM" version="2.0.0">
<extension point="com.ibm.ws.portletcontainer.portlet-filter-config">
<portlet-filter-config
class-name="com.webspherenotes.portlet.filter.HelloGlobalFilter" order="100">
<description> Hello Global Filter, order = 101 </description>
<lifecycle>RENDER_PHASE</lifecycle>
</portlet-filter-config>
</extension>
</plugin>


In this case i am using com.ibm.ws.portletcontainer.portlet-filter-config extension point for injecting my custom HelloGlobalFilter. I want to apply the filter only to the RENDER_PHASE and that's the reason for value of lifecycle element. Copy the plugin.xml file in the root of the HelloGlobalFilter.

Problem with enable client side logging

I followed the steps in Enable client side logging , to turn the client side logging on, but somehow the logs were not getting enabled, so i made changes in the WebSphere/PortalServer/theme/wp.mashup.cc.theme/installedApps/wp.mashup.cc.theme.ear/PageBuilder2.war/themes/html/PageBuilder2/configGlobal.jsp manually

I made changes to set value of isDebug to true and value of traceConfig to ["com.ibm.mm.iwidget.*"]

"isDebug": "true",
traceConfig: ["com.ibm.mm.iwidget.*"],


Then i could see the client side logging

Enable client side logging

WebSphere Portal 7.0 has lot of JavaScript code for Page Builder theme, for enabler API, for mashups, iWidgets,.. So if something goes wrong we will need a way to debug the problem on the client side. You can enable client side logging by following these steps


  • Login into WAS Admin console for WebSphere Portal server

  • Go to Resources -> Resource environment providers -> WP CommonComponentConfigService > Custom properties and set value of cc.isDebug property to true


  • Next step is to set trace string, which is same as that of the log trace string that we set for server side logging, but here you will have to set the traceConfig on the client side, setting set of packages for which you want to enable trace like this


  • Once the trace related properties are set verify them in the Admin COnsole like this


  • Save your changes and restart the server



Once the server is restarted you can view the log on the client side, if your using Firefox browser you can see the logs in the console view of Firebug like this




But if your using Internet explorer you will have to install Developer Tools and you can see the logs like this




Important Note: I am using WPS 7.0 and i followed the instructions in the Info center but somehow the trace was not getting enabled, so i did some manual changes to fix this problem

Using custom dynamic content spot in PageBuilder2 theme

Page Builder2 theme makes use of dynamic content spots, which are nothing but .jsp's that are included in theme.html. I wanted to see if i can create a custom dynamic content spot and include it in my theme so i tried these steps and it worked


  • First i did create a simple testds.jsp file, it looks like this

    <h3>This is sample text generated by testds.jsp</h3>

    I am just generating one h1 element inside the testds.jsp

  • Then i copied the testds.jsp file inside the /PortalServer/theme/wp.mashup.cc.theme/installedApps/wp.mashup.cc.theme.ear/PageBuilder2.war/themes/html/PageBuilder2 folder like this


  • Once your testds.jsp is copied into the PageBuilder2.war you have two options for including it in the theme.html, one is directly using the path to PageBuilder2 and second is using the dynamic content spot matching service

    <a rel="dynamic-content" href="res:/PageBuilder2/themes/html/PageBuilder2/testds.jsp"></a>

    <a rel="dynamic-content" href="dyn-cs:id:testds@tl:oid:csa2.theme"></a>


    In this the href="res:/PageBuilder2/themes/html/PageBuilder2/testds.jsp" is sample of how you can directly include the testds.jsp inside your theme.html, it does not require any further steps

    But if you dont want to hardcode path to testds.jsp in your theme.html then you can can create a mapping in the dynamic content spot mapping service and use the mapped name. In my case i did create mapping to testds name so i have to use dyn-cs:id:testds@tl:oid:csa2.theme as value of href

  • Next step is to create mapping that maps testds name to res:/PageBuilder2/themes/html/PageBuilder2/testds.jsp, you will have to use WAS Admin console





With mapping in place i copied my theme_en.html file to the nls folder and now when i try accessing the portal page i can see the testds.jsp getting included once because of direct .jsp reference and once because of content spot mapping reference like this




Important Note: After i copied testds.jsp in the PageBuilder2 theme i tried accessing theme.html and first it was throwing test.jsp not found error but then i did export of PageBuilder2.war and updated it and it started working, you might want to do same thing in ND environment.

Customizing Person card actions

You can use the theme to add items to the Person card's More actions menu in any portlet that uses the AJAX person tag. I wanted to try this feature and it seems that there is one error in the steps provided in Info center

  • First i had to add following code to the theme_en.html(theme_en.html is static html page used by PageBuilder2 theme to decide layout of the page), this code declares Test Action


    <div class="com.ibm.portal.action" style="display:none;">
    <span class="action-id">test.action1</span>
    <span class="action-impl">/javascript/TestAction.js</span>
    <span class="action-context">person</span>
    <span class="action-label">Test Action</span>
    <span class="action-description">This is a test for extending Person menu</span>
    <span class="action-showif">TestAction.showif</span>
    <span class="action-url">javascript:TestAction.execute(@@@ARGS@@@)</span>
    <span class="action-order">0</span>
    </div>


  • Next create TestAction.js file like this

    var TestAction = {
    showif: function(person) {
    return true;
    },
    execute: function(person) {
    alert("TestAction executed for: " + person.fn);
    }
    }

    The showif function gets called by the theme to decide if the TestAction should be displayed for persontag. I am returning true always, so the Test Action will always get displayed.

    The execute function will get called when user clicks on the Test Action. Here i am displaying alert with user name

  • As per Info center i can copy the TestAction.js in the JavaScript folder on webserver but it seems that part does not work,



    When i tried accessing the Person Tag, i could see that it was making a request to /wps_semanticTag/javascript/TestAction.js?language=en_US URL and that was failing so the Test Action did not get displayed.

  • I did some debugging to figure out what is happening and it seems that the logic related to read the com.ibm.portal.action micro-format is part of semanticTagService.js, there is JavaScript function which reads value of action-impl, which is /javascript/TestAction.js in my case adds /wps_semanticTag to it and includes that javascript using script tag in the page

    loadScript: function() {
    var scriptElem = document.createElement("script");
    var url = SemTagSvcPortal.connUrl;
    url += (url.indexOf("?")==-1)? "?": "&";
    url += "lang=" + SemTagSvcPortal.lang;
    scriptElem.src = url;
    document.body.insertBefore(scriptElem, document.body.firstChild);
    }

    Since i dont have anything in that directory it fails
  • So i spent some time trying to figure out which application is mapped to the /wps_semanticTag url and it seems that there is liveobjects.war file like this


    So i copied my TestAction.js to /software/IBM/WebSphere/PortalServer/ui/wp.tagging.liveobject/semTagEar/Live_Object_Framework.ear/liveobjects.war/javascript folder and tried again and now it works







YOu can also extend the person tag at portlet level by adding the <div class="com.ibm.portal.action" style="display:none;"> inside the portlet markup. I changed my persontag.jsp so that it looks like this

<%@page language="java" contentType="text/html; session="false"%>
<%@taglib prefix="person" uri="/WEB-INF/tld/people.tld"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model"
prefix="portlet-client-model"%>
<portlet-client-model:init>
<portlet-client-model:require module="ibm.portal.xml.*" />
<portlet-client-model:require module="ibm.portal.portlet.*" />
</portlet-client-model:init>
<portlet:defineObjects />

<h3>PersonTag Portlet</h3>

<person:person value="uid=sunil,o=defaultWIMFileBasedRealm" valueType="LDAPDN" displayName="Sunil Patil" /> <br/>
<person:person value="uid=jiya,o=defaultWIMFileBasedRealm" valueType="LDAPDN" displayName="Jiya Patil" />

<div class="com.ibm.portal.action" style="display:none;">
<span class="action-id">test.action2</span>
<span class="action-impl">/javascript/TestAction.js</span>
<span class="action-context">person</span>
<span class="action-label">Test Portlet Action</span>
<span class="action-description">This is a test for extending Person menu inside portlet</span>
<span class="action-showif">TestAction.showif</span>
<span class="action-url">javascript:TestAction.execute(@@@ARGS@@@)</span>
<span class="action-order">0</span>
</div>



Now when i try accessing the person tag i see Test Action contributed by theme.html and Test Portlet Action contributed by portlet, but the second menu shows up only when i access the persontag inside the portlet.

Using Person Tag inside custom portlet

The Collaborative Services include a JavaServer Page tag language descriptor (TLD) for a person tag. When added to your custom portlet, the person tag causes people's names to appear as hyperlinks, and the Click for Person Card option to display when the user moves the cursor over an active (underlined) person's name. Clicking this option displays the Person card. If WebSphere Portal cannot identify the person name, it displays the name as plain text and the Click for Person Card option is not available.

By default, the Person card includes the action Profile. The Send Mail action displays if the user has an e-mail address. If Lotus Sametime is installed and enabled to work with the portal, the person tag adds an icon that indicates the person's online status and additional actions:

I wanted to try this feature, so i used following steps

  • First you need to find out either EMAIL, LDAPDN or MembmerDN of the user that you want to display. In my local environment my portal is not integrated with LDAP, i am using default file based registry that ships with portal out of box. So first i checked the users that are available in the wp_profile/config/cells/localhost/fileregistry.xml




  • I have 3 users in my local file registry one is wasadmin, other is sunil and jiya. I wanted to display person tag for sunil and jiya so i created a persontag.jsp in my portlet like this

    <%@page language="java" contentType="text/html; session="false"%>
    <%@taglib prefix="person" uri="/WEB-INF/tld/people.tld"%>
    <%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
    <%@taglib
    uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model"
    prefix="portlet-client-model"%><portlet-client-model:init>
    <portlet-client-model:require module="ibm.portal.xml.*" />
    <portlet-client-model:require module="ibm.portal.portlet.*" />
    </portlet-client-model:init>
    <portlet:defineObjects />

    <h3>PersonTag Portlet</h3>

    <person:person value="uid=sunil,o=defaultWIMFileBasedRealm" valueType="LDAPDN"
    displayName="Sunil Patil"></person:person> <br/>
    <person:person value="uid=jiya,o=defaultWIMFileBasedRealm" valueType="LDAPDN"
    displayName="Jiya Patil"></person:person>


    First you will have to include /WEB-INF/tld/people.tld tag library in the JSP and then you can use the person:person tag to display name of the person as person tag. I am using hard coded names to keep it simple but you can easily mix it with PUMA API

  • Once the portlet is deployed you can add it on a page and when you take your move on person's name it will display "Click for person Card" context menu, when you click on the menu, that person's card would be displayed like this


Code generated by client model init tags

If you want to use the Enabler API in your portlet then you will have to include following code at the top of the JSP


<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model"
prefix="portlet-client-model"%>

<portlet-client-model:init>
<portlet-client-model:require module="ibm.portal.xml.*" />
<portlet-client-model:require module="ibm.portal.portlet.*" />
</portlet-client-model:init>


These JSP tags generate following code into your markup

<script>
if(typeof dojo=='undefined') {
document.writeln("<scr"+"ipt src='/wps/themes/dojo/portal_dojo/dojo/dojo.js' ></scr"+"ipt>");
}
</script>
<script>
dojo.require('ibm.portal.xml.xpath');
dojo.require('ibm.portal.xml.xslt');
</script>
<script>
dojo.require('ibm.portal.portlet.portlet');
</script>
<script>
if(typeof(ibmPortalConfig) == "undefined") {
ibmPortalConfig = {contentHandlerURI: "wsrp_rewrite"};
} else if(!ibmPortalConfig["contentHandlerURI"]) {
ibmPortalConfig["contentHandlerURI"] = "wsrp_rewrite";
}
</script>
<div id="com.ibm.wps.web2.portlet.root.Z7_OGFLMKG100AE00IQD0B8FL3042"
style="display: none;">
http://192.168.117.132:10039/wps/mycontenthandler/!ut/p/digest!Mm2hqcemQRtdiuTGl0RuBg/pm/oid:--portletwindowid--@oid:Z6_OGFLMKG100F610IAJQLHQ800G1
</div>
<div id="com.ibm.wps.web2.portlet.preferences.Z7_OGFLMKG100AE00IQD0B8FL3042" style="display: none;"
pageid="Z6_OGFLMKG100F610IAJQLHQ800G1" configid="Z3_OGFLMKG100AE00IQD0B8FL3081" editdefaultsid="Z5_OGFLMKG100AE00IQD0B8FL3046">
</div>
<div id="com.ibm.wps.web2.portlet.user.Z7_OGFLMKG100AE00IQD0B8FL3042" style="display: none;">
http://192.168.117.132:10039/wps/mycontenthandler/!ut/p/digest!Mm2hqcemQRtdiuTGl0RuBg/um/secure/currentuser/profile?expandRefs=true
</div>


The code takes care of first including dojo on page, if its not loaded already then it includes dojo related classes and then it generates couple of hidden div's that has values of portlet Window Id and page id. Then it generates URls which can be used for getting ATOM feed
http://192.168.117.132:10039/wps/mycontenthandler/!ut/p/digest!Mm2hqcemQRtdiuTGl0RuBg/pm/oid:Z7_OGFLMKG100AE00IQD0B8FL3042@oid:Z6_OGFLMKG100F610IAJQLHQ800G1 url can be used for getting ATOM feed for the current portlet and the http://192.168.117.132:10039/wps/mycontenthandler/!ut/p/digest!Mm2hqcemQRtdiuTGl0RuBg/um/secure/currentuser/profile?expandRefs=true URL can be used for getting ATOM feed for the current user's profile

What is enabler API

WebSphere Portal, has introduced Enabler API in Version 7.0, The Enabler API is replacement of Client Side API that was part of the 6.x version. The Enabler API allows you to do following things on client side


  • Manipulate portlet preferences

  • Manipulate user profile

  • Manipulate portlet state

    • Portlet Mode

    • Window State





The Enabler API provides functions that are equivalent to the Portlet client side API and there is one set of functions that can be used from iWidget and other set that can be used from portlet code.

Ex. In WPS 6.0 this is how we use to set portlet preferences

var _portletWindow = new ibm.portal.portlet.PortletWindow("<%=portletWindowID%>");
_portletWindow.getPortletPreferences(setPreference);
function setPreference(){
portletPrefs.setValue(preferenceName,preferenceValue);
portletWindow.setPortletPreferences(portletPrefs,printPreferencesCallback);
}


But now you will have to use code like this inside the Portlet

var navigationModel = com.ibm.mashups.enabler.navigation.Factory.getNavigationModel();
var selectedNode = navigationModel.find().start();
var layoutModel = navigationModel.getLayoutModel(selectedNode);
var layoutControl = layoutModel.find().start();
var widgetInstance = widgetModel.getWidgetWindow(layoutControl).start();

// set preferences
var modifiablePreferences = widgetModel.getHierarchicalPreferences(widgetInstance).start();
modifiablePreferences.setValues(key, values);

// commit
this.widgetModel.commit().start();


This is the code that you can use inside the iWidget

var result = iContext.getiWidgetAttributes();
result.setItemValue(itemName, itemValue);


Important Note: IBM deprecates the client side programming model from the previous versions. Although the old model still works, developers are encouraged to write new code to comply with the new Enabler APIs. with the old API.

Modify title, metadata properties of page using WebDav client

WPS 7.0 provides one more option for managing your portal pages, which is WebDav. Every portal page is not represented as folder in your WebDav.



On my local the Home -< Fun folder has 5 pages so when i go to corresponding folder in WebDav i see 5 folders. Name of the folder is either ObjectId or unique name. If i go inside a folder that represents a portal page this is what i see




  • localized_en.properties: This is properties file that has value of title and description for the page

  • metadata.properties This file represents the meta data for the page

  • staticcontent: This folder has information about the static content, such as layout.html and option to change the value



This is how the localized_en.properties file for my page looks like, if i change this file and save it using WebDav those changes get stored in the portal database. Ex. I can rename the portal page by changing value of title property in this file


description= Test PageBuilder 2 theme description
title=Test PageBuilder2 Theme


If you want to change any page level meta data values such as caching related data or template file name then you can open metadata.properties file change the corresponding value and save it back. This is how the metadata.properties file for my sample page looks like

com.ibm.portal.bookmarkable=Yes
com.ibm.portal.feed.remote-cache-expiry=86400
com.ibm.portal.layout.template.expiration=1285007105961
com.ibm.portal.IgnoreAccessControlInCaches=false
com.ibm.portal.layout.template.file.name.html=layout.html
com.ibm.portal.remote-cache-expiry=86400
com.ibm.portal.layout.template.ref=dav\:fs-type1/layout-templates/2ColumnEqual/
com.ibm.portal.layout.template.markup=html
com.ibm.portal.layout.template.lastmodified=1285007107434
com.ibm.portal.static.page.file.name.html=layout.html
com.ibm.portal.remote-cache-scope=NON-SHARED

Using WebDAV to manage portal pages

The WebSphere Portal 7.0 allows you to manage portal pages using the WebDav tool. It allows you to do following things


  • Browse through the page hierarchy. Each portal page is represented as a folder. The name of the folder is the unique name or the object ID of the page. Children pages in the topology are represented as subfolders.

  • Change globalization information of pages. To do this, users edit and save properties files that contain the globalization information.

  • Change metadata of pages. To do this, users edit and save properties files that contain the metadata information.

  • For static pages, you can browse, read, create, update, save, copy, move, and delete static content. Users can access the content of static pages via the subfolder staticcontent .

  • Delete pages.



I wanted to try this feature so first i created a WebDav connection to the http://localhost:10039/wps/mycontenthandler/dav/contentmodel/wps.content.root url like this



Once the connection is established i can see all the pages in my portal in the directory format. This is screen shot of my portal page which displays all the pages at the Content Root level



This is how they are represented in the WebDav repository. There is a folder corresponding to every portal page and lable. If you drill down in the folder you will notice there is folder corresponding to every child page,..

Working with PageBuilder2 theme .html, theme.html, skin.html

For last few days i was struggling to figure out how to modify theme.html and finally i got help from my colleagues Evan and Sanjay and now i am able to modify markup generated for theme.html. Take a look at the screen shot, i did add <h1>This is test modification in theme.html</h1> as first element to the body tag



You will have to use following steps to get it working


  • First of all create WebDav connection to /wps/mycontenthandler/dav/fs-type1 URL, this is the URL that you should use. It seems that http://localhost:10039/wps/mycontenthandler/dav/themelist url is not a valid URL for WebDav, it will keep throwing some weired error


  • Once your WebDav connection is established go to themes/PageBuilder2 folder, you will find a theme.html file here and there is locale specific version of theme.html in nls folder. I tried changing the theme.html in PageBuilder2 folder but somehow it never gets picked up instead portal always picks up locale specific version from nls folder



  • Make changes in theme.html and save those changes, if your using WebDav client(WebFolders, BitKinex) on Windows, first you will have to copy the file to local machine, modify it and then copy it back






Once your changes are updated you can refresh the page and you should be able to see the modified markup