Previous Page | Next Page

Sample Portlets

SampleRemote: Remote Portlet


Overview: Steps for Creating the SampleRemote Portlet

SampleRemote is a remote portlet that calls a Web application. The Web application displays the string Hello user , where user is the name of the user who is logged on to the SAS Information Delivery Portal. It also displays text that the user can edit.

To create the SampleRemote portlet, follow these steps:

  1. Create portlet configuration and source directories.

  2. Create the enterprise application deployment descriptor (application.xml).

  3. Create the Web application deployment descriptor (web.xml).

  4. Create the Spring framework configuration file (infrastructure-config.xml).

  5. Create the display pages for the Web application (Viewer.jsp, Editor.jsp, Error.jsp, and Help.jsp).

  6. Create the controller servlet class (ControllerServlet.java).

  7. Create the portlet deployment descriptor (portlet.xml).

  8. Create a title and description for the portlet.

  9. Compile the remote portlet.

  10. Create the EAR and PAR files and deploy and test the portlet.

Note:   Before you begin developing the SampleRemote portlet, ensure that the SAS Metadata Server is running so that metadata can be accessed during the configuration and deployment processes.  [cautionend]


Step 1: Create the Portlet Configuration and Source Directories

Follow these steps to create a source directory structure for building the portlet:

  1. Create a configuration directory for the portlet named SampleRemote under the SAS-configuration-directory/Lev1/CustomAppData directory. This directory is referred to as portlet-configuration-directory in the code and descriptions for this portlet.

  2. Copy the contents of the testportlet directory to the SampleRemote directory.

  3. Create a source code directory for the portlet named Source under the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory. This directory is referred to as portlet-source-directory in the code and descriptions for this portlet.

  4. Edit the custom.properties file in the SampleRemote directory as follows:

    Note:   Be sure to substitute the full pathnames from the steps above in the install.currprod.config.dir= and testportlet.install.dir= argument values.  [cautionend]

    # If you change the value "testportlet", make sure to rename in all properties 
    # here as well as in the custom_config.xml.
    config.currprod.12byte=testportlet
    
    # Change the value of this property to be the name of your web application.
    config.currprod.legalname=Remote Portlet Sample
    
    # The value of this property should be the location where the configuration 
    # files are placed.  Make sure to change the level directory based on your 
    # installation and make sure to rename testportlet if the value of 
    # config.currprod.12byte changes above.
    install.currprod.config.dir=port-configuration-directory
    
    # Do not change the value of this property.  The name might be changed if you 
    # change the value of config.currprod.12byte above.
    webappsrv.testportlet.server=server
    
    # Change the value of this property to be the location of your portlet's source 
    # code and configuration files.  The name might be changed if you change the 
    # value of config.currprod.12byte above.
    testportlet.install.dir=portlet-source-directory
    
    # Change the value of this property to be the name of you par, war, and ear 
    # file.  The name might be changed if you change the value of 
    # config.currprod.12byte above.
    webapp.testportlet.archive.name=sample.remote
    
    # Change the value of this property to be the context root of your web 
    # application and the name of the portlet.  The name might be changed if you 
    # change the value of config.currprod.12byte above.
    webapp.testportlet.contextroot=SampleRemote
    
    # Change the value of this property to be the versioned name of your web 
    # application.  This property is only used for remote portlets.  The name might 
    # be changed if you change the value of config.currprod.12byte above.
    webapp.testportlet.display.name=Remote Portlet Sample

  5. From the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory, run the following configuration script to create the source directory structure for building the portlet:

    cfg createRemotePortletDirectories -Dmetadata.connection.passwd="password"

    For the password value, you must supply the unrestricted user password for your SAS installation.

    Note:   You can specify the password either in clear text or in encoded form. For information about generating the encoded form, see "The PWENCODE Procedure" in Encryption in SAS.  [cautionend]

  6. Review the customconfig.log file in the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory to determine whether any errors occurred.


Step 2: Create the Enterprise Application Deployment Descriptor

Java Enterprise (J2EE) applications are deployed in the form of enterprise archive (EAR) files. An enterprise application deployment descriptor file describes the Web projects and other components that comprise an EAR file. The following example shows the contents of the enterprise application deployment descriptor file for the SampleRemote portlet:

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/j2ee" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                http://java.sun.com/xml/ns/j2ee/application_1_4.xsd"
             version="1.4">
    <display-name>@webapp.testportlet.contextroot@</display-name>
    <description>@webapp.testportlet.display.name@</description>
    <module>
        <web>
            <web-uri>@webapp.testportlet.archive.name@.war</web-uri>
            <context-root>@webapp.testportlet.contextroot@</context-root>
        </web>
    </module>
</application>

Store this text in a file named application.xml.orig in the portlet-source-directory/Configurable/ears/sample.remote/META-INF directory. The testportlet scripting facility performs name/value pair substitution on this file to produce the application.xml file.

The EAR file must also contain a manifest file that specifies information about the files packaged in the EAR. The SampleRemote portlet uses the following manifest file:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 1.5.0_12-b04 (Sun Microsystems Inc.)

Store this text in a file named MANIFEST.MF in the portlet-source-directory/Static/ears/sample.remote/META-INF directory.

Note:   This file is placed in the /Static directory hierarchy rather than the /Configurable directory hierarchy because no substitution is required.  [cautionend]


Step 3: Create the Web Application Deployment Descriptor

The Web application deployment descriptor is an XML file that describes the Web application's initialization parameters, servlets, and other components. The following example shows the contents of the deployment descriptor file for the SampleRemote portlet's Web application. For more information about creating Web application deployment descriptors, see the documentation for your servlet container.

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="@webapp.testportlet.contextroot@" version="2.4" 
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
                        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-config/infrastructure-config.xml</param-value>
    </context-param>
    <context-param>
        <param-name>locatorFactorySelector</param-name>
        <param-value>classpath:beanRefContext.xml</param-value>
    </context-param>
    <context-param>
        <param-name>parentContextKey</param-name>
        <param-value>config.context</param-value>
    </context-param>

    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.sas.servlet.filters.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>PortletSecurityFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>portletSecurityFilter</param-value>
        </init-param>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>trusted.url</param-name>
            <param-value>Logoff</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>WIPPlatformServicesFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>platformServicesFilter</param-value>
        </init-param>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>RemotePortletFilter</filter-name>
        <filter-class>com.sas.portal.portlet.remote.RemotePortletFilter
        </filter-class>
        <init-param>
            <param-name>allow-webapp-mode</param-name>
            <param-value>false</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>PortletSecurityFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>WIPPlatformServicesFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>RemotePortletFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <listener>
        <listener-class>com.sas.common.components.SpringComponentFacade
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>logoff</servlet-name>
        <servlet-class>com.sas.svcs.webapp.servlet.DelegatingServletProxy
        </servlet-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>logoffServlet</param-value>
        </init-param>
    </servlet>
    <servlet>
        <servlet-name>ControllerServlet</servlet-name>
        <servlet-class>sample.remote.ControllerServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>logoff</servlet-name>
        <url-pattern>/Logoff</url-pattern>
    </servlet-mapping>  
    <servlet-mapping>
        <servlet-name>ControllerServlet</servlet-name>
        <url-pattern>/Controller</url-pattern>
    </servlet-mapping>

    <session-config>
       <session-timeout>30</session-timeout>
    </session-config>
</web-app>

Store this Web application deployment descriptor source text in a file named web.xml.orig in the portlet-source-directory/Configurable/wars/sample.remote/WEB-INF directory. The testportlet scripting facility performs name/value pair substitution on this file to produce the web.xml file.

The following files provide additional settings for Web application servers. For more information about configuring Web application servers, see SAS Intelligence Platform: Web Application Administration Guide.

<?xml version="1.0" encoding="UTF-8" ?>
<jboss-web>
    <security-domain>java:/jaas/PFS</security-domain>
    <context-root>@webapp.testportlet.contextroot@</context-root>
</jboss-web>

Store this text in a file named jboss-web.xml.orig in the portlet-source-directory/Configurable/wars/sample.remote/WEB-INF directory. The testportlet scripting facility performs name/value pair substitution on this file to produce the jboss-web.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/90" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <jsp-descriptor>
        <jsp-param>
            <param-name>page-check-seconds</param-name>
            <param-value>-1</param-value>
        </jsp-param>
    </jsp-descriptor>
    <container-descriptor>
        <servlet-reload-check-secs>-1</servlet-reload-check-secs>
        <prefer-web-inf-classes>true</prefer-web-inf-classes>
    </container-descriptor>
    <context-root>@webapp.testportlet.contextroot@</context-root>
</weblogic-web-app>

Store this text in a file named weblogic-web.xml.orig in the portlet-source-directory/Configurable/wars/sample.remote/WEB-INF directory. The testportlet scripting facility performs name/value pair substitution on this file to produce the weblogic-web.xml file.


Step 4: Create the Spring Framework Configuration File

The Web application for the SampleRemote portlet uses the open-source Spring J2EE application development framework. An infrastructure configuration file defines the Spring framework components that are used in the application. The following example shows the infrastructure configuration file for the SampleRemote portlet. For more information about the Spring framework, see http://www.springsource.org.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans    
           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
  
    <!-- Public ids provided as a part of these files are: 
         sas.framework.commons.jar: configurationService, urlGenerator 
         sas.framework.themes.jar: themeService 
         sas.svcs.mail.client.jar: mailService 
         sas.svcs.directives.client.jar: directivesService 
         sas.svcs.security.client.jar: authenticationService, userValidationService 
         sas.svcs.userinfo.client.jar: userInfoService 
         sas.svcs.status.client.jar: capabilityVerification, systemValidationService 
         Each of these depends on an id defined elsewhere for sas.svcs.cache.
    -->
    <import resource="classpath*:META-INF/wip-services-client-config.xml" />
    <import resource="classpath*:META-INF/spring-config/aop-config.xml" />
    <import resource="classpath*:META-INF/spring-config/data-config.xml" />
    <import resource="classpath*:META-INF/spring-config/webapp-config.xml" />
    <import resource="classpath*:META-INF/spring-config/presentation-config.xml" />
    <import resource="classpath*:META-INF/spring-config/jps-config.xml" />
    <import resource="classpath*:META-INF/spring-config/portlet-config.xml" />
</beans>

Store this text in a file named infrastructure-config.xml in the portlet-source-directory/Static/wars/sample.remote/WEB-INF/spring-config directory.


Step 5: Create the Display Pages for the Web Application

The Web application for the SampleRemote portlet has the following JSP pages:

Viewer.jsp

is the presentation component of the portlet.

Editor.jsp

is the presentation component of the editor action.

Error.jsp

displays messages for errors that occur during the editing process.

Help.jsp

displays help information for the portlet.


Create the Viewer.jsp Page

The following example shows the code for the Viewer JSP page, which is the presentation component of the SampleRemote portlet:

<%-- Copyright (c) 2009 by SAS Institute Inc., Cary, NC 27513 --%>
<%@ page language="java" contentType="text/html; charset=UTF-8" %> 
<%@ page import="com.sas.portal.portlet.NavigationUtil" %>
<%@ page import="com.sas.portal.portlet.RemotePortletContext" %>
<%@ page import="com.sas.portal.portlet.remote.RemotePortletToolkitUtil" %>
<%@ page import="com.sas.services.user.UserContextInterface" %>
<%@ page import="com.sas.web.keys.CommonKeys" %>
<%@ page import="com.sas.webapp.contextsharing.WebappContextParams" %>
<%@ page import="sample.remote.ControllerServlet" %>

<%
try {
   // Get the Remote User Context Information
   UserContextInterface uc =
      (UserContextInterface) session.getAttribute(CommonKeys.REMOTE_USER_CONTEXT);

   // Determine the Display Name of the user (Remote User Context).
   String user = uc.getPerson().getDisplayName();

   RemotePortletContext pcontext =
      RemotePortletToolkitUtil.getRemotePortletContext(request);
   String pid = pcontext.getId();
   String param_name = "sample.param." + pid;
   String param_value = (request.getParameter(param_name) == null) ?  "" : "checked";
   String submiturl = NavigationUtil.buildBaseURL(pcontext, request, "formsubmit");
%>

<p>This remote portlet supports view mode, edit mode,and help mode.</p>

<p>Hello <%= user %>.</p>

<p>Data value: <%= session.getAttribute(ControllerServlet.DATA_KEY1 + pid) %></p>

<form method="post" action="<%= submiturl %>">
  <input name="<%= param_name %>" type="checkbox" <%= param_value %> />
  <%= param_name %>
  <br />  
  <button type="submit">Submit</button>
</form>

<%
} catch (Throwable thr1) {
    thr1.printStackTrace();
}
%>

Store this JSP code in a file named Viewer.jsp in the portlet-source-directory/Static/wars/sample.remote/jsp directory.


Create the Editor.jsp Page

The following example shows the code for the Editor JSP page, which is the presentation component of the editor for the SampleRemote portlet:

<%@ page language="java" contentType="text/html; charset=UTF-8" %> 
<%@ page import="com.sas.portal.portlet.RemotePortletContext" %>
<%@ page import="com.sas.portal.portlet.remote.RemotePortletToolkitUtil" %>
<%@ page import="sample.remote.ControllerServlet" %>

<%
    RemotePortletContext pcontext =
       RemotePortletToolkitUtil.getRemotePortletContext(request);
    String pid = pcontext.getId();
%>

<table border="0" cellpadding="2" cellspacing="0" align="center" width="100%">
  <tr>
    <td colspan="3"> </td>
  </tr>
  <tr>
    <td> </td>
    <td nowrap align="center">Edit Page</td>
    <td> </td>     
  </tr>
  <tr>
    <td colspan="3"> </td>
  </tr>
  <tr>
    <form method="post"
          action="<%= request.getAttribute(ControllerServlet.EDIT_OK) %>" 
          accept-charset="UTF-8">
    <td> </td>
    <td> <table border="0" cellpadding="0" cellspacing="0" align="center">
      <tr>
        <td class="celljustifyright" nowrap>Input:</td>
        <td> </td> 
        <td class="celljustifyleft" nowrap>
          <input type="text" name="<%= ControllerServlet.EDIT_FIELD1 %>" 
              value="<%= session.getAttribute(ControllerServlet.DATA_KEY1 + pid) %>"
              size="25">
        </td>   
      </tr>
      <tr>
        <td colspan="3"> </td>
      </tr>
      <tr>
        <td class="celljustifyright">
          <input class="button" type="submit" value="Ok" name="submit" >
    </form>
        </td>
        <td> </td>
        <td class="celljustifyleft">
          <form method="post"
                action="<%= request.getAttribute(ControllerServlet.EDIT_CANCEL) %>"
                accept-charset="UTF-8">
          <input class="button" type="submit" value="Cancel" name="submit" >
          </form>
        </td>
      </tr>
      </table>
    </td>
  </tr>
</table>

Store this JSP code in a file named Editor.jsp in the portlet-source-directory/Static/wars/sample.remote/jsp directory.


Create the Error.jsp Page

The following example shows the code for the Error JSP page, which displays messages for any errors that occur during the editing process:

<%@ page language="java" contentType= "text/html; charset=UTF-8" %>
<%@ page import="sample.remote.ControllerServlet" %>

<h1>Error</h1>
<p><%= request.getAttribute(ControllerServlet.ERROR_MESSAGE) %></p>

Store this JSP code in a file named Error.jsp in the portlet-source-directory/Static/wars/sample.remote/jsp directory.


Create the Help.jsp Page

The following example shows the code for the Help JSP page, which displays text to help the user understand how to use the portlet:

<%@ page language="java" contentType= "text/html; charset=UTF-8" %>
<%@ page import="com.sas.portal.portlet.RemotePortletContext" %>
<%@ page import="com.sas.portal.portlet.remote.RemotePortletToolkitUtil" %>
<%@ page import="sample.remote.ControllerServlet" %>

<%
try {
    RemotePortletContext pcontext =
       RemotePortletToolkitUtil.getRemotePortletContext(request);
    String pid = pcontext.getId();
%>

<h1>Portlet Help</h1>
<p>Portlet ID: <%= pid %></p>
<p>This is where portlet help would be displayed</p>

<%
} catch (Throwable thr1) {
    thr1.printStackTrace();
}
%>

Store this JSP code in a file named Help.jsp in the portlet-source-directory/Static/wars/sample.remote/jsp directory.


Step 6: Create the Controller Servlet Class

The SampleRemote portlet has its own class, ControllerServlet, to support the actions of the JSP pages for the application. The following example shows the source code for the ControllerServlet class.

Note:   This example uses the remote user context to obtain application metadata. This is the simplest way for a remote portlet to obtain metadata, but it has a negative effect on performance because Java objects execute in the remote services JVM rather than locally. For more information about remote contexts, see Obtaining a User and Session Context  [cautionend]

package sample.remote;

import com.sas.portal.portlet.NavigationUtil;
import com.sas.portal.portlet.PortletContext;
import com.sas.portal.portlet.RemotePortletContext;
import com.sas.portal.portlet.remote.RemotePortletToolkitUtil;
import com.sas.services.session.SessionContextInterface;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class ControllerServlet extends HttpServlet {
    /* Request attribute key for the error screen error message */
    public static final String ERROR_MESSAGE = "sample.remote.errormessage";

    /* Request attribute key for the edit screen Ok button URL */
    public static final String EDIT_OK = "sample.remote.editok.url";

    /* Request attribute key for the edit screen Cancel button URL */
    public static final String EDIT_CANCEL = "sample.remote.editcancel.url";

    /* Name of field1 input parameter */
    public static final String EDIT_FIELD1 = "sample.remote.editfield1.name";

    /* Attribute name for persistent storage of string entered during edit mode */
    public static final String DATA_KEY1 = "sample.remote.key1.";

    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException
    {
        processRequest(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException
    {
        processRequest(request, response);
    }

    public boolean processRequest(HttpServletRequest request,
       HttpServletResponse response) 
          throws ServletException
    {
        String data;

        try {
            // If there are multiple instances of the same remote portlet in a
            // users portal session, they will use the same HttpSession. This
            // requires session attributes to be namespaced.
            HttpSession session = request.getSession();
            ServletContext servletContext = getServletConfig().getServletContext();

            // Check for logoff notification before doing anything else. Multiple
            // portlet instance can have information stored in the HttpSession,
            // but the logoff request will only be processed once. Use of an
            // HttpSessionBindingListener is recommended if resources need to be
            // cleaned up when the session is invalidated.
            if (RemotePortletToolkitUtil.isLogoffRequest(request)) {
                session.invalidate();
                return false;
            }

            // Retrieve the remote portlet context that is needed to process
            // the request.
            RemotePortletContext pcontext =
               RemotePortletToolkitUtil.getRemotePortletContext(request);
            if (pcontext == null) {
                // If there is no remote portlet context, goto error page.
                request.setAttribute(ERROR_MESSAGE, "No remote portlet context");
                RequestDispatcher rd =
                   servletContext.getRequestDispatcher("/jsp/Error.jsp");
                rd.forward(request, response);
                return false;
            }

            // The portlet id is uniquely identifies a portlet instance.
            String pid = pcontext.getId();

            // A remote portlet does not have access to the portlet Configuration
            // object, so it is responsible for persisting data. This codes uses
            // the HttpSession to cache data, but does not implement a persistent
            // store.
            if (session.getAttribute(DATA_KEY1 + pid) == null)
                session.setAttribute(DATA_KEY1 + pid, "initial state");

            String jspurl = null;
            String action = RemotePortletToolkitUtil.getAction(request, pcontext);

            if (action.equalsIgnoreCase(RemotePortletToolkitUtil.PAGE_REFRESH_ACTION)
                || action.equalsIgnoreCase("default")) {
                // This portlet was called with either the default action or
                // no action. Both indicate a page refresh.
                jspurl = "/jsp/Viewer.jsp";
            } else if (action.equalsIgnoreCase("urlsubmit")) {
                // This is where the portlet would process submit parameters.

                // When finished processing, redisplay.
                jspurl = "/jsp/Viewer.jsp";
            } else if (action.equalsIgnoreCase("formsubmit")) {
                // This is where the portlet would process submit parameters.

                // When finished processing, redisplay.
                jspurl = "/jsp/Viewer.jsp";
            } else if (action.equalsIgnoreCase("startedit")) {
                // Start edit mode.

                // The following call resets the portlet mode back to
                // display mode when the submit URL is issued and thus
                // needs to be called before NavigationUtil.buildBaseURL
                pcontext.resetMode();

                //Create the URLs for the OK and Cancel buttons.
                String submiturl =
                   NavigationUtil.buildBaseURL(pcontext, request, "endedit");
                request.setAttribute(EDIT_OK, submiturl);
                request.setAttribute(EDIT_CANCEL, submiturl);

                jspurl = "/jsp/Editor.jsp";
            } else if (action.equalsIgnoreCase("endedit")) {
                // Exit edit mode

                String submitAction = request.getParameter("submit");
                if ((submitAction != null)
                     && submitAction.equalsIgnoreCase("Ok")) {
                    // This is where you would add code to persist changes and
                    // update your model.
                    data = request.getParameter(EDIT_FIELD1);
                    session.setAttribute(DATA_KEY1 + pid, data);
                }

                // When finished processing, redisplay.
                jspurl = "/jsp/Viewer.jsp";
            } else if (action.equalsIgnoreCase("help")) {
                // Help mode.

                jspurl = "/jsp/Help.jsp";
            } else {
                // An error occurred.
                request.setAttribute(ERROR_MESSAGE,
                   "Unknown portlet action: " + action);
                jspurl = "/jsp/Error.jsp";
            }

            RequestDispatcher rd = servletContext.getRequestDispatcher(jspurl);
            rd.forward(request, response);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new ServletException(ex);
        }

        return true;
    }

}

Create a directory named sample under the portlet-source-directory/Static/wars/sample.remote/source directory, and then create a directory named remote under the portlet-source-directory/Static/wars/sample.remote/source/sample directory. Store the class source code in a file named ControllerServlet.java in the portlet-source-directory/Static/wars/sample.remote/source/sample/remote directory.


Step 7: Create the Portlet Deployment Descriptor

The portlet deployment descriptor is an XML file that provides all of the information that the SAS Information Delivery Portal needs to deploy one or more portlets. The following example shows the contents of the portlet deployment descriptor file for the SampleRemote. For more information about portlet deployment descriptor files, see Creating a Portlet Deployment Descriptor.

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

 Note about code
<!DOCTYPE portlets SYSTEM "http://www.sas.com/idp/portlet.dtd">
<portlets>
 Note about code
   <remote-portlet name="@webapp.testportlet.contextroot@"
                   title="@webapp.testportlet.display.name@" 
                   passContextId="true" editorType="portlet"
                   showEditProperties="true">

      <localized-resources locales="en" />

      <deployment scope="user" autoDeploy="false" userCanCreateMore="true" />

      <portlet-path>/sample/portlets/remote</portlet-path>
 Note about code
      <portlet-actions>
         <portlet-action name="default" default="true">
             <url>@javaportal.url@@webapp.testportlet.contextroot@/Controller</url>
         </portlet-action>

         <portlet-action name="startedit" editor="true">
             <url>@javaportal.url@@webapp.testportlet.contextroot@/Controller</url>
         </portlet-action>

         <portlet-action name="endedit">
             <url>@javaportal.url@@webapp.testportlet.contextroot@/Controller</url>
         </portlet-action>

         <portlet-action name="help" help="true">
             <url>@javaportal.url@@webapp.testportlet.contextroot@/Controller</url>
         </portlet-action>

         <portlet-action name="logoff" remote-logoff="true">
             <url>@javaportal.url@@webapp.testportlet.contextroot@/Controller</url>
         </portlet-action>

      </portlet-actions>
   </remote-portlet>
</portlets>

Store this portlet deployment descriptor source text in a file named portlet.xml.orig in the portlet-source-directory/Configurable/pars/sample.remote directory. The testportlet scripting facility performs name/value pair substitution on this file to produce the portlet.xml file.


Step 8: Create a Title and Description for the Portlet

The SampleRemote portlet uses a display resources file to provide a description that is placed in the portlet's metadata for display to users. If this file is not provided, the portal creates a default description based on the portlet's name. For more information about display resources files, see Creating Display Resources Files.

For the SampleRemote portlet, create a display resources file with the following content:

portlet.title=Remote Portlet Sample 
portlet.description=Remote Portlet Sample

Store this text in a file named portletDisplayResources.properties in the portlet-source-directory/Static/pars/sample.remote/SampleRemote/classes directory.


Step 9: Compile the Remote Portlet

The action class that was defined in Step 6 must be compiled before the portlet can be used. SAS 9.2 uses a Versioned JAR Repository to manage the JAR files that ship with SAS products. The testportlet scripting facility integrates with the Versioned JAR Repository by requiring a picklist to define which JAR files are used for compiling the portlet and building the WAR file. If your portlet requires additional JAR files, they must also be added to the picklist.

Follow these steps to compile the SampleRemote portlet:

  1. Create a picklist for this sample portlet. As a starting point, copy the SAS Information Delivery Portal picklist file from the SAS-installation-directory/SASInformationDeliveryPortal/4.2/Picklists/wars/sas.portal directory into the portlet-source-directory/Picklist/wars/sample.remote directory.

    Note:   After a SAS maintenance release is applied at your site, you must copy the updated picklist file and repeat the building and deploying of PAR and EAR files for all custom portlets.  [cautionend]

  2. Copy any custom or third-party JAR files that are not defined in the SAS picklist but that are needed to compile the custom portlet into the portlet-source-directory/Static/lib directory. For this sample portlet, you must copy the file named servlet-api.jar that ships with the application server into the portlet-source-directory/Static/lib directory.

  3. From the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory, run the configuration script with the following arguments to compile the Java class:

    cfg compileRemotePortlet -Dmetadata.connection.passwd="password"

    For the password value, you must supply the unrestricted user password for your SAS installation.

    Note:   You can specify the password either in clear text or in encoded form. For information about generating the encoded form, see "The PWENCODE Procedure" in Encryption in SAS.  [cautionend]

  4. Review the customconfig.log file in the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory to determine whether any errors occurred.


Step 10: Create the EAR and PAR Files and Deploy and Test the Portlet

The last step in developing the SampleRemote portlet is to archive its files into EAR and PAR files and deploy the Web application and the new portlet. For a remote portlet, the EAR file includes all of the Web application's supporting files, including the files created in Steps 2 through 6. The PAR file contains the portlet definition created in Steps 7 and 8. To create the EAR and PAR files and deploy the Web application and the portlet, follow these steps:

  1. Stop the Web application server on which the SAS Information Delivery Portal is deployed so that development of the new portlet will not affect the running system.

  2. From the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory, run the configuration script with the following arguments:

    cfg buildWebapps -Dmetadata.connection.passwd="password"

    For the password value, you must supply the unrestricted user password for your SAS installation.

    Note:   You can specify the password either in clear text or in encoded form. For information about generating the encoded form, see "The PWENCODE Procedure" in Encryption in SAS.  [cautionend]

  3. Review the customconfig.log file in the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory to determine whether any errors occurred.

  4. From the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory, run the configuration script with the following arguments:

    cfg deployWebapps -Dmetadata.connection.passwd="password"

    For the password value, you must supply the unrestricted user password for your SAS installation.

    The sample.remote.ear file containing the Web application will be copied to the staging area under the SAS configuration directory. You must manually deploy the file to your Web application server.

  5. Review the customconfig.log file in the SAS-configuration-directory/Lev1/CustomAppData/SampleRemote directory to determine whether any errors occurred.

  6. Rebuild the sas.portal4.2.ear file using the SAS Deployment Manager. This step is required because the sas.portal4.2.ear file contains files associated with each portlet.

  7. Manually redeploy the sas.portal4.2.ear file into the Web application server.

  8. Start the Web application server on which the SAS Information Delivery Portal is deployed. The SampleRemote portlet should now be available to the portal.

It is a good practice to deploy new portlets into a staging area (that is, a test installation of the SAS Information Delivery Portal) for verification and testing before deploying them into a production environment.

Previous Page | Next Page | Top of Page