001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.web;
017
018import java.io.File;
019import java.io.IOException;
020import java.io.InputStream;
021import java.util.List;
022import javax.jcr.Binary;
023import javax.jcr.Node;
024import javax.jcr.Session;
025import javax.jcr.ValueFactory;
026import javax.servlet.ServletContext;
027import javax.servlet.ServletException;
028import javax.servlet.http.HttpServlet;
029import javax.servlet.http.HttpServletRequest;
030import javax.servlet.http.HttpServletResponse;
031import org.apache.commons.fileupload.FileItem;
032import org.apache.commons.fileupload.FileUploadException;
033import org.apache.commons.fileupload.disk.DiskFileItemFactory;
034import org.apache.commons.fileupload.servlet.ServletFileUpload;
035import org.modeshape.common.logging.Logger;
036import org.modeshape.web.server.Connector;
037
038/**
039 *
040 * @author kulikov
041 */
042public class BinaryContentUploadServlet extends HttpServlet {
043
044    private static final long serialVersionUID = 1505304380334878522L;
045
046    private final static String CONTENT_PARAMETER = "Upload content";
047    private final static String REPOSITORY_NAME_PARAMETER = "repository";
048    private final static String WORKSPACE_NAME_PARAMETER = "workspace";
049    private final static String NODE_PATH_PARAMETER = "path";
050    private final static String PROPERTY_NAME_PARAMETER = "pname";
051    private final static String REPOSITORY_CONNECTOR = "connector";
052    private final static String MIME_TYPE = "jcr:mimeType";
053    private final static String DESTINATION_URL = "/tree/%s/ws-%s%s";
054    
055    private ServletFileUpload upload;
056    private final Logger logger = Logger.getLogger(BinaryContentServlet.class);
057
058    /**
059     * Processes requests for both HTTP
060     * <code>GET</code> and
061     * <code>POST</code> methods.
062     *
063     * @param request servlet request
064     * @param response servlet response
065     * @throws ServletException if a servlet-specific error occurs
066     * @throws IOException if an I/O error occurs
067     */
068    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
069            throws ServletException, IOException {
070        List<FileItem> items;
071        // Parse the request
072        try {
073            items = upload.parseRequest(request);
074        } catch (FileUploadException e) {
075            throw new ServletException(e);
076        }
077
078        String repository = getParameter(items, REPOSITORY_NAME_PARAMETER);
079        String workspace = getParameter(items, WORKSPACE_NAME_PARAMETER);
080        String path = getParameter(items, NODE_PATH_PARAMETER);
081        String pname = getParameter(items, PROPERTY_NAME_PARAMETER);
082        
083        if (logger.isDebugEnabled()) {
084            logger.debug(String.format("Upload %s at %s/%s%s", 
085                    pname, repository, workspace, path));
086        }
087        
088        String mimeType = getContentType(items);
089        Connector connector = (Connector) 
090                request.getSession().getAttribute(REPOSITORY_CONNECTOR);
091        
092        try {
093            Session session = connector.find(repository).session(workspace);
094            ValueFactory valueFactory = session.getValueFactory(); 
095            Binary bin = valueFactory.createBinary(getStream(items));
096            
097            Node node = session.getNode(path);
098            node.setProperty(pname, bin);
099            node.setProperty(MIME_TYPE, mimeType);
100            bin.dispose();
101        } catch (Exception e) {
102            throw new ServletException(e);
103        }
104        
105        String uri = request.getContextPath() + 
106                String.format(DESTINATION_URL, repository, workspace, path);
107        response.sendRedirect(uri);
108    }
109
110    /**
111     * Extracts value of the parameter with given name.
112     *
113     * @param items
114     * @param name
115     * @return parameter value or null.
116     */
117    private String getParameter(List<FileItem> items, String name) {
118        for (FileItem i : items) {
119            if (i.isFormField() && i.getFieldName().equals(name)) {
120                return i.getString();
121            }
122        }
123        return null;
124    }
125    
126    /**
127     * Gets uploaded file as stream.
128     * 
129     * @param items
130     * @return the stream
131     * @throws IOException 
132     */
133    private InputStream getStream(List<FileItem> items) throws IOException {
134        for (FileItem i : items) {
135            if (!i.isFormField() && i.getFieldName().equals(CONTENT_PARAMETER)) {
136                return i.getInputStream();
137            }
138        }
139        return null;
140    }
141    
142    /**
143     * Determines content-type of the uploaded file.
144     * 
145     * @param items
146     * @return the content type
147     */
148    private String getContentType(List<FileItem> items) {
149        for (FileItem i : items) {
150            if (!i.isFormField() && i.getFieldName().equals(CONTENT_PARAMETER)) {
151                return i.getContentType();
152            }
153        }
154        return null;
155    }
156    
157    @Override
158    public void init() {
159        DiskFileItemFactory diskFactory = new DiskFileItemFactory();
160
161        // Configure a repository (to ensure a secure temp location is used)
162        ServletContext servletContext = this.getServletConfig().getServletContext();
163        File tempDir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
164        diskFactory.setRepository(tempDir);
165
166        // Create a new file upload handler
167        upload = new ServletFileUpload(diskFactory);
168    }
169    
170    
171    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
172
173    /**
174     * Handles the HTTP
175     * <code>GET</code> method.
176     *
177     * @param request servlet request
178     * @param response servlet response
179     * @throws ServletException if a servlet-specific error occurs
180     * @throws IOException if an I/O error occurs
181     */
182    @Override
183    protected void doGet(HttpServletRequest request, HttpServletResponse response)
184            throws ServletException, IOException {
185        processRequest(request, response);
186    }
187
188    /**
189     * Handles the HTTP
190     * <code>POST</code> method.
191     *
192     * @param request servlet request
193     * @param response servlet response
194     * @throws ServletException if a servlet-specific error occurs
195     * @throws IOException if an I/O error occurs
196     */
197    @Override
198    protected void doPost(HttpServletRequest request, HttpServletResponse response)
199            throws ServletException, IOException {
200        processRequest(request, response);
201    }
202
203    /**
204     * Returns a short description of the servlet.
205     *
206     * @return a String containing servlet description
207     */
208    @Override
209    public String getServletInfo() {
210        return "Short description";
211    }// </editor-fold>
212}