org.jbpm.bpel.web.DeploymentServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.jbpm.bpel.web.DeploymentServlet.java

Source

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the JBPM BPEL PUBLIC LICENSE AGREEMENT as
 * published by JBoss Inc.; either version 1.0 of the License, or
 * (at your option) any later version.
 *
 * This software 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.
 */
package org.jbpm.bpel.web;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.ZipInputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.bpel.BpelException;
import org.jbpm.bpel.graph.def.BpelProcessDefinition;
import org.jbpm.bpel.persistence.db.BpelGraphSession;
import org.jbpm.bpel.tools.WebModuleBuilder;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.jpdl.par.ProcessArchive;

/**
 * @author Alejandro Guizar
 * @version $Revision$ $Date: 2007/11/29 10:14:01 $
 */
public class DeploymentServlet extends HttpServlet {

    private JbpmConfiguration jbpmConfiguration;
    private File deployDirectory;

    /** Servlet parameter: deploy directory. */
    public static final String PARAM_DEPLOY_DIRECTORY = "deployDirectory";

    /** Request parameter: process archive. */
    public static final String PARAM_PROCESS_ARCHIVE = "processArchive";

    private static final long serialVersionUID = 1L;

    private static final Pattern fileSeparatorPattern = compileFileSeparatorPattern();

    private static final Log log = LogFactory.getLog(DeploymentServlet.class);

    public void init() throws ServletException {
        // jbpm configuration
        String configResource = getServletContext().getInitParameter(WebConstants.PARAM_CONFIG_RESOURCE);
        jbpmConfiguration = JbpmConfiguration.getInstance(configResource);

        // deploy directory
        String deployDirectoryName = getInitParameter(PARAM_DEPLOY_DIRECTORY);
        if (deployDirectoryName == null) {
            // deduce the deploy directory from environment information
            String serverHomeDirectory;
            try {
                serverHomeDirectory = System.getProperty("jboss.server.home.dir");
            } catch (SecurityException e) {
                serverHomeDirectory = null;
            }
            if (serverHomeDirectory == null)
                throw new ServletException("servlet parameter not found: " + PARAM_DEPLOY_DIRECTORY);

            deployDirectoryName = serverHomeDirectory + File.separatorChar + "deploy";
            // TODO what about servers other than jboss?
        }

        deployDirectory = new File(deployDirectoryName);
        if (!deployDirectory.exists())
            throw new ServletException("deploy directory does not exist: " + deployDirectory);
    }

    private static Pattern compileFileSeparatorPattern() {
        String expression = "[/\\\\]";
        if (File.separatorChar != '/' && File.separatorChar != '\\') {
            expression = new StringBuffer(expression).insert(expression.length() - 2, File.separatorChar)
                    .toString();
        }
        return Pattern.compile(expression);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // parse request
        parseRequest(request);
        // read and deploy process definition
        FileItem fileItem = (FileItem) request.getAttribute(PARAM_PROCESS_ARCHIVE);
        String fileName = extractFileName(fileItem.getName());
        ProcessDefinition processDefinition = readProcessDefinition(fileItem.getInputStream(), fileName);
        deployProcessDefinition(processDefinition, fileName);
        // transfer web flow
        response.sendRedirect("processes.jsp");
    }

    private void parseRequest(HttpServletRequest request) throws ServletException, IOException {
        if (!ServletFileUpload.isMultipartContent(request))
            throw new ServletException("request does not have multipart content");

        try {
            ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
            List items = upload.parseRequest(request);
            if (items.size() != 1)
                throw new ServletException("deployment request must contain exactly one parameter");

            request.setAttribute(PARAM_PROCESS_ARCHIVE, parseProcessArchive((FileItem) items.get(0)));
        } catch (FileUploadException e) {
            throw new ServletException("could not parse upload request", e);
        }
    }

    private FileItem parseProcessArchive(FileItem processItem) throws ServletException {
        if (!PARAM_PROCESS_ARCHIVE.equals(processItem.getFieldName())) {
            throw new ServletException(
                    "expected parameter '" + PARAM_PROCESS_ARCHIVE + "', found: " + processItem.getFieldName());
        }

        if (processItem.isFormField()) {
            throw new ServletException("parameter '" + PARAM_PROCESS_ARCHIVE + "' is not an uploaded file");
        }

        String contentType = processItem.getContentType();
        if (!contentType.startsWith(WebConstants.CONTENT_TYPE_ZIP)
                && !contentType.startsWith(WebConstants.CONTENT_TYPE_X_ZIP_COMPRESSED)) {
            throw new ServletException("parameter '" + PARAM_PROCESS_ARCHIVE
                    + "' is expected to have content type '" + WebConstants.CONTENT_TYPE_ZIP + "' or '"
                    + WebConstants.CONTENT_TYPE_X_ZIP_COMPRESSED + "', found: " + contentType);
        }

        return processItem;
    }

    private static String extractFileName(String filePath) {
        /*
         * PORTABILITY INFO. Some browsers (e.g. internet explorer) send the file's
         * absolute path. If this servlet ran on the client side, it could leverage
         * the File class to extract the file name. However, since the separator
         * char may differ between the client and the server, File is not reliable.
         * This code splits the path around matches of all known file separators and
         * takes the last fragment as the file name.
         */
        String[] fragments = fileSeparatorPattern.split(filePath);
        return fragments[fragments.length - 1];
    }

    private ProcessDefinition readProcessDefinition(InputStream fileSource, String fileName) throws IOException {
        try {
            ProcessArchive processArchive = new ProcessArchive(new ZipInputStream(fileSource));
            log.debug("loaded process archive: " + fileName);

            ProcessDefinition processDefinition = processArchive.parseProcessDefinition();
            log.debug("read process definition: " + processDefinition.getName());

            return processDefinition;
        } finally {
            fileSource.close();
        }
    }

    private void deployProcessDefinition(ProcessDefinition processDefinition, String fileName) {
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        try {
            if (processDefinition instanceof BpelProcessDefinition) {
                BpelProcessDefinition bpelProcessDefinition = (BpelProcessDefinition) processDefinition;
                BpelGraphSession.getContextInstance(jbpmContext).deployProcessDefinition(bpelProcessDefinition);
                deployWebModule(bpelProcessDefinition, fileName);
            } else {
                jbpmContext.deployProcessDefinition(processDefinition);
            }
            log.info("deployed process definition: " + processDefinition.getName());
        } catch (RuntimeException e) {
            jbpmContext.setRollbackOnly();
            throw e;
        } finally {
            jbpmContext.close();
        }
    }

    private void deployWebModule(BpelProcessDefinition processDefinition, String fileName) {
        File moduleFile = new File(deployDirectory, extractFilePrefix(fileName) + ".war");

        WebModuleBuilder builder = new WebModuleBuilder();
        builder.setModuleFile(moduleFile);
        builder.buildModule(processDefinition);

        if (builder.getProblemHandler().getProblemCount() > 0)
            throw new BpelException("could not build web module for: " + processDefinition);

        log.info("deployed web module: " + moduleFile.getName());
    }

    private static String extractFilePrefix(String fileName) {
        int dotIndex = fileName.lastIndexOf('.');
        return dotIndex != -1 ? fileName.substring(0, dotIndex) : fileName;
    }
}