/**
 * Topic encapsulates particular endpoint for sending/receiving messages.
 *
 * @author Nick Belaevski
 * @see Topic
 */
public abstract class AbstractTopic implements Topic {
  private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
  private TopicKey key;
  private volatile MessageDataSerializer serializer;
  private volatile boolean allowSubtopics;
  private List<TopicListener> listeners = new CopyOnWriteArrayList<TopicListener>();

  public AbstractTopic(TopicKey key) {
    super();
    this.key = key;
  }

  /*
   * (non-Javadoc)
   * @see org.richfaces.application.push.Topic#getMessageDataSerializer()
   */
  @Override
  public MessageDataSerializer getMessageDataSerializer() {
    if (serializer == null) {
      return DefaultMessageDataSerializer.instance();
    }

    return serializer;
  }

  /*
   * (non-Javadoc)
   * @see org.richfaces.application.push.Topic#setMessageDataSerializer(org.richfaces.application.push.MessageDataSerializer)
   */
  @Override
  public void setMessageDataSerializer(MessageDataSerializer serializer) {
    this.serializer = serializer;
  }

  /** Returns true if this topic allow to use subtopics */
  public boolean isAllowSubtopics() {
    return allowSubtopics;
  }

  /** Allow or disallow use of topics */
  public void setAllowSubtopics(boolean allowSubtopics) {
    this.allowSubtopics = allowSubtopics;
  }

  /*
   * (non-Javadoc)
   * @see org.richfaces.application.push.Topic#getKey()
   */
  @Override
  public TopicKey getKey() {
    return key;
  }

  /*
   * (non-Javadoc)
   * @see org.richfaces.application.push.Topic#addTopicListener(org.richfaces.application.push.TopicListener)
   */
  @Override
  public void addTopicListener(TopicListener topicListener) {
    TopicListener listener = topicListener;

    listeners.add(listener);
  }

  /*
   * (non-Javadoc)
   * @see org.richfaces.application.push.Topic#removeTopicListener(org.richfaces.application.push.TopicListener)
   */
  @Override
  public void removeTopicListener(TopicListener topicListener) {
    listeners.remove(topicListener);
  }

  /*
   * (non-Javadoc)
   * @see org.richfaces.application.push.Topic#checkSubscription(org.richfaces.application.push.Session)
   */
  @Override
  public void checkSubscription(Session session) throws SubscriptionFailureException {
    SessionPreSubscriptionEvent event = new SessionPreSubscriptionEvent(this, getKey(), session);
    for (TopicListener listener : listeners) {
      if (event.isAppropriateListener(listener)) {
        try {
          event.invokeListener(listener);
        } catch (SubscriptionFailureException e) {
          throw e;
        } catch (Exception e) {
          logError(e);
        }
      }
    }
  }

  private void logError(Exception e) {
    LOGGER.error(MessageFormat.format("Exception invoking listener: {0}", e.getMessage()), e);
  }

  /*
   * (non-Javadoc)
   * @see org.richfaces.application.push.Topic#publishEvent(org.richfaces.application.push.TopicEvent)
   */
  @Override
  public void publishEvent(TopicEvent event) {
    for (TopicListener listener : listeners) {
      if (event.isAppropriateListener(listener)) {
        try {
          event.invokeListener(listener);
        } catch (Exception e) {
          logError(e);
        }
      }
    }
  }

  /*
   * (non-Javadoc)
   * @see org.richfaces.application.push.Topic#publish(java.lang.Object)
   */
  @Override
  public abstract void publish(Object messageData) throws MessageException;
}
示例#2
0
/** @author <a href="http://community.jboss.org/people/bleathem">Brian Leathem</a> */
public class SelectManyHelper {
  private static final Logger LOG = RichfacesLogger.APPLICATION.getLogger();

  public static final String CELL_CSS = "-c";
  public static final String ITEM_CSS = "-opt";
  public static final String ITEM_CSS_DIS = "-opt-dis";
  public static final String BUTTON_CSS = "-btn";
  public static final String BUTTON_CSS_DIS = "-btn-dis";
  public static Comparator<ClientSelectItem> clientSelectItemComparator =
      new Comparator<ClientSelectItem>() {
        public int compare(ClientSelectItem clientSelectItem, ClientSelectItem clientSelectItem1) {
          Integer sortOrder =
              (clientSelectItem == null || clientSelectItem.getSortOrder() == null)
                  ? 0
                  : clientSelectItem.getSortOrder();
          Integer sortOrder1 =
              (clientSelectItem1 == null || clientSelectItem1.getSortOrder() == null)
                  ? 0
                  : clientSelectItem1.getSortOrder();
          return sortOrder.compareTo(sortOrder1);
        }
      };

  public static Predicate<ClientSelectItem> SELECTED_PREDICATE =
      new Predicate<ClientSelectItem>() {
        public boolean apply(@Nullable ClientSelectItem clientSelectItem) {
          return clientSelectItem.isSelected();
        }
      };

  public static Predicate<ClientSelectItem> UNSELECTED_PREDICATE =
      Predicates.not(SELECTED_PREDICATE);

  public static void encodeHeader(
      FacesContext facesContext,
      UIComponent component,
      SelectManyRendererBase renderer,
      String rowClass,
      String cellClass)
      throws IOException {
    ResponseWriter writer = facesContext.getResponseWriter();
    AbstractSelectManyComponent select = (AbstractSelectManyComponent) component;
    Iterator<UIColumn> headers = select.columns();

    if (headers.hasNext()) {
      writer.startElement("tr", component);
      StringBuilder headerClass = new StringBuilder(rowClass);
      if (select.getHeaderClass() != null && !select.getHeaderClass().isEmpty()) {
        if (headerClass.length() > 0) {
          headerClass.append(" ");
        }
        headerClass.append(select.getHeaderClass());
      }

      writer.writeAttribute("class", headerClass, null);
      while (headers.hasNext()) {
        UIColumn header = headers.next();
        writer.startElement("th", component);
        writer.writeAttribute("class", cellClass, null);
        UIComponent facet = header.getFacet("header");
        if (facet != null && facet.isRendered()) {
          facet.encodeBegin(facesContext);
          if (facet.getRendersChildren()) {
            facet.encodeChildren(facesContext);
          } else {
            renderer.renderChildren(facesContext, facet);
          }
          facet.encodeEnd(facesContext);
        }
        writer.endElement("th");
      }
      writer.endElement("tr");
    }
  }

  public static void encodeRows(
      FacesContext facesContext,
      UIComponent component,
      SelectManyRendererBase renderer,
      Iterator<ClientSelectItem> clientSelectItems,
      String cssPrefix)
      throws IOException {
    AbstractSelectManyComponent select = (AbstractSelectManyComponent) component;
    if (clientSelectItems != null && clientSelectItems.hasNext()) {
      String clientId = component.getClientId(facesContext);
      Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
      Object oldVar = requestMap.get(select.getVar());
      while (clientSelectItems.hasNext()) {
        ClientSelectItem clientSelectItem = clientSelectItems.next();
        requestMap.put(select.getVar(), clientSelectItem.getSelectItem().getValue());
        encodeOneRow(facesContext, component, renderer, clientSelectItem, cssPrefix);
      }
      requestMap.put(select.getVar(), oldVar);
      oldVar = null;
    }
  }

  public static void encodeOneRow(
      FacesContext facesContext,
      UIComponent component,
      SelectManyRendererBase renderer,
      ClientSelectItem clientSelectItem,
      String cssPrefix)
      throws IOException {
    AbstractSelectManyComponent table = (AbstractSelectManyComponent) component;
    String defaultItemCss = cssPrefix + ITEM_CSS;
    String defaultItemCssDis = cssPrefix + ITEM_CSS_DIS;

    ResponseWriter writer = facesContext.getResponseWriter();
    String clientId = table.getClientId(facesContext);
    String itemClientId = clientId + "Item" + clientSelectItem.getSortOrder();
    clientSelectItem.setClientId(itemClientId);
    writer.startElement(HtmlConstants.TR_ELEMENT, table);
    writer.writeAttribute("id", itemClientId, null);
    String itemCss;
    if (!table.isDisabled()) {
      itemCss = HtmlUtil.concatClasses(table.getItemClass(), defaultItemCss);
    } else {
      itemCss = HtmlUtil.concatClasses(table.getItemClass(), defaultItemCss, defaultItemCssDis);
    }
    writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, itemCss, null);

    String cellClassName = cssPrefix + CELL_CSS;

    String[] columnClasses;
    if (table.getColumnClasses() != null) {
      columnClasses = table.getColumnClasses().split(",");
    } else {
      columnClasses = new String[0];
    }
    int columnCounter = 0;
    Iterator<UIColumn> columnIterator = table.columns();
    while (columnIterator.hasNext()) {
      UIColumn column = columnIterator.next();
      if (column.isRendered()) {
        writer.startElement(HtmlConstants.TD_ELEM, table);

        Object width = column.getAttributes().get("width");
        if (width != null) {
          writer.writeAttribute(
              "style", "width: " + HtmlDimensions.formatSize(width.toString()), null);
        }

        String columnClass;
        if (columnClasses.length > 0) {
          columnClass =
              HtmlUtil.concatClasses(
                  cellClassName,
                  columnClasses[columnCounter % columnClasses.length],
                  column.getAttributes().get("styleClass"));
        } else {
          columnClass =
              HtmlUtil.concatClasses(cellClassName, column.getAttributes().get("styleClass"));
        }
        writer.writeAttribute("class", columnClass, null);
        renderer.renderChildren(facesContext, column);
        writer.endElement(HtmlConstants.TD_ELEM);
        columnCounter++;
      }
    }
    writer.endElement(HtmlConstants.TR_ELEMENT);
  }

  public static void encodeItems(
      FacesContext facesContext,
      UIComponent component,
      Iterator<ClientSelectItem> clientSelectItems,
      String cssPrefix)
      throws IOException {
    AbstractSelectManyComponent select = (AbstractSelectManyComponent) component;
    String defaultItemCss = cssPrefix + ITEM_CSS;
    String defaultItemCssDis = cssPrefix + ITEM_CSS_DIS;
    if (clientSelectItems != null && clientSelectItems.hasNext()) {
      ResponseWriter writer = facesContext.getResponseWriter();
      String clientId = component.getClientId(facesContext);
      while (clientSelectItems.hasNext()) {
        ClientSelectItem clientSelectItem = clientSelectItems.next();
        String itemClientId = clientId + "Item" + clientSelectItem.getSortOrder();
        clientSelectItem.setClientId(itemClientId);
        writer.startElement(HtmlConstants.DIV_ELEM, component);
        writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, itemClientId, null);
        String itemCss;
        if (!select.isDisabled()) {
          itemCss = HtmlUtil.concatClasses(select.getItemClass(), defaultItemCss);
        } else {
          itemCss =
              HtmlUtil.concatClasses(select.getItemClass(), defaultItemCss, defaultItemCssDis);
        }
        writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, itemCss, null);
        String label = clientSelectItem.getLabel();
        if (label != null && label.trim().length() > 0) {
          writer.writeText(label, null);
        } else {
          writer.write("\u00a0");
        }
        writer.endElement(HtmlConstants.DIV_ELEM);
        writer.write('\n');
      }
    }
  }

  public static List<ClientSelectItem> getClientSelectItems(
      FacesContext facesContext,
      AbstractSelectManyComponent select,
      Iterator<SelectItem> selectItems) {
    List<ClientSelectItem> clientSelectItems = new ArrayList<ClientSelectItem>();
    Object object = select.getValue();
    List values;
    if (object == null) {
      values = new ArrayList();
    } else if (object instanceof List) {
      values = (List) object;
    } else if (object instanceof Object[]) {
      values = Arrays.asList((Object[]) object);
    } else {
      throw new IllegalArgumentException(
          "Value expression must evaluate to either a List or Object[]");
    }
    int count = values.size();
    // TODO: Deal with SelectItemGroups
    while (selectItems.hasNext()) {
      SelectItem selectItem = selectItems.next();
      boolean selected;
      int sortOrder;
      if (values.contains(
          selectItem
              .getValue())) { // TODO: this requires value#equals() to be overridden. Redo with
                              // comparators?
        selected = true;
        sortOrder = values.indexOf(selectItem.getValue());
      } else {
        selected = false;
        sortOrder = count;
      }
      ClientSelectItem clientSelectItem =
          SelectHelper.generateClientSelectItem(
              facesContext, select, selectItem, sortOrder, selected);
      clientSelectItems.add(clientSelectItem);
      if (!selected) {
        count++;
      }
    }
    Collections.sort(clientSelectItems, clientSelectItemComparator);
    return clientSelectItems;
  }

  public static Object getConvertedValue(
      FacesContext facesContext, UIComponent component, Object val) throws ConverterException {
    String[] values = (val == null) ? new String[0] : (String[]) val;
    Converter converter = SelectManyHelper.getItemConverter(facesContext, component);
    ValueExpression ve = component.getValueExpression("value");
    Object targetForConvertedValues = null;
    if (ve != null) {
      // If the component has a ValueExpression for value, let modelType be the type of the value
      // expression
      Class<?> modelType = ve.getType(facesContext.getELContext());
      if (modelType.isArray()) {
        // If the component has a ValueExpression for value and the type of the expression is an
        // array, let targetForConvertedValues be a new array of the expected type.
        Class<?> arrayComponentType = modelType.getComponentType();
        targetForConvertedValues = Array.newInstance(arrayComponentType, values.length);
      } else if (Collection.class.isAssignableFrom(modelType) || Object.class.equals(modelType)) {
        // If modelType is a Collection, do the following to arrive at targetForConvertedValues:
        // Ask the component for its attribute under the key "collectionType"
        String collectionType = (String) component.getAttributes().get("collectionType");
        if (collectionType != null) {
          // Let targetForConvertedValues be a new instance of Collection implemented by the
          // concrete class specified in collectionType
          Class<?> collectionClass = getCollectionClass(collectionType);
          try {
            targetForConvertedValues = collectionClass.newInstance();
          } catch (Exception e) {
            throw new FacesException(e);
          }
        } else {
          // If there is no "collectionType" attribute, call getValue() on the component
          // The result will implement Collection.
          Collection value = (Collection) ((EditableValueHolder) component).getValue();
          if (value instanceof Cloneable) {
            // If the result also implements Cloneable, let targetForConvertedValues be the result
            // of calling its clone() method,
            // then calling clear() on the cloned Collection.
            try {
              targetForConvertedValues =
                  (Collection) value.getClass().getMethod("clone").invoke(value);
              ((Collection) targetForConvertedValues).clear();
            } catch (Exception e) {
              // If unable to clone the value for any reason, log a message
              LOG.log(Logger.Level.WARNING, "Unable to clone collection");
            }
          }
          if (targetForConvertedValues == null) {
            // and proceed to the next step
            Class<?> collectionClass = value == null ? modelType : value.getClass();
            try {
              // If modelType is a concrete class, let targetForConvertedValues be a new instance of
              // that class.
              targetForConvertedValues = collectionClass.newInstance();
              ((Collection) targetForConvertedValues).clear();
            } catch (Exception e) {
              // Otherwise, the concrete type for targetForConvertedValues is taken from the
              // following table
              if (Collection.class.isAssignableFrom(modelType)) {
                if (SortedSet.class.isAssignableFrom(modelType)) {
                  targetForConvertedValues = new TreeSet();
                } else if (Queue.class.isAssignableFrom(modelType)) {
                  targetForConvertedValues = new LinkedList();
                } else if (Set.class.isAssignableFrom(modelType)) {
                  targetForConvertedValues = new HashSet(values.length);
                } else {
                  targetForConvertedValues = new ArrayList(values.length);
                }
              }
            }
          }
        }
      } else {
        throw new FacesException("ValueExpression must be either an Array, or a Collection");
      }
    } else {
      // If the component does not have a ValueExpression for value, let targetForConvertedValues be
      // an array of type Object.
      targetForConvertedValues = new Object[values.length];
    }
    for (int i = 0; i < values.length; i++) {
      Object value;
      if (converter == null) {
        value = values[i];
      } else {
        value = converter.getAsObject(facesContext, component, values[i]);
      }
      if (targetForConvertedValues.getClass().isArray()) {
        Array.set(targetForConvertedValues, i, value);
      } else {
        ((Collection) targetForConvertedValues).add(value);
      }
    }
    return targetForConvertedValues;
  }

  private static Class getCollectionClass(String collectionType) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    Class<?> collectionClass = null;
    if (classLoader == null) {
      classLoader = SelectManyRendererBase.class.getClassLoader();
    }
    try {
      collectionClass = classLoader.loadClass(collectionType).asSubclass(Collection.class);
    } catch (ClassNotFoundException e) {
      throw new FacesException(e);
    }
    return collectionClass;
  }

  public static Converter getItemConverter(FacesContext facesContext, UIComponent component) {
    Converter converter = null;
    if (component instanceof ValueHolder) {
      // If the component has an attached Converter, use it.
      converter = ((ValueHolder) component).getConverter();
      if (converter != null) {
        return converter;
      }
    }
    // If not, look for a ValueExpression for value (if any). The ValueExpression must point to
    // something that is:
    ValueExpression ve = component.getValueExpression("value");
    if (ve != null) {
      Class<?> valueType = ve.getType(facesContext.getELContext());
      // An array of primitives (such as int[]). Look up the registered by-class Converter for this
      // primitive type.
      // An array of objects (such as Integer[] or String[]). Look up the registered by-class
      // Converter for the underlying element type.
      if (valueType != null && valueType.isArray()) {
        converter = facesContext.getApplication().createConverter(valueType);
      }
      // A java.util.Collection. Do not convert the values.
    }
    if (converter == null) {
      // Spec says "If for any reason a Converter cannot be found, assume the type to be a String
      // array." However
      // if we don't have an explicit converter, see if one is registered for the class of the
      // SelectItem values
      Iterator<SelectItem> selectItems = SelectUtils.getSelectItems(facesContext, component);
      converter = getSelectItemConverter(facesContext.getApplication(), selectItems);
    }

    return converter;
  }

  public static Converter getSelectItemConverter(
      Application facesApplication, Iterator<SelectItem> selectItems) {
    Converter converter = null;
    while (selectItems.hasNext() && converter == null) {
      SelectItem selectItem = selectItems.next();
      if (selectItem instanceof SelectItemGroup) {
        SelectItemGroup selectItemGroup = (SelectItemGroup) selectItem;
        Iterator<SelectItem> groupSelectItems =
            Iterators.forArray(selectItemGroup.getSelectItems());
        // Recursively get the converter from the SelectItems of the SelectItemGroup
        converter = getSelectItemConverter(facesApplication, groupSelectItems);
      } else {
        Class<?> selectItemClass = selectItem.getValue().getClass();
        if (String.class.equals(selectItemClass)) {
          return null; // No converter required for strings
        }
        try {
          converter =
              facesApplication.createConverter(
                  selectItemClass); // Lookup the converter registered for the class
        } catch (FacesException exception) {
          // Converter cannot be created
        }
      }
    }
    return converter;
  }

  public static UISelectItems getPseudoSelectItems(SelectItemsInterface selectItemsInterface) {
    UISelectItems selectItems = null;
    if (selectItemsInterface.getVar() != null && selectItemsInterface.getItemValues() != null) {
      selectItems = new UISelectItems();
      selectItems.setValue(selectItemsInterface.getItemValues());
      selectItems.getAttributes().put("var", selectItemsInterface.getVar());
      if (selectItemsInterface.getItemValue() != null) {
        selectItems.getAttributes().put("itemValue", selectItemsInterface.getItemValue());
      }
      if (selectItemsInterface.getItemLabel() != null) {
        selectItems.getAttributes().put("itemLabel", selectItemsInterface.getItemLabel());
      }
    }
    return selectItems;
  }
}
/**
 * When deserializing objects, first check that the class being deserialized is in the allowed
 * whitelist.
 *
 * @author <a href="http://community.jboss.org/people/bleathem">Brian Leathem</a>
 */
public class LookAheadObjectInputStream extends ObjectInputStream {
  private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
  private static final Map<String, Class<?>> PRIMITIVE_TYPES =
      new HashMap<String, Class<?>>(9, 1.0F);
  private static Set<Class> whitelistBaseClasses = new HashSet<Class>();
  private static Set<String> whitelistClassNameCache =
      Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());

  static {
    PRIMITIVE_TYPES.put("bool", Boolean.TYPE);
    PRIMITIVE_TYPES.put("byte", Byte.TYPE);
    PRIMITIVE_TYPES.put("char", Character.TYPE);
    PRIMITIVE_TYPES.put("short", Short.TYPE);
    PRIMITIVE_TYPES.put("int", Integer.TYPE);
    PRIMITIVE_TYPES.put("long", Long.TYPE);
    PRIMITIVE_TYPES.put("float", Float.TYPE);
    PRIMITIVE_TYPES.put("double", Double.TYPE);
    PRIMITIVE_TYPES.put("void", Void.TYPE);

    whitelistClassNameCache.add(new Object[0].getClass().getName());
    whitelistClassNameCache.add(new String[0].getClass().getName());
    whitelistClassNameCache.add(new Boolean[0].getClass().getName());
    whitelistClassNameCache.add(new boolean[0].getClass().getName());
    whitelistClassNameCache.add(new Byte[0].getClass().getName());
    whitelistClassNameCache.add(new byte[0].getClass().getName());
    whitelistClassNameCache.add(new Character[0].getClass().getName());
    whitelistClassNameCache.add(new char[0].getClass().getName());
    whitelistClassNameCache.add(new Short[0].getClass().getName());
    whitelistClassNameCache.add(new short[0].getClass().getName());
    whitelistClassNameCache.add(new Integer[0].getClass().getName());
    whitelistClassNameCache.add(new int[0].getClass().getName());
    whitelistClassNameCache.add(new Long[0].getClass().getName());
    whitelistClassNameCache.add(new long[0].getClass().getName());
    whitelistClassNameCache.add(new Float[0].getClass().getName());
    whitelistClassNameCache.add(new float[0].getClass().getName());
    whitelistClassNameCache.add(new Double[0].getClass().getName());
    whitelistClassNameCache.add(new double[0].getClass().getName());
    whitelistClassNameCache.add(new Void[0].getClass().getName());

    whitelistBaseClasses.add(String.class);
    whitelistBaseClasses.add(Boolean.class);
    whitelistBaseClasses.add(Byte.class);
    whitelistBaseClasses.add(Character.class);
    whitelistBaseClasses.add(Number.class);
    whitelistBaseClasses.add(Collection.class);

    loadWhitelist();
  }

  public LookAheadObjectInputStream(InputStream in) throws IOException {
    super(in);
  }

  /** Only deserialize primitive or whitelisted classes */
  @Override
  protected Class<?> resolveClass(ObjectStreamClass desc)
      throws IOException, ClassNotFoundException {
    Class<?> primitiveType = PRIMITIVE_TYPES.get(desc.getName());
    if (primitiveType != null) {
      return primitiveType;
    }
    if (!isClassValid(desc.getName())) {
      throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
    }
    return super.resolveClass(desc);
  }

  /** Determine if the given requestedClassName is allowed by the whitelist */
  boolean isClassValid(String requestedClassName) {
    if (whitelistClassNameCache.contains(requestedClassName)) {
      return true;
    }
    try {
      Class<?> requestedClass = Class.forName(requestedClassName);
      for (Class baseClass : whitelistBaseClasses) {
        if (baseClass.isAssignableFrom(requestedClass)) {
          whitelistClassNameCache.add(requestedClassName);
          return true;
        }
      }
    } catch (ClassNotFoundException e) {
      return false;
    }
    return false;
  }

  /** Load the whitelist from the properties file */
  static void loadWhitelist() {
    Properties whitelistProperties = new Properties();
    InputStream stream = null;
    try {
      stream =
          LookAheadObjectInputStream.class.getResourceAsStream(
              "/org/richfaces/resource/resource-serialization.properties");
      whitelistProperties.load(stream);
    } catch (IOException e) {
      throw new RuntimeException("Error loading the resource-serialization.properties file", e);
    } finally {
      if (stream != null) {
        try {
          stream.close();
        } catch (IOException e) {
          throw new RuntimeException("Error closing the resource-serialization.properties file", e);
        }
      }
    }
    for (String baseClassName : whitelistProperties.getProperty("whitelist").split(",")) {
      try {
        Class<?> baseClass = Class.forName(baseClassName);
        whitelistBaseClasses.add(baseClass);
      } catch (ClassNotFoundException e) {
        if (LOGGER.isInfoEnabled()) {
          LOGGER.debug(e);
        }
      }
    }
  }
}
public class MultipartRequest25 extends BaseMultipartRequest {
  private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
  private static final Function<Collection<String>, Object> MULTIMAP_VALUE_TRANSFORMER =
      new Function<Collection<String>, Object>() {
        public Object apply(Collection<String> input) {
          if (input.isEmpty()) {
            return null;
          }

          if (input.size() == 1) {
            return Iterables.get(input, 0);
          }

          return input.toArray(new String[input.size()]);
        }
      };
  private MultipartRequestParser requestParser;
  private ResponseState responseState;
  private Iterable<UploadedFile> uploadedFiles;
  private Multimap<String, String> params;

  public MultipartRequest25(
      HttpServletRequest request,
      String uploadId,
      ProgressControl progressControl,
      MultipartRequestParser requestParser) {

    super(request, uploadId, progressControl);

    this.requestParser = requestParser;
  }

  private void parseIfNecessary() {
    if (responseState != null) {
      return;
    }

    try {
      requestParser.parse();

      uploadedFiles = requestParser.getUploadedFiles();
      params = requestParser.getParameters();
      responseState = ResponseState.ok;
    } catch (FileUploadException e) {
      LOGGER.error(e.getMessage(), e);
      responseState = ResponseState.serverError;
    }
  }

  @SuppressWarnings({"rawtypes", "unchecked"})
  @Override
  public Enumeration getParameterNames() {
    Collection<Object> result = Sets.newHashSet();

    Enumeration names = super.getParameterNames();
    while (names.hasMoreElements()) {
      String name = (String) names.nextElement();

      result.add(name);
    }

    parseIfNecessary();
    result.addAll(params.keySet());

    return Iterators.asEnumeration(result.iterator());
  }

  @Override
  public String getParameter(String name) {

    String parameter = super.getParameter(name);
    if (parameter != null) {
      return parameter;
    }

    parseIfNecessary();
    Collection<String> values = params.get(name);

    if (values.isEmpty()) {
      return null;
    }

    return Iterables.get(values, 0);
  }

  @Override
  public String[] getParameterValues(String name) {
    String[] parameterValues = super.getParameterValues(name);
    if (parameterValues != null) {
      return parameterValues;
    }

    parseIfNecessary();
    Collection<String> values = params.get(name);

    if (values.isEmpty()) {
      return null;
    }

    return values.toArray(new String[values.size()]);
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  @Override
  public Map getParameterMap() {
    Map parameterMap = Maps.newHashMap(super.getParameterMap());
    parseIfNecessary();
    parameterMap.putAll(Maps.transformValues(params.asMap(), MULTIMAP_VALUE_TRANSFORMER));

    return parameterMap;
  }

  public Iterable<UploadedFile> getUploadedFiles() {
    parseIfNecessary();

    return uploadedFiles;
  }

  public void release() {
    super.release();

    if (uploadedFiles != null) {
      for (UploadedFile uploadedFile : uploadedFiles) {
        try {
          uploadedFile.delete();
        } catch (IOException e) {
          LOGGER.error(e.getMessage(), e);
        }
      }
    }
  }

  public ResponseState getResponseState() {
    parseIfNecessary();

    return responseState;
  }
}