001    package org.apache.myfaces.tobago.fileupload;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.slf4j.Logger;
021    import org.slf4j.LoggerFactory;
022    import org.apache.myfaces.tobago.internal.util.JndiUtils;
023    import org.apache.myfaces.tobago.internal.webapp.TobagoMultipartFormdataRequest;
024    
025    import javax.faces.FacesException;
026    import javax.faces.application.FacesMessage;
027    import javax.faces.context.FacesContext;
028    import javax.faces.context.FacesContextFactory;
029    import javax.faces.lifecycle.Lifecycle;
030    import javax.naming.InitialContext;
031    import javax.naming.NamingException;
032    import javax.servlet.http.HttpServletRequest;
033    import java.io.File;
034    
035    /**
036     * This FacesContextFactory handles multipart request. Add the tobago-fileupload.jar to your web application.
037     * Configuration:
038     *
039     * <p><blockquote><pre>
040        &lt;env-entry&gt;
041          &lt;description&gt;Set the size limit for uploaded files. Default value is 1 MB.
042            Format: 10 = 10 bytes
043            10k = 10 KB
044            10m = 10 MB
045            1g = 1 GB
046          &lt;/description&gt;
047          &lt;env-entry-name&gt;uploadMaxFileSize&lt;/env-entry-name&gt;
048          &lt;env-entry-type&gt;java.lang.String&lt;/env-entry-type&gt;
049          &lt;env-entry-value&gt;20m&lt;/env-entry-value&gt;
050        &lt;/env-entry&gt;
051        &lt;env-entry&gt;
052          &lt;description&gt;Set the upload repository path for uploaded files.
053                 Default value is java.io.tmpdir.&lt;/description&gt;
054          &lt;env-entry-name&gt;uploadRepositoryPath&lt;/env-entry-name&gt;
055          &lt;env-entry-type&gt;java.lang.String&lt;/env-entry-type&gt;
056          &lt;env-entry-value&gt;/tmp&lt;/env-entry-value&gt;
057        &lt;/env-entry&gt;
058     </pre></blockquote><p>
059    
060     *
061     */
062    public class FileUploadFacesContextFactoryImpl extends FacesContextFactory {
063      private static final Logger LOG = LoggerFactory.getLogger(FileUploadFacesContextFactoryImpl.class);
064      private FacesContextFactory facesContextFactory;
065      private String repositoryPath = System.getProperty("java.io.tmpdir");
066      private long maxSize = TobagoMultipartFormdataRequest.ONE_MB;
067    
068      public FileUploadFacesContextFactoryImpl(FacesContextFactory facesContextFactory) {
069        // TODO get Configuration from env entries in the web.xml or context-param
070        this.facesContextFactory = facesContextFactory;
071        if (LOG.isDebugEnabled()) {
072          LOG.debug("Wrap FacesContext for file upload");
073        }
074        InitialContext ic = null;
075        try {
076          ic = new InitialContext();
077    
078          try {
079            String repositoryPath = (String) JndiUtils.getJndiProperty(ic, "uploadRepositoryPath");
080            if (repositoryPath != null) {
081              File file = new File(repositoryPath);
082              if (!file.exists()) {
083                LOG.error("Given repository Path for "
084                    + getClass().getName() + " " + repositoryPath + " doesn't exists");
085              } else if (!file.isDirectory()) {
086                LOG.error("Given repository Path for "
087                    + getClass().getName() + " " + repositoryPath + " is not a directory");
088              } else {
089                this.repositoryPath = repositoryPath;
090              }
091            }
092          } catch (NamingException ne) {
093            // ignore
094          }
095    
096          try {
097            String size = (String) JndiUtils.getJndiProperty(ic, "uploadMaxFileSize");
098            maxSize = TobagoMultipartFormdataRequest.getMaxSize(size);
099          } catch (NamingException ne) {
100            // ignore
101          }
102        } catch (NamingException e) {
103          // ignore no naming available
104        } finally {
105          if (ic != null) {
106            try {
107              ic.close();
108            } catch (NamingException e) {
109              // ignore
110            }
111          }
112        }
113        if (LOG.isInfoEnabled()) {
114          LOG.info("Configure uploadMaxFileSize for "+ getClass().getName() + " to "+ this.maxSize);
115          LOG.info("Configure uploadRepositryPath for "+ getClass().getName() + " to "+ this.repositoryPath);
116        }
117      }
118    
119      public FacesContext getFacesContext(Object context, Object request, Object response, Lifecycle lifecycle)
120          throws FacesException {
121        if (request instanceof HttpServletRequest && !(request instanceof TobagoMultipartFormdataRequest)) {
122          String contentType = ((HttpServletRequest) request).getContentType();
123          if (contentType != null && contentType.toLowerCase().startsWith("multipart/form-data")) {
124            if (LOG.isDebugEnabled()) {
125              LOG.debug("Wrap HttpServletRequest for file upload");
126            }
127            try {
128              request = new TobagoMultipartFormdataRequest((HttpServletRequest) request, repositoryPath, maxSize);
129            } catch (FacesException e) {
130              LOG.error("", e);
131              FacesContext facesContext = facesContextFactory.getFacesContext(context, request, response, lifecycle);
132              // TODO  better Message i18n Message?
133              FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getCause().getMessage(), null);
134              facesContext.addMessage(null, facesMessage);
135              facesContext.renderResponse();
136              return facesContext;
137            }
138          }
139        }
140        return facesContextFactory.getFacesContext(context, request, response, lifecycle);
141      }
142    }