/* * Copyright (c) 2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wso2.carbon.bpel.ui.fileupload; import org.apache.commons.fileupload.FileItem; import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ode.bpel.dd.DeployDocument; import org.apache.ode.bpel.dd.TDeployment; import org.apache.ode.bpel.dd.TInvoke; import org.apache.ode.bpel.dd.TProvide; import org.apache.ode.store.DeploymentUnitDir; import org.wso2.carbon.CarbonConstants; import org.wso2.carbon.CarbonException; import org.wso2.carbon.ui.CarbonUIMessage; import org.wso2.carbon.ui.transports.fileupload.AbstractFileUploadExecutor; import org.wso2.carbon.utils.FileItemData; import org.wso2.carbon.utils.ServerConstants; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.namespace.QName; /** * */ public class BPELUploadExecutor extends AbstractFileUploadExecutor { private static final String[] ALLOWED_FILE_EXTENSIONS = new String[]{".zip"}; private static Log log = LogFactory.getLog(BPELUploadExecutor.class); private static void addDir(File dirObj, ZipOutputStream out, int basePathLen) throws Exception { if (dirObj != null && out != null) { File[] files = dirObj.listFiles(); byte[] tmpBuf = new byte[2048]; if (files != null) { for (File file : files) { if (file.isDirectory()) { addDir(file, out, basePathLen); continue; } FileInputStream in = null; try { in = new FileInputStream(file.getAbsolutePath()); if (log.isDebugEnabled()) { log.debug("Adding: " + file.getAbsolutePath()); } out.putNextEntry(new ZipEntry(file.getAbsolutePath().substring(basePathLen))); int len; while ((len = in.read(tmpBuf)) > 0) { out.write(tmpBuf, 0, len); } } finally { if (in != null) { in.close(); } } } } } } public boolean execute(HttpServletRequest request, HttpServletResponse response) throws CarbonException, IOException { String errMsg; response.setContentType("text/html; charset=utf-8"); PrintWriter out = response.getWriter(); String webContext = (String) request.getAttribute(CarbonConstants.WEB_CONTEXT); String serverURL = (String) request.getAttribute(CarbonConstants.SERVER_URL); String cookie = (String) request.getAttribute(ServerConstants.ADMIN_SERVICE_COOKIE); Map<String, ArrayList<FileItemData>> fileItemsMap = getFileItemsMap(); if (fileItemsMap == null || fileItemsMap.isEmpty()) { String msg = "File uploading failed."; log.error(msg); out.write("<textarea>" + "(function(){i18n.fileUplodedFailed();})();" + "</textarea>"); return true; } BPELUploaderClient uploaderClient = new BPELUploaderClient(configurationContext, serverURL + "BPELUploader", cookie); SaveExtractReturn uploadedFiles = null; ArrayList<String> extractedFiles = new ArrayList<String>(); try { for (FileItemData fieldData : fileItemsMap.get("bpelFileName")) { String fileName = getFileName(fieldData.getFileItem().getName()); //Check filename for \ charactors. This cannot be handled at the lower stages. if (fileName.matches("(.*[\\\\].*[/].*|.*[/].*[\\\\].*)")) { log.error("BPEL Package Validation Failure: one or many of the following illegal characters are " + "in " + "the package.\n ~!@#$;%^*()+={}[]| \\<>"); throw new Exception("BPEL Package Validation Failure: one or many of the following illegal " + "characters " + "are in the package. ~!@#$;%^*()+={}[]| \\<>"); } //Check file extension. checkServiceFileExtensionValidity(fileName, ALLOWED_FILE_EXTENSIONS); if (fileName.lastIndexOf('\\') != -1) { int indexOfColon = fileName.lastIndexOf('\\') + 1; fileName = fileName.substring(indexOfColon, fileName.length()); } if (fieldData.getFileItem().getFieldName().equals("bpelFileName")) { uploadedFiles = saveAndExtractUploadedFile(fieldData.getFileItem()); extractedFiles.add(uploadedFiles.extractedFile); validateBPELPackage(uploadedFiles.extractedFile); DataSource dataSource = new FileDataSource(uploadedFiles.zipFile); uploaderClient.addUploadedFileItem(new DataHandler(dataSource), fileName, "zip"); } } uploaderClient.uploadFileItems(); String msg = "Your BPEL package been uploaded successfully. Please refresh this page in a" + " while to see the status of the new process."; CarbonUIMessage.sendCarbonUIMessage(msg, CarbonUIMessage.INFO, request, response, getContextRoot(request) + "/" + webContext + "/bpel/process_list.jsp"); return true; } catch (Exception e) { errMsg = "File upload failed :" + e.getMessage(); log.error(errMsg, e); CarbonUIMessage.sendCarbonUIMessage(errMsg, CarbonUIMessage.ERROR, request, response, getContextRoot(request) + "/" + webContext + "/bpel/upload_bpel.jsp"); } finally { for (String s : extractedFiles) { File extractedFile = new File(s); if (log.isDebugEnabled()) { log.debug("Cleaning temporarily extracted BPEL artifacts in " + extractedFile.getParent()); } try { FileUtils.cleanDirectory(new File(extractedFile.getParent())); } catch (IOException ex) { log.warn("Failed to clean temporary extractedFile.", ex); } } } return false; } public SaveExtractReturn saveAndExtractUploadedFile(FileItem fileItem) throws Exception { String serviceUploadDir = getTempUploadDir(); File servicesDir = new File(serviceUploadDir); if (!servicesDir.exists() && !servicesDir.mkdirs()) { throw new IOException("Fail to create the directory: " + servicesDir.getAbsolutePath()); } // Writing BPEL archive to file system String fileItemName = getFileName(fileItem.getName()); File uploadedFile = new File(servicesDir, fileItemName); if (log.isDebugEnabled()) { log.debug("[BPELUI]BPEL Archive Path: " + uploadedFile.getAbsolutePath()); } try { fileItem.write(uploadedFile); } catch (Exception e) { log.error("Error occurred while writing file item to file system.", e); throw new Exception("Erorr occurred while writing file item to file system.", e); } String destinationDir = serviceUploadDir + File.separator + fileItemName.substring(0, fileItemName.lastIndexOf('.')); if (log.isDebugEnabled()) { log.debug("[BPELUI]Bpel package location: " + destinationDir); } try { ArchiveExtractor.extract(uploadedFile, destinationDir); } catch (Exception e) { log.error("Error extracting archive.", e); throw new Exception(e); } // Handling backward compatibility issues. If user upload BPEL archive which follows the BPS 1.0.1 archive // format // we need to convert it to new format and upload. File deployXml = new File(destinationDir, "deploy.xml"); if (!deployXml.exists()) { String depXmlSrc = fileItemName.substring(0, fileItemName.lastIndexOf('.')) + File.separator + "deploy.xml"; deployXml = new File(destinationDir, depXmlSrc); if (deployXml.exists() && onlyOneChildDir(destinationDir, fileItemName.substring(0, fileItemName.lastIndexOf('.')))) { String tempUploadDir = getTempUploadDir(); File tempDir = new File(tempUploadDir); if (!tempDir.exists() && !tempDir.mkdirs()) { throw new IOException("Fail to create the directory: " + tempDir.getAbsolutePath()); } String filesToZipParent = destinationDir + File.separator + fileItemName.substring(0, fileItemName.lastIndexOf('.')); String zipLocation = tempDir.getAbsolutePath() + File.separator + fileItemName; try { zip(zipLocation, filesToZipParent); } catch (Exception e) { throw new Exception(e); } return new SaveExtractReturn(zipLocation, filesToZipParent); } throw new Exception("BPEL Archive format error.Please confirm that the file being uploaded is a " + "valid BPEL archive."); } return new SaveExtractReturn(uploadedFile.getAbsolutePath(), destinationDir); } private void zip(String zipFile, String sourceDir) throws Exception { File dirObj = new File(sourceDir); int len = dirObj.getAbsolutePath().length() + 1; ZipOutputStream out = null; try { out = new ZipOutputStream(new FileOutputStream(zipFile)); if (log.isDebugEnabled()) { log.debug("Creating: " + zipFile); } addDir(dirObj, out, len); } finally { if (out != null) { out.close(); } } } private String getTempUploadDir() { String uuid = generateUUID(); String tmpDir = "bpelTemp"; return getWorkingDir() + File.separator + tmpDir + File.separator + uuid + File.separator; } private boolean onlyOneChildDir(String location, String dirNameToCheck) { if (location != null && dirNameToCheck != null) { File parentDir = new File(location); if (parentDir.isDirectory()) { String[] entries = parentDir.list(); if (entries != null && entries.length == 1 && entries[0].equals(dirNameToCheck)) { return true; } } } return false; } public void validateBPELPackage(String directoryPath) throws Exception { DeploymentUnitDir du; try { du = new DeploymentUnitDir(new File(directoryPath)); } catch (IllegalArgumentException iae) { log.error("BPEL Package Validation Failure.", iae); throw new Exception("BPEL Package Validation Failure.", iae); } //check package for illegal charactors which registry does not support. (~!@#$;%^*()+={}[]|\<>) List<File> packageFiles = du.allFiles(); for (File packageFile : packageFiles) { if (!packageFile.getName().matches("[^\\~\\!\\@\\#\\$\\;\\%\\^\\*\\(\\)\\+ " + "/\\=\\{\\}\\[\\]\\\\|\\<\\>\"\\'\\`]+")) { log.error("BPEL Package Validation Failure: one or many of the following illegal characters are in " + "the package.\n ~!@#$;%^*()+={}[]| \\<>\"'`"); throw new Exception("BPEL Package Validation Failure: one or many of the following illegal characters" + " " + "are in the package. ~!@#$;%^*()+={}[]| \\<>\"'`"); } } try { du.compile(); } catch (RuntimeException ce) { log.error("BPEL Process Compilation Failure.", ce); throw new Exception("BPEL Compilation Failure!", ce); } catch (Exception e) { log.error("BPEL Process Compilation Failure.", e); throw new Exception("BPEL Compilation Failure!", e); } du.scan(); DeployDocument dd = du.getDeploymentDescriptor(); for (TDeployment.Process processDD : dd.getDeploy().getProcessList()) { QName processType = processDD.getType() != null ? processDD.getType() : processDD.getName(); DeploymentUnitDir.CBPInfo cbpInfo = du.getCBPInfo(processType); if (cbpInfo == null) { //removeDeploymentArtifacts(deploymentContext, du); String logMessage = "Aborting deployment. Cannot find Process definition for type " + processType + "."; log.error(logMessage); throw new Exception(logMessage); } for (TProvide tProvide : processDD.getProvideList()) { if (tProvide.getService() == null) { String errMsg = "Service element missing for the provide element in deploy.xml"; log.error(errMsg); throw new Exception(errMsg); } } for (TInvoke tInvoke : processDD.getInvokeList()) { if (tInvoke.getService() == null) { String errMsg = "Service element missing for the invoke element in deploy.xml"; log.error(errMsg); throw new Exception(errMsg); } } } } static class SaveExtractReturn { private String zipFile; private String extractedFile; public SaveExtractReturn(String zipFile, String extractedFile) { this.zipFile = zipFile; this.extractedFile = extractedFile; } } }