/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 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. 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.bpm.console.server; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.bpm.console.client.model.ProcessInstanceRef; import org.jboss.bpm.console.server.integration.ManagementFactory; import org.jboss.bpm.console.server.integration.ProcessManagement; import org.jboss.bpm.console.server.integration.TaskManagement; import org.jboss.bpm.console.server.plugin.FormAuthorityRef; import org.jboss.bpm.console.server.plugin.FormDispatcherPlugin; import org.jboss.bpm.console.server.plugin.PluginMgr; import org.jboss.bpm.console.server.util.RsComment; import org.jboss.resteasy.plugins.providers.multipart.InputPart; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * @author Heiko.Braun <heiko.braun@jboss.com> */ @Path("form") @RsComment( title = "Form Processing", description = "Web based form processing" ) public class FormProcessingFacade { private static final Log log = LogFactory.getLog(FormProcessingFacade.class); private FormDispatcherPlugin formPlugin; private ProcessManagement processManagement; private TaskManagement taskManagement; private static final String SUCCESSFULLY_PROCESSED_INPUT = "<div style='font-family:sans-serif; padding:10px;'>" + "<h3>Successfully processed input</h3><p/>" + "You can now close this window." + "</div>"; /** * Lazy load the {@link org.jboss.bpm.console.server.integration.TaskManagement} */ private TaskManagement getTaskManagement() { if(null==this.taskManagement) { ManagementFactory factory = ManagementFactory.newInstance(); this.taskManagement = factory.createTaskManagement(); log.debug("Using ManagementFactory impl:" + factory.getClass().getName()); } return this.taskManagement; } private ProcessManagement getProcessManagement() { if(null==this.processManagement) { ManagementFactory factory = ManagementFactory.newInstance(); this.processManagement = factory.createProcessManagement(); log.debug("Using ManagementFactory impl:" + factory.getClass().getName()); } return this.processManagement; } /** * Lazy load the {@link org.jboss.bpm.console.server.integration.TaskManagement} */ private FormDispatcherPlugin getFormDispatcherPlugin() { if(null==this.formPlugin) { this.formPlugin = PluginMgr.load(FormDispatcherPlugin.class); log.debug("Using FormDispatcherPlugin impl:" + this.formPlugin); } return this.formPlugin; } @GET @Path("task/{id}/render") @Produces("text/html") public Response renderTaskUI( @PathParam("id") String taskId ) { return provideForm(new FormAuthorityRef(taskId)); } @GET @Path("process/{id}/render") @Produces("text/html") public Response renderProcessUI( @PathParam("id") String definitionId ) { return provideForm(new FormAuthorityRef(definitionId, FormAuthorityRef.Type.PROCESS)); } @POST @Path("task/{id}/complete") @Produces("text/html") @Consumes("multipart/form-data") public Response closeTaskWithUI( @Context HttpServletRequest request, @PathParam("id") String taskId, MultipartFormDataInput payload ) { FieldMapping mapping = createFieldMapping(payload); // complete task String username = request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null; String outcomeDirective = mapping.directives.get("outcome"); if(outcomeDirective!=null) { getTaskManagement().completeTask( Long.valueOf(taskId), // TODO: change to string id's outcomeDirective, // actually a plugin implementation detail mapping.processVars, username ); } else { getTaskManagement().completeTask( Long.valueOf(taskId), mapping.processVars, username ); } return Response.ok(SUCCESSFULLY_PROCESSED_INPUT).build(); } @POST @Path("process/{id}/complete") @Produces("text/html") @Consumes("multipart/form-data") public Response startProcessWithUI( @Context HttpServletRequest request, @PathParam("id") String definitionId, MultipartFormDataInput payload ) { FieldMapping mapping = createFieldMapping(payload); // start process ProcessInstanceRef instance = getProcessManagement().newInstance(definitionId, mapping.processVars); return Response.ok(SUCCESSFULLY_PROCESSED_INPUT).build(); } private Response provideForm(FormAuthorityRef authorityRef) { DataHandler dh = getFormDispatcherPlugin().provideForm( authorityRef ); if(null==dh) { throw new RuntimeException("No UI associated with "+authorityRef.getType()+" " + authorityRef.getReferenceId()); } return Response.ok(dh.getDataSource()).type("text/html").build(); } private FieldMapping createFieldMapping(MultipartFormDataInput payload) { FieldMapping mapping = new FieldMapping(); Map<String, InputPart> formData = payload.getFormData(); Iterator<String> partNames = formData.keySet().iterator(); while(partNames.hasNext()) { final String partName = partNames.next(); final InputPart part = formData.get(partName); final MediaType mediaType = part.getMediaType(); if(MediaType.TEXT_PLAIN_TYPE.equals(mediaType)) { // RFC2045: Each part has an optional "Content-Type" header // that defaults to "text/plain". // Can go into process without conversion if(mapping.isReserved(partName)) mapping.directives.put(partName, part.getBodyAsString()); else mapping.processVars.put(partName, part.getBodyAsString()); } else { // anything else turns into a DataHandler final byte[] data = part.getBodyAsString().getBytes(); DataHandler dh = new DataHandler( new DataSource() { public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(data); } public OutputStream getOutputStream() throws IOException { throw new RuntimeException("This is a readonly DataHandler"); } public String getContentType() { return mediaType.getType(); } public String getName() { return partName; } } ); mapping.processVars.put(partName, dh); } } return mapping; } private class FieldMapping { final String[] reservedNames = {"outcome", "form"}; // TODO: implementation detail of the form plugin Map<String,Object> processVars = new HashMap<String,Object>(); Map<String,String> directives = new HashMap<String,String>(); public boolean isReserved(String name) { boolean result = false; for(String s : reservedNames) { if(s.equals(name)) { result = true; break; } } return result; } } }