Package org.richfaces.renderkit

Source Code of org.richfaces.renderkit.FileUploadRendererBase

/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

package org.richfaces.renderkit;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIParameter;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.http.HttpSession;

import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.javascript.JSFunction;
import org.ajax4jsf.javascript.JSFunctionDefinition;
import org.ajax4jsf.javascript.JSLiteral;
import org.ajax4jsf.javascript.JSReference;
import org.ajax4jsf.javascript.ScriptUtils;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.RendererUtils;
import org.ajax4jsf.request.MultipartRequest;
import org.ajax4jsf.resource.CountingOutputWriter;
import org.richfaces.component.FileUploadConstants;
import org.richfaces.component.UIFileUpload;
import org.richfaces.component.UIProgressBar;
import org.richfaces.component.util.HtmlUtil;
import org.richfaces.event.UploadAjaxActionEvent;
import org.richfaces.event.UploadEvent;
import org.richfaces.model.UploadItem;

/**
* Class provides base renderer for upload file component
*
* @author "Andrey Markavtsov"
*
*/
public abstract class FileUploadRendererBase extends
    TemplateEncoderRendererBase {

  /** Attribute name where collection of files uploaded will be stored */
  private static final String _FILES_UPLOADED_ATTRIBUTE_NAME = "uploadData";

  /** File upload bundle name */
  private static final String FILE_UPLOAD_BUNDLE = "org.richfaces.renderkit.fileUpload";

  /** Bundle prefix */
  private static final String bundlePrefix = "RICH_FILE_UPLOAD_";

  /** Bundle postfix */
  private static final String bundlePostfix = "_LABEL";

  /** Set of bundles that can be defined */
  private static final String[] bundlesLables = { "add", "upload", "stop",
      "clear_all", "entry_cancel", "entry_clear", "entry_stop", "done",
      "size_error", "transfer_error","progress" };

  /** Default labels values */
  private static final String[] defaultLables = { "Add...", "<b>Upload</b>",
      "<b>Stop</b>", "Clear All", "Cancel", "Clear", "Stop",
      "<b>Done</b>", "File size restricted", "Transfer error occurred","uploading"};

  /** Set of attributes that can define label's value */
  private static final String[] labelAttribues = { "addControlLabel",
      "uploadControlLabel", "stopControlLabel", "clearAllControlLabel",
      "cancelEntryControlLabel", "clearControlLabel",
      "stopEntryControlLabel", "doneLabel", "sizeErrorLabel", "transferErrorLabel", "progressLabel" };

  /**
   * Overrides standard JSF component method.
   *
   * @param context
   *            faces context
   * @param component
   *            file upload component
   */
  @Override
  @SuppressWarnings("unchecked")
  protected void doDecode(FacesContext context, UIComponent component) {
    UIFileUpload fileUpload = (UIFileUpload) component;
    String clientId = component.getClientId(context);
    ExternalContext externalContext = context.getExternalContext();
    Map<String, String> requestParameterMap = externalContext.getRequestParameterMap();

    if (requestParameterMap.get(clientId) != null) {
            String actionString = requestParameterMap.get(FileUploadConstants.FILE_UPLOAD_ACTION);

            String uid = requestParameterMap.get(FileUploadConstants.UPLOAD_FILES_ID);
           
            if (actionString != null) {
              new UploadAjaxActionEvent(component, actionString, uid).queue();
            }
     
      String fileUploadIndicator = requestParameterMap.get(FileUploadConstants.FILE_UPLOAD_INDICATOR);
      if (fileUploadIndicator != null && Boolean.TRUE.toString().equals(fileUploadIndicator)) {
        decreaseFileCounter(context, clientId);
       
        MultipartRequest multipartRequest = MultipartRequest.lookupRequest(context, uid);
       
        boolean isFlash = (requestParameterMap.get("_richfaces_send_http_error") != null);
       
        List<UploadItem> fileList = multipartRequest.getUploadItems();
       
        if (fileList == null || fileList.size() == 0) {
          return;
        }
       
        boolean formUpload = multipartRequest.isFormUpload();
       
        if (isFlash && !formUpload && fileList.size() > 0) {
          try {
            UploadItem item = fileList.get(0);
            int actualSize = item.getFileSize();
            int clientSize = Integer.parseInt(requestParameterMap.get("_richfaces_size"));
           
            if (actualSize != clientSize) {
              return; // File uploading has been stopped on the client side
            }
          }catch (Exception e) {
            return;
          }
        }
        onUploadComplete(context, fileList, fileUpload, formUpload);
      }
    }
   

  }
 
  /**
   * Put max file count into session scope
   *
   * @param context
   * @param component
   * @param clientId
   * @return
   */
  @SuppressWarnings("unchecked")
  public Integer initMaxFilesCount(FacesContext context,
      UIComponent component, String clientId) {
    Integer max = (Integer) component.getAttributes().get(
        "maxFilesQuantity");
    Object session = context.getExternalContext()
        .getSession(false);
    synchronized (session) {
      Map<String, Integer> map = (Map<String, Integer>) context.getExternalContext().getSessionMap().get(FileUploadConstants.UPLOADED_COUNTER);
      if (map == null) {
        map = Collections
            .synchronizedMap(new HashMap<String, Integer>());
      }
      map.put(clientId, max);
    }
    return max;
  }

  /**
   * Gets form id
   *
   * @param context -
   *            faces context
   * @param component -
   *            component
   * @return String form id
   */
  public String getFormId(FacesContext context, UIComponent component) {
    UIComponent form = AjaxRendererUtils.getNestingForm(component);
    if (form != null) {
      return form.getClientId(context);
    }
    return "";
  }

  /**
   * Generates map with internalized labels to be put into JS
   *
   * @param o
   *            map of labels
   * @return javascript hash map
   */
  public Object _getLabels(Object o) {
    return ScriptUtils.toScript(o);
  }

  /**
   * Gets internalized labels. At the first system is looking for them in
   * appropriate attributes if they are defined. Next search place is
   * application and file upload bundles. If no result - default label value
   * will be set up.
   *
   * @param context
   *            facesContext instance
   * @param component
   *            UIComponent
   * @return map of labels
   */
  public Map<String, String> getLabels(FacesContext context,
      UIComponent component) {
    Map<String, String> labelsMap = new HashMap<String, String>();
    ResourceBundle bundle1 = null;
    ResourceBundle bundle2 = null;
    UIFileUpload fileUpload = (UIFileUpload) component;
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    String messageBundle = context.getApplication().getMessageBundle();
    Object locale = fileUpload.getLocale();
    if (locale == null) {
      locale = context.getExternalContext().getRequestLocale();
    }
    if (null != messageBundle) {
      bundle1 = ResourceBundle.getBundle(messageBundle, fileUpload
          .getAsLocale(locale), loader);
    }
    try {
      bundle2 = ResourceBundle.getBundle(FILE_UPLOAD_BUNDLE, fileUpload
          .getAsLocale(locale), loader);

    } catch (MissingResourceException e) {
      // No external bundle was found, ignore this exception.
    }
    initLabels(labelsMap, bundle1, bundle2, fileUpload);
    return labelsMap;
  }

  /**
   * Sets values for labels.
   *
   * @param map
   *            map of labels
   * @param bundle1
   *            application bundle
   * @param bundle2
   *            file upload bundle
   * @param fileUpload
   */
  private void initLabels(Map<String, String> map, ResourceBundle bundle1,
      ResourceBundle bundle2, UIFileUpload fileUpload) {
    int i = 0;
    for (String name : bundlesLables) {
      boolean found = false;
      if (labelAttribues[i] != null) {
        String attributeName = labelAttribues[i];
        if (fileUpload.getAttributes().get(attributeName) != null) {
          map.put(name, (String) fileUpload.getAttributes().get(
              attributeName));
          found = true;
        }
      }
      if (!found && (bundle1 != null || bundle2 != null)) {
        String label = getFromBundle(name, bundle1, bundle2);
        if (label != null) {
          map.put(name, getFromBundle(name, bundle1, bundle2));
          found = true;
        }
      }
      if (!found) {
        map.put(name, defaultLables[i]);
      }
      i++;
    }
  }

  /**
   * Looking for labels name in bundles provided.
   *
   * @param bundle1
   *            application bundle
   * @param bundle2
   *            file upload bundle
   * @return String label value
   */
  private String getFromBundle(String name, ResourceBundle bundle1,
      ResourceBundle bundle2) {
    name = bundlePrefix + name.toUpperCase() + bundlePostfix;
    String v = null;
    if (bundle1 != null) {
      try {
        v = bundle1.getString(name);
      } catch (Exception e) {
        if (bundle2 != null) {
          try {
            v = bundle2.getString(name);
          } catch (Exception ex) {
            // no value has been found
          }
        }

      }

    } else if (bundle2 != null) {
      try {
        v = bundle2.getString(name);
        ByteArrayOutputStream b = new ByteArrayOutputStream();
        b.write(v.getBytes());
      } catch (Exception e) {
        // no value has been found
      }
    }
    return v;
  }

  /**
   * Method decrease file counter
   *
   * @param context
   * @param id
   */
  @SuppressWarnings("unchecked")
  private void decreaseFileCounter(FacesContext context, String id) {
    Map<String, Integer> map = (Map<String, Integer>) context.getExternalContext().getSessionMap()
        .get(FileUploadConstants.UPLOADED_COUNTER);
    if (map != null) {
      Integer i = map.get(id);
      if (i == null) {
        i = 0;
      } else {
        i--;
      }
      map.put(id, i);
    }
  }

  /**
   * Put uploaded file into data attribute defined
   *
   * @param context
   * @param fileUpload
   * @param file
   */
  @SuppressWarnings("unchecked")
  private void storeData(FacesContext context, UIFileUpload fileUpload,
      List<UploadItem> fileList) {
    ValueExpression data = fileUpload
        .getValueExpression(_FILES_UPLOADED_ATTRIBUTE_NAME);
    if (data != null) {
      if (data.getValue(context.getELContext()) instanceof Collection) {
        Collection collection = (Collection) data.getValue(context
            .getELContext());
        collection.addAll(fileList);
      }
    }
    new UploadEvent(fileUpload, fileList).queue();
  }

  /**
   * Call with method after uploading completed
   *
   * @param context
   * @param file
   * @param fileUpload
   */
  private void onUploadComplete(FacesContext context, List<UploadItem> fileList,
      UIFileUpload fileUpload, boolean formUpload) {
    storeData(context, fileUpload, fileList);
    AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
    if ((Boolean)fileUpload.getAttributes().get(AjaxRendererUtils.AJAX_SINGLE_ATTR)) {
      ajaxContext.setAjaxSingleClientId(fileUpload.getClientId(context));
    }

    ajaxContext.setAjaxRequest(!formUpload);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ajax4jsf.renderkit.RendererBase#getComponentClass()
   */
  @Override
  protected Class<? extends UIComponent> getComponentClass() {
    return UIFileUpload.class;
  }

  /**
   * Generates common JS script by action value
   *
   * @param context
   * @param component
   * @param action
   * @param oncomplete
   * @return
   * @throws IOException
   */
  @SuppressWarnings("unchecked")
  public String getActionScript(FacesContext context, UIComponent component) throws IOException {
    String clientId = component.getClientId(context);
    JSFunction ajaxFunction = AjaxRendererUtils.buildAjaxFunction(component, context);

    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put(FileUploadConstants.FILE_UPLOAD_ACTION, new JSReference("action"));
    parameters.put(FileUploadConstants.UPLOAD_FILES_ID, new JSReference("uid"));
    parameters.put(AjaxRendererUtils.AJAX_SINGLE_ATTR, clientId);
   
    Map options = AjaxRendererUtils.buildEventOptions(context, component, parameters, true);
    options.put("onbeforedomupdate", new JSReference("callback"));
   
    ajaxFunction.addParameter(options);

    JSFunctionDefinition function = new JSFunctionDefinition("uid", "action", "callback");
    function.addParameter("event");
    function.addToBody(ajaxFunction.toScript());

    return function.toScript();
  }
 
  /**
   * https://jira.jboss.org/jira/browse/RF-8053 - public hook to change action URL in portlet environment.
   * @param context
   * @return
   */
  public String getActionUrl(FacesContext context){
    AjaxContext ajaxContext = org.ajax4jsf.context.AjaxContext.getCurrentInstance(context);
    String ajaxActionUrl = ajaxContext.getAjaxActionURL(context);
    return ajaxActionUrl;
  }

  /**
   * Return accepted types map
   *
   * @param context
   * @param component
   * @return
   */
  public Object getAcceptedTypes(FacesContext context, UIComponent component) {
    String acceptedTypes = (String) component.getAttributes().get(
        "acceptedTypes");
    Map<String, Boolean> accepted = new HashMap<String, Boolean>();
    if (acceptedTypes != null && acceptedTypes.length() > 0) {
      acceptedTypes = acceptedTypes.replaceAll("[\\s]", "");
      String[] types = acceptedTypes.split("[,;|]");
      if (types != null) {
        for (String type : types) {
          accepted.put(type.toLowerCase(), true);
        }
      }
    }
    return accepted;
  }

  /**
   * Generates progress label markup
   *
   * @param context
   * @param component
   * @return
   * @throws IOException
   */
  public Object getLabelMarkup(FacesContext context, UIComponent component)
      throws IOException {
    CountingOutputWriter customWriter = new CountingOutputWriter();
    StringBuffer result = null;
    UIComponent label = component.getFacet("label");
    if (label != null) {

      ResponseWriter writer = context.getResponseWriter();

      String defaultRenderKitId = context.getApplication()
      .getDefaultRenderKitId();
      if (null == defaultRenderKitId) {
        defaultRenderKitId = RenderKitFactory.HTML_BASIC_RENDER_KIT;
      }
      RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder
      .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
      RenderKit renderKit = renderKitFactory.getRenderKit(context,
          defaultRenderKitId);

      ResponseWriter responseWriter = renderKit.createResponseWriter(
          customWriter, null, "UTF-8");
      context.setResponseWriter(responseWriter);
      writeScriptBody(context, label, false);
      if (writer != null) {
        context.setResponseWriter(writer);
      }
      result = customWriter.getContent();
    }

    return (result != null) ? new JSLiteral(result.toString())
        : null;
  }

  /**
   * Gets a string representing css specific height of downloaded file list
   * panel.
   *
   * @param component
   *            file upload component
   * @return a string representing css specific height of downloaded file list
   *         panel
   */
  public String getFileListHeight(UIFileUpload component) {
    return HtmlUtil.qualifySize(component.getListHeight());
  }

  /**
   * Gets a string representing css specific width of downloaded file list
   * panel.
   *
   * @param component
   *            file upload component
   * @return a string representing css specific width of downloaded file list
   *         panel
   */
  public String getFileListWidth(UIFileUpload component) {
    return HtmlUtil.qualifySize(component.getListWidth());
  }

  /**
   * Generate component custom events functions
   *
   * @param context
   * @param component
   * @param attributeName
   * @return
   */
  public String getAsEventHandler(FacesContext context,
      UIComponent component, String attributeName) {
    Object eventHandler = RendererUtils.getInstance().getAsEventHandler(
        context, component, attributeName, "");
    if (eventHandler != null) {
      return eventHandler.toString();
    }
    return JSReference.NULL.toScript();
  }

  /**
   * Gets progress bar Id
   *
   * @param context
   * @param component
   * @return
   * @throws IOException
   */
  public String getProgressBarId(FacesContext context, UIComponent component)
      throws IOException {
    return getProgressBar(context, component).getClientId(context);
  }

  /**
   * Renders progress bar
   *
   * @param context
   * @param component
   * @throws IOException
   */
  public void renderProgress(FacesContext context, UIComponent component)
      throws IOException {
    UIComponent progressBar = getProgressBar(context, component);
    renderChild(context, progressBar);
  }

  /**
   * Creates progress bar component
   *
   * @param context
   * @param fileUpload
   * @return
   */
  private UIComponent createProgressBar(FacesContext context,
      UIComponent fileUpload) {
    UIComponent progressBar = fileUpload.getFacet("progress");
    if (null == progressBar) {
      progressBar = context.getApplication().createComponent(
          UIProgressBar.COMPONENT_TYPE);
            progressBar.setId(fileUpload.getId() + "_rich_progress");
    }
    fileUpload.getFacets().put("progress", progressBar);
    return progressBar;
  }

  /**
   * Returns progress bar
   *
   * @param context
   * @param component
   * @return
   */
  public UIComponent getProgressBar(FacesContext context,
      UIComponent component) {
    UIComponent progressBar = component.getFacet("progress");
    if (null == progressBar) {
      progressBar = createProgressBar(context, component);
    }
    progressBar.getAttributes().put("minValue", -1);
   
    ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
    ValueExpression falseExpression = expressionFactory.createValueExpression(
        context.getELContext(),
        "#{" + Boolean.FALSE + "}",
        Boolean.class);
   
    progressBar.setValueExpression("enabled", falseExpression);
    progressBar.setTransient(false);
    return progressBar;
  }
 
 
  /**
   * Returns set of children UIParameters
   * @param context
   * @param component
   * @return
   */
  public Object getChildrenParams(FacesContext context, UIComponent component) {
    Map<String, Object> parameters = new HashMap<String, Object>();
    for (Iterator<UIComponent> iterator = component.getChildren().iterator(); iterator.hasNext();) {
      UIComponent child =  iterator.next();
      if (child instanceof UIParameter) {
        UIParameter p = (UIParameter)child;
        parameters.put(p.getName(), p.getValue());
      }
    }
   
    AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
    Map<String, Object> commonAjaxParameters = ajaxContext.getCommonAjaxParameters();
    if (commonAjaxParameters != null) {
      parameters.putAll(commonAjaxParameters);
    }
   
    return parameters;
  }
 
  public String getSessionId(FacesContext context, UIComponent component) {
    String id = null;
    Object session = context.getExternalContext().getSession(false);
    if (session != null) {
      if (session instanceof HttpSession) {
        id = ((HttpSession) session).getId();
      } else {
        Class<? extends Object> sesssionClass = session.getClass();
        try {
          Method getIdMethod = sesssionClass.getMethod("getId");
          id = (String) getIdMethod.invoke(session);
        } catch (SecurityException e) {
          throw new FacesException(e.getMessage(), e);
        } catch (NoSuchMethodException e) {
          throw new FacesException(e.getMessage(), e);
        } catch (IllegalArgumentException e) {
          throw new FacesException(e.getMessage(), e);
        } catch (IllegalAccessException e) {
          throw new FacesException(e.getMessage(), e);
        } catch (InvocationTargetException e) {
          Throwable cause = e.getCause();
          throw new FacesException(cause.getMessage(), cause);
        }
      }
    }
   
    return id;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.richfaces.renderkit.TemplateEncoderRendererBase#encodeChildren(javax.faces.context.FacesContext,
   *      javax.faces.component.UIComponent)
   */
  @Override
  public void encodeChildren(FacesContext context, UIComponent component)
      throws IOException {
    ; // We should not render children
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ajax4jsf.renderkit.RendererBase#doEncodeChildren(javax.faces.context.ResponseWriter,
   *      javax.faces.context.FacesContext, javax.faces.component.UIComponent)
   */
  @Override
  public void doEncodeChildren(ResponseWriter writer, FacesContext context,
      UIComponent component) throws IOException {
    ; // We should not render children
  }

}
TOP

Related Classes of org.richfaces.renderkit.FileUploadRendererBase

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.