Package com.liferay.faces.util.lifecycle

Source Code of com.liferay.faces.util.lifecycle.ViewScopePhaseListener$ManagedPropertyInjector

/**
* Copyright (c) 2000-2014 Liferay, Inc. All rights reserved.
*
* This library 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 library 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.
*/
package com.liferay.faces.util.lifecycle;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.el.ELContext;
import javax.faces.application.Application;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

import com.liferay.faces.util.lang.StringPool;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;


/**
* <p>This class is a JSF {@link PhaseListener} that listens to the {@link PhaseId#RESTORE_VIEW} phase of the JSF
* lifecycle. Its purpose is to re-inject {@link ManagedProperty} values into {@link ViewScoped} managed-bean instances
* after postback.</p>
*
* <p>When running under Mojarra, {@link ViewScoped} managed-beans are essentially stored in the underlying session.
* When running under MyFaces, {@link ViewScoped} managed-beans are serialized after the JSF lifecycle runs, probably so
* that they don't take up memory on the server. When doing a postback to a {@link ViewScoped} managed-bean, Mojarra
* simply pulls the live instance from the session. But with MyFaces, the managed-bean must be deserialized. The problem
* with this is that MyFaces does not re-inject @ManagedProperty values after deserialization. This class exists to
* work-around this problem.</p>
*
* <p>For more information, see: http://issues.liferay.com/browse/FACES-1400</p>
*
* @author  Neil Griffin
*/
public class ViewScopePhaseListener implements PhaseListener {

  // serialVersionUID
  private static final long serialVersionUID = 4328185923344558170L;

  // Logger
  private static final Logger logger = LoggerFactory.getLogger(ViewScopePhaseListener.class);

  public void afterPhase(PhaseEvent phaseEvent) {

    FacesContext facesContext = phaseEvent.getFacesContext();

    if (facesContext.isPostback()) {
      processViewScopedManagedBeans(facesContext);
    }
  }

  public void beforePhase(PhaseEvent phaseEvent) {
    // This method is required by the interface but is not used.
  }

  protected void injectManagedProperties(Object managedBean, ManagedPropertyInjector managedPropertyInjector) {

    if (managedBean.getClass().isAnnotationPresent(ManagedBean.class)) {
      Map<String, Field> managedPropertyFields = getManagedPropertyFields(managedBean.getClass());
      Set<Map.Entry<String, Field>> managedPropertyEntrySet = managedPropertyFields.entrySet();

      for (Map.Entry<String, Field> managedPropertyMapEntry : managedPropertyEntrySet) {
        String managedPropertyName = managedPropertyMapEntry.getKey();
        Field managedPropertyField = managedPropertyMapEntry.getValue();
        ManagedProperty managedPropertyAnnotation = managedPropertyField.getAnnotation(ManagedProperty.class);
        String managedPropertyExpression = managedPropertyAnnotation.value();

        if ((managedPropertyExpression != null) && (managedPropertyExpression.length() > 0)) {
          managedPropertyInjector.inject(managedBean, managedPropertyName, managedPropertyField.getType(),
            managedPropertyExpression);
        }
      }
    }
  }

  protected void processViewScopedManagedBeans(FacesContext facesContext) {
    UIViewRoot viewRoot = facesContext.getViewRoot();

    if (viewRoot != null) {

      ManagedPropertyInjector managedPropertyInjector = new ManagedPropertyInjector(facesContext);
      Map<String, Object> viewMap = viewRoot.getViewMap();
      Set<Map.Entry<String, Object>> managedBeanEntrySet = viewMap.entrySet();

      for (Map.Entry<String, Object> managedBeanMapEntry : managedBeanEntrySet) {
        Object managedBean = managedBeanMapEntry.getValue();

        if (managedBean != null) {
          injectManagedProperties(managedBean, managedPropertyInjector);
        }
      }
    }
  }

  protected Map<String, Field> getManagedPropertyFields(Class<?> managedBeanClass) {

    Map<String, Field> managedPropertyFields = new HashMap<String, Field>();

    // For each of the delcared fields of the specified class:
    Field[] declaredFields = managedBeanClass.getDeclaredFields();

    for (Field declaredField : declaredFields) {

      // If there is a @ManagedProperty annotation present on the field, then
      ManagedProperty managedPropertyAnnotation = declaredField.getAnnotation(ManagedProperty.class);

      if (managedPropertyAnnotation != null) {

        // Add the managed-property field to the return value map.
        String managedPropertyName = getManagedPropertyName(managedPropertyAnnotation, declaredField);
        managedPropertyFields.put(managedPropertyName, declaredField);

        // Recurse with the superclass of the specified class, so as to gather up all the @ManagedProperty
        // fields in the class hierarchy.
        Class<?> superClass = managedBeanClass.getSuperclass();

        if (!Object.class.equals(superClass)) {

          Map<String, Field> superClassFields = getManagedPropertyFields(superClass);

          Set<Map.Entry<String, Field>> superClassFieldsEntrySet = superClassFields.entrySet();

          for (Map.Entry<String, Field> superClassMapEntry : superClassFieldsEntrySet) {

            // If the managed-property name not yet been processed, then add it to the map. If it has
            // already been processed then that means it's an @Override from a subclass, and therefore it
            // would not be appropriate to clobber it.
            String superClassManagedPropertyName = superClassMapEntry.getKey();

            if (!managedPropertyFields.containsKey(superClassManagedPropertyName)) {
              Field superClassManagedPropertyField = superClassMapEntry.getValue();
              managedPropertyFields.put(superClassManagedPropertyName, superClassManagedPropertyField);
            }
          }
        }
      }
    }

    return managedPropertyFields;
  }

  protected String getManagedPropertyName(ManagedProperty managedProperty, Field field) {

    // Get the name of the managed-property from the @ManagedProperty annotation.
    String managedPropertyName = managedProperty.name();

    // Since the name element of the @ManagedProperty annotation is optional, then if it is missing, use
    // the name of the field itself.
    if ((managedPropertyName == null) || (managedPropertyName.length() == 0)) {
      managedPropertyName = field.getName();
    }

    return managedPropertyName;
  }

  public PhaseId getPhaseId() {
    return PhaseId.RESTORE_VIEW;
  }

  protected class ManagedPropertyInjector {

    // Private Constants
    private static final String EXPRESSION_PREFIX = StringPool.POUND + StringPool.OPEN_CURLY_BRACE;
    private static final String EXPRESSION_SUFFIX = StringPool.CLOSE_CURLY_BRACE;
    private static final String METHOD_PREFIX_SET = "set";

    // Private Data Members
    private Application application;
    private ELContext elContext;

    public ManagedPropertyInjector(FacesContext facesContext) {
      this.application = facesContext.getApplication();
      this.elContext = facesContext.getELContext();
    }

    public void inject(Object managedBean, String managedPropertyName, Class<?> managedPropertyClass,
      String elExpression) {

      String expressionWithoutSyntax = removeExpressionSyntax(elExpression);

      try {
        Object managedPropertyValue = application.getELResolver().getValue(elContext, null,
            expressionWithoutSyntax);
        String methodName = METHOD_PREFIX_SET + managedPropertyName.toUpperCase().substring(0, 1) +
          managedPropertyName.substring(1);
        Method setterMethod = managedBean.getClass().getMethod(methodName, managedPropertyClass);

        if (setterMethod != null) {
          setterMethod.invoke(managedBean, managedPropertyValue);
          logger.debug(
            "Injected @ManagedProperty name=[{0}] elExpression=[{1}] value=[{2}] into @ViewScoped managedBean=[{3}]",
            managedPropertyName, elExpression, managedPropertyValue, managedBean);
        }
        else {
          logger.error(
            "Unable to inject managed-property name=[{0}] elExpression=[{1}] using setter methodName=[{2}]",
            managedPropertyName, elExpression, methodName);
        }
      }
      catch (Exception e) {
        logger.error(e);
      }
    }

    protected String removeExpressionSyntax(String elExpression) {

      String expressionWithoutSyntax = elExpression;

      if (expressionWithoutSyntax != null) {

        if (expressionWithoutSyntax.startsWith(EXPRESSION_PREFIX)) {
          expressionWithoutSyntax = expressionWithoutSyntax.substring(EXPRESSION_PREFIX.length());
        }

        if (expressionWithoutSyntax.endsWith(EXPRESSION_SUFFIX)) {
          expressionWithoutSyntax = expressionWithoutSyntax.substring(0,
              expressionWithoutSyntax.length() - EXPRESSION_SUFFIX.length());
        }
      }

      return expressionWithoutSyntax;
    }
  }
}
TOP

Related Classes of com.liferay.faces.util.lifecycle.ViewScopePhaseListener$ManagedPropertyInjector

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.