Package javax.portlet.faces

Source Code of javax.portlet.faces.GenericFacesPortlet

/******************************************************************************
* JBoss, a division of Red Hat                                               *
* Copyright 2006, Red Hat Middleware, LLC, and individual                    *
* contributors as indicated by the @authors tag. See the                     *
* copyright.txt in the distribution for a full listing of                    *
* individual contributors.                                                   *
*                                                                            *
* This is free software; you can redistribute it and/or modify it            *
* under the terms of the GNU Lesser General Public License as                *
* published by the Free Software Foundation; either version 2.1 of           *
* the License, or (at your option) any later version.                        *
*                                                                            *
* This software is distributed in the hope that it will be useful,           *
* but WITHOUT ANY WARRANTY; without even the implied warranty of             *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU           *
* Lesser General Public License for more details.                            *
*                                                                            *
* You should have received a copy of the GNU Lesser General Public           *
* License along with this software; if not, write to the Free                *
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA         *
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.                   *
******************************************************************************/
package javax.portlet.faces;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;

/**
* JSR 301 generic faces pottlet implementation.
*
* @author asmirnov
*
*/
public class GenericFacesPortlet extends GenericPortlet {

  private static final int EXTENDED_ATTR_PREFIX_LENGTH = Bridge.EXTENDED_PORTLET_ATTR_PREFIX
      .length();
  private static final String BRIDGE_SERVICE_CLASSPATH = "META-INF/services/javax.portlet.faces.Bridge";
  public static final String BRIDGE_CLASS = "javax.portlet.faces.BridgeImplClass";
  public static final String DEFAULT_CONTENT_TYPE = Bridge.BRIDGE_PACKAGE_PREFIX
      + "defaultContentType";
  public static final String DEFAULT_CHARACTERSET_ENCODING = Bridge.BRIDGE_PACKAGE_PREFIX
      + "defaultCharacterSetEncoding";

  private volatile String bridgeClassName = null;
  private volatile Class<? extends Bridge> facesBridgeClass;
  private volatile Bridge facesPortletBridge = null;
  private Map<String, String> viewIdMap;
  // Following are names of request attributes a portletbridge must set before
  // calling the Bridge to process a request
  private static final String DEFAULT_VIEWID = Bridge.BRIDGE_PACKAGE_PREFIX
      + "defaultViewId";

  private static final int DEFAULT_VIEW_ID_LENGTH = DEFAULT_VIEWID.length() + 1;

  public void init(PortletConfig config) throws PortletException {
    super.init(config);
    PortletContext portletContext = this.getPortletContext();
    String bridgeClassName = getBridgeClassName();
    try {
      facesBridgeClass = getClassLoader().loadClass(bridgeClassName)
          .asSubclass(Bridge.class);
    } catch (ClassNotFoundException e) {
      throw new PortletException(
          "Faces portlet Bridge implementation class not found", e);
    }

    String portletName = getPortletName();
    Boolean isPreserveActionParams = getPreserveActionParameters();
    portletContext.setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + portletName
        + "." + Bridge.PRESERVE_ACTION_PARAMS, isPreserveActionParams);
    List<String> attrsList = getExcludedRequestAttributes();
    if (null != attrsList) {
      portletContext.setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX
          + portletName + "." + Bridge.EXCLUDED_REQUEST_ATTRIBUTES,
          attrsList);

    }
    // Get extension config attributes.
    Enumeration<?> configNames = config.getInitParameterNames();
    while (configNames.hasMoreElements()) {
      String name = (String) configNames.nextElement();
      if (name.startsWith(Bridge.EXTENDED_PORTLET_ATTR_PREFIX)) {
        int i = name.lastIndexOf('.');
        if (i > EXTENDED_ATTR_PREFIX_LENGTH + 2) {
          String attribute = name.substring(i);
          String preffix = name.substring(
              EXTENDED_ATTR_PREFIX_LENGTH, i + 1);
          String extensionAttributeName = Bridge.EXTENDED_PORTLET_ATTR_PREFIX
              + preffix + portletName + attribute;
          portletContext.setAttribute(extensionAttributeName, config
              .getInitParameter(name));
        }
      }
    }

    Map<String, String> viewIdMap = getDefaultViewIdMap();
    getPortletContext().setAttribute(
        Bridge.BRIDGE_PACKAGE_PREFIX + portletName + "."
            + Bridge.DEFAULT_VIEWID_MAP, viewIdMap);
  }

  private String calculateBridgeClassName(PortletContext portletContext)
      throws PortletException {
    String bridgeClassName = portletContext.getInitParameter(BRIDGE_CLASS);
    if (bridgeClassName == null) {
      ClassLoader loader = getClassLoader();
      InputStream stream = loader
          .getResourceAsStream(BRIDGE_SERVICE_CLASSPATH);
      if (null != stream) {
        try {
          BufferedReader reader = null;
          try {
            reader = new BufferedReader(new InputStreamReader(
                stream, "UTF-8"));
          } catch (UnsupportedEncodingException e) {
            reader = new BufferedReader(new InputStreamReader(
                stream));
          }
          bridgeClassName = reader.readLine();
          if (null != bridgeClassName) {
            bridgeClassName = bridgeClassName.trim();
          }
        } catch (IOException e) {
          // Ignore
        } catch (SecurityException e) {
          // Ignore
        } finally {
          try {
            stream.close();
          } catch (IOException e) {
            throw new PortletException(
                "Error to close input stream for a resource "
                    + BRIDGE_SERVICE_CLASSPATH);
          }
        }
      }
    }
    if (null == bridgeClassName) {
      throw new PortletException(
          "Can't detect bridge implementation class name");
    }
    return bridgeClassName;
  }

  /**
   * 4.2.7 getExcludedRequestAttributes() As a portlet lifecycle allows
   * multiple (re)renders to occur following an action, the bridge manages an
   * extended notion of a request scope to ensure that such rerenders produces
   * identical results. Specifically, portlet scoped request attributes are
   * saved/restored by the bridge across such rerenders [5.1.2]. However,
   * sometimes a portlet request scoped attribute truly must be removed when
   * the request scope ends. The bridge uses multiple mechanisms for
   * determining which attributes are marked for exclusion from its managed
   * scope. The portlet can directly instruct the bridge to exclude attributes
   * on a per portlet basis by setting a PorletContext attribute [3.2]. This
   * attribute's value is a List containing the excluded attribute names.
   *
   * The GenericFacesPortlet sets this attribute based on the result of
   * calling getExcludedRequestAttributes() in its init() method. The default
   * (GenericFacesPortlet) implementation for getExcludedRequestAttributes()
   * returns a List constructed by parsing the comma delimited String value
   * from the corresponding portlet initialization parameter,
   * javax.portlet.faces.excludedRequestAttributes. If this initialization
   * parameter isn't present null is returned which causes the
   * GenericFacesPortlet to not set the corresponding PortletContext
   * attribute.
   *
   * @return
   */
  public List<String> getExcludedRequestAttributes() {
    List<String> attrsList = null;
    String excludedAttrs = getPortletConfig().getInitParameter(
        Bridge.BRIDGE_PACKAGE_PREFIX
            + Bridge.EXCLUDED_REQUEST_ATTRIBUTES);
    if (null != excludedAttrs) {
      String[] atrs = excludedAttrs.split(",");
      attrsList = new ArrayList<String>(atrs.length);
      for (String string : atrs) {
        attrsList.add(string);
      }
    }
    return attrsList;
  }

  /**
   * 4.2.9 getResponseContentType() In Portlet 1.0 a portlet must set the
   * response content type prior to dispatching to a servlet or jsp as setting
   * a content type in a dispatch (include) is ignored. When the Faces view is
   * represented in a jsp, the bridge uses dispatch to render the view. In
   * this situation any content type set by the jsp/render is ignored. To
   * ensure a content type is set, the bridge sets the content type to the one
   * which the portlet container indicates is preferred for this request if
   * one hasn't been set by the portlet. To provide more flexibility the
   * GenericFacesPortlet always sets the response content type by calling
   * getResponseContentType() on itself. If not overridden, the
   * GenericFacesPortlet returns the value of the portlet initialization
   * parameter javax.portlet.faces.defaultContentType, or if this parameter
   * doesn't exists, the portlet container's indication of the preferred
   * content type for this request.
   *
   * @param request
   * @return
   */
  public String getResponseContentType(PortletRequest request) {
    String contentType = getPortletConfig().getPortletContext()
        .getInitParameter(DEFAULT_CONTENT_TYPE);

    if (contentType == null) {
      contentType = request.getResponseContentType();
    }
    return contentType;
  }

  /**
   * 4.2.10 getResponseCharacterSetEncoding() Though a portlet is prevented
   * from setting the character set encoding of the actual response as this is
   * under the control of the portlet container, its common for portlet
   * containers to interpret such settings as an indication of the encoding
   * that is being written and hence should be translated by the container to
   * its response encoding. In such circumstances character set encoding
   * information is passed as extra information in the string used to set the
   * response content type. As part of the content type it too must be
   * expressed prior to any dispatching. In the situation that the bridge sets
   * a response content type because none has been set yet, it doesn't set a
   * corresponding character set encoding. I.e. it that the Faces view renders
   * in the encoding chosen by the container. To provide more flexibility the
   * GenericFacesPortlet extends its behavior which sets a response content
   * type. As part of the process of determining the content type to set, the
   * GenericFacesPortlet calls getResponseCharacterSetEncoding on itself. If a
   * non-null value is returned, the value is appended (; delimited) to the
   * content type prior to setting the response content type such that its
   * form is the same as one returned in the http response CONTENT-TYPE
   * header. The GenericFacesPortlet implements
   * getResponseCharacterSetEncoding by returning the value of the portlet
   * initialization parameter javax.portlet.faces.defaultCharacterSetEncoding
   * or null if this parameter doesn't exist.
   *
   * @param request
   * @return
   */
  public String getResponseCharacterSetEncoding(PortletRequest request) {
    return getPortletConfig().getPortletContext().getInitParameter(
        DEFAULT_CHARACTERSET_ENCODING);
  }

  /**
   * 4.2.8 getPreserveActionParameters() By default the bridge doesn't
   * preserve action parameters into subsequent renders. This can be
   * overridden on a per portlet basis by passing a value of true in the
   * appropriate PortletContext attribute [3.2]. To determine the setting for
   * this attributes for this particular portlet, the GenericFacesPortlet
   * calls getPreserveActionParameters() in its init() method. The default
   * (GenericFacesPortlet) implementation returns the Boolean value
   * corresponding to the String value represented in the portlet
   * initialization parameter, javax.portlet.faces.preserveActionParams. If
   * this initialization parameter doesn't exist, Boolean.FALSE is returned.
   *
   * @return preserve or not action attributes.
   */
  public Boolean getPreserveActionParameters() {
    String preserveActionParams = getPortletConfig().getInitParameter(
        Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.PRESERVE_ACTION_PARAMS);
    Boolean isPreserveActionParams = Boolean.valueOf(preserveActionParams);
    return isPreserveActionParams;
  }

  protected void doDispatch(RenderRequest request, RenderResponse response)
      throws PortletException, IOException {
    PortletMode mode = request.getPortletMode();
    if (mode == PortletMode.VIEW || mode == PortletMode.EDIT
        || mode == PortletMode.HELP) {
      super.doDispatch(request, response);
    } else {
      doFacesDispatch(request, response);
    }

  }

  protected void doEdit(RenderRequest request, RenderResponse response)
      throws PortletException, IOException {
    doFacesDispatch(request, response);
  }

  protected void doHelp(RenderRequest request, RenderResponse response)
      throws PortletException, IOException {
    doFacesDispatch(request, response);
  }

  protected void doView(RenderRequest request, RenderResponse response)
      throws PortletException, IOException {
    doFacesDispatch(request, response);
  }

  public void processAction(ActionRequest request, ActionResponse response)
      throws PortletException, IOException {
    // String defaultViewId = getDefaultViewIdMap().get(request
    // .getPortletMode());
    Bridge bridge = getFacesPortletBridge();
    // request.setAttribute(GenericFacesPortlet.DEFAULT_VIEWID,
    // defaultViewId);
    try {
      bridge.doFacesRequest(request, response);

    } catch (BridgeException e) {
      throw new PortletException("Error process faces request", e);
    }
  }

  void doFacesDispatch(RenderRequest request, RenderResponse response)
      throws PortletException, IOException {
    String defaultViewId = getDefaultViewIdMap().get(
        request.getPortletMode().toString());
    if (null != defaultViewId
        && !request.getWindowState().equals(WindowState.MINIMIZED)) {
      Bridge bridge = getFacesPortletBridge();
      // request.setAttribute(GenericFacesPortlet.DEFAULT_VIEWID,
      // defaultViewId);
      String responseContentType = getResponseContentType(request);
      if (null != responseContentType) {
        StringBuilder contentType = new StringBuilder(
            responseContentType);
        String characterSetEncoding = getResponseCharacterSetEncoding(request);
        if (null != characterSetEncoding) {
          contentType.append(';').append(characterSetEncoding);
        }
        response.setContentType(contentType.toString());

      }
      try {
        bridge.doFacesRequest(request, response);

      } catch (BridgeException e) {
        throw new PortletException("Error process faces request", e);
      }
    }
  }

  /**
   * JSR 301 API method
   *
   * @return
   */
  public String getBridgeClassName() throws PortletException {
    if (null == bridgeClassName) {
      bridgeClassName = calculateBridgeClassName(getPortletContext());
    }
    return bridgeClassName;
  }

  private ClassLoader getClassLoader() {
    ClassLoader classLoader = Thread.currentThread()
        .getContextClassLoader();
    if (null == classLoader) {
      classLoader = this.getClass().getClassLoader();
    }
    return classLoader;
  }

  public Map<String, String> getDefaultViewIdMap() {
    if (null == viewIdMap) {
      viewIdMap = calculateDefaultViewIdMap();
    }
    return viewIdMap;

  }

  private Map<String, String> calculateDefaultViewIdMap() {
    Map<String, String> viewIdMap = new HashMap<String, String>();
    PortletConfig portletConfig = getPortletConfig();
    Enumeration<?> configNames = portletConfig.getInitParameterNames();
    while (configNames.hasMoreElements()) {
      String name = (String) configNames.nextElement();
      if (name.startsWith(DEFAULT_VIEWID)) {
        // Put viewId with mode name as key.
        viewIdMap.put(name.substring(DEFAULT_VIEW_ID_LENGTH),
            portletConfig.getInitParameter(name));
      }
    }
    return viewIdMap;
  }

  public void destroy() {
    bridgeClassName = null;
    // If bridge was initialized, destroy it.
    if (null != facesPortletBridge) {
      facesPortletBridge.destroy();
      facesPortletBridge = null;
    }
    super.destroy();
  }

  /**
   * @return the facesPortletBridge
   * @throws PortletException
   */
  @SuppressWarnings("unchecked")
  Bridge getFacesPortletBridge() throws PortletException {
    if (null == facesPortletBridge) {
      synchronized (this) {
        if (null == facesPortletBridge) {
          try {
          // Do not assign uninitialized instance to field
            Bridge bridge = (Bridge) facesBridgeClass
                .newInstance();
            bridge.init(getPortletConfig());
            this.facesPortletBridge = bridge;
          } catch (InstantiationException e) {
            throw new PortletException(
                "Error on create instance of a JSF Portlet Bridge",
                e);
          } catch (IllegalAccessException e) {
            throw new PortletException(
                "IllegalAccess on create instance of a JSF Portlet Bridge",
                e);
          } catch (BridgeException e) {
            throw new PortletException(
                "Bridge initialization error", e);
          }
        }
      }
    }
    return facesPortletBridge;
  }
}
TOP

Related Classes of javax.portlet.faces.GenericFacesPortlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.