Java tutorial
/* * Copyright (C) 2007-2013 Crafter Software Corporation. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.craftercms.deployer.git.processor; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.text.StrSubstitutor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.craftercms.cstudio.publishing.PublishedChangeSet; import org.craftercms.cstudio.publishing.exception.PublishingException; import org.craftercms.cstudio.publishing.servlet.FileUploadServlet; import org.craftercms.deployer.git.config.SiteConfiguration; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.*; import java.util.regex.Pattern; public class ShellProcessor extends AbstractPublishingProcessor { private static final String INCLUDE_FILTER_PARAM = "includeFilter"; private static final String INCLUDE_FILES_ARG = "files"; private static Log LOGGER = LogFactory.getLog(ShellProcessor.class); private String workingDir; private String command; private Map<String, String> arguments; private Map<String, String> enviroment; private String sourceFiles; private boolean asSingleCommand; @Override public void doProcess(SiteConfiguration siteConfiguration, PublishedChangeSet changeSet) throws PublishingException { checkConfiguration(siteConfiguration); LOGGER.debug("Starting Shell Processor"); ProcessBuilder builder = new ProcessBuilder(); builder.directory(getWorkingDir(workingDir, siteConfiguration.getSiteId())); LOGGER.debug("Working directory is " + workingDir); HashMap<String, String> argumentsMap = buildArgumentsMap(getFileList(changeSet)); if (asSingleCommand) { StrSubstitutor substitutor = new StrSubstitutor(argumentsMap, "%{", "}"); String execComand = substitutor.replace(command); LOGGER.debug("Command to be Executed is " + execComand); builder.command("/bin/bash", "-c", execComand); } else { Set<String> keys = argumentsMap.keySet(); ArrayList<String> commandAsList = new ArrayList<String>(); commandAsList.add(command.trim()); for (String key : keys) { if (!key.equalsIgnoreCase(INCLUDE_FILTER_PARAM)) { commandAsList.add(argumentsMap.get(key)); } } LOGGER.debug("Command to be Executed is " + StringUtils.join(commandAsList, " ")); builder.command(commandAsList); } builder.environment().putAll(enviroment); builder.redirectErrorStream(true); try { Process process = builder.start(); process.waitFor(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String str; while ((str = reader.readLine()) != null) { LOGGER.info("PROCESS OUTPUT :" + str); } reader.close(); LOGGER.info("Process Finish with Exit Code " + process.exitValue()); LOGGER.debug("Process Output "); } catch (IOException ex) { LOGGER.error("Error ", ex); } catch (InterruptedException e) { LOGGER.error("Error ", e); } finally { LOGGER.debug("End of Shell Processor"); } } private File getWorkingDir(final String workingDir, final String siteId) { String actualWorkingDir = workingDir; if (actualWorkingDir.contains("{siteId}")) { actualWorkingDir = actualWorkingDir.replaceAll(FileUploadServlet.CONFIG_MULTI_TENANCY_VARIABLE, siteId); } return new File(actualWorkingDir); } /** * Generates a unmodifiableList list with the merge of the changeset files<br> * If {@link FILES_SOURCE} : * <ul> * <li>Null will merge delete, create and updated files</li> * <li>If "UPDATED" only updated files</li> * <li>If "NEW" only created files</li> * <li>If "EXISTENT" created and updated files</li> * <li>If "DELETED" only delete files</li> * </ul> * * @param parameters Map to get {@link FILES_SOURCE} * @param changeSet Changeset where the deleted,created and updated files are. * @return A unmodifiableList depending on {@link FILES_SOURCE} <br/> * <b> Empty</b> if {@link FILES_SOURCE} is no valid */ @SuppressWarnings("unchecked") private List<String> getFileList(PublishedChangeSet changeSet) { List<String> result = new ArrayList<String>(); if (sourceFiles == null) { result = mergeList(changeSet.getCreatedFiles(), changeSet.getDeletedFiles(), changeSet.getUpdatedFiles()); } else if (sourceFiles.equalsIgnoreCase("UPDATED")) { result = mergeList(changeSet.getUpdatedFiles()); } else if (sourceFiles.equalsIgnoreCase("NEW")) { result = mergeList(changeSet.getCreatedFiles()); } else if (sourceFiles.equalsIgnoreCase("EXISTENT")) { result = mergeList(changeSet.getCreatedFiles(), changeSet.getUpdatedFiles()); } else if (sourceFiles.equalsIgnoreCase("DELETED")) { result = mergeList(changeSet.getDeletedFiles()); } else { LOGGER.debug("Parameter " + sourceFiles + " has a non valid value, valid values (UPDATED,NEW,EXISTENT," + "DELETE)"); LOGGER.debug("Due non valid " + sourceFiles + " value returning empty list"); } for (int i = 0; i < result.size(); i++) { result.set(i, result.get(i).substring(1)); } return Collections.unmodifiableList(result); } /** * Checks that all configuration is ok and set defaults if necessary * * @param parameters Parameters of the Processors * @param target Target in which the processor is running * @throws PublishingException If some of the given configuration is wrong */ private void checkConfiguration(SiteConfiguration siteConfiguration) throws PublishingException { if (workingDir == null) { // Set a default one workingDir = buildContentPath(siteConfiguration); LOGGER.debug("working Dir is not set, using " + workingDir + " as default"); } else { if (!getWorkingDir(workingDir, siteConfiguration.getSiteId()).exists()) { LOGGER.error("The path " + workingDir + " does not exist"); throw new PublishingException("The path " + workingDir + " does not exist"); } } if (command == null) { LOGGER.error("Command can't be Null"); throw new PublishingException("Command can't be Null"); } if (enviroment == null) { LOGGER.debug("There are non Enviroment Variables Overrides"); enviroment = new HashMap<String, String>(); } else { LOGGER.debug("Enviroment Overrides are " + enviroment.toString()); } if (sourceFiles == null) { LOGGER.debug("Using all files to apply " + INCLUDE_FILTER_PARAM); } } /** * Build Default Path from targets parameters * * @param target Target to base build of the root * @return Relative to working directory path of where the content should be * @throws PublishingException If Working dir can't be calculated */ protected String buildContentPath(SiteConfiguration siteConfiguration) throws PublishingException { LOGGER.debug("Building root Path"); File directory = new File("."); String path = ""; if (new File(siteConfiguration.getLocalRepositoryRoot()).exists()) { path = siteConfiguration.getLocalRepositoryRoot(); } else { path = directory.getAbsolutePath().subSequence(0, directory.getAbsolutePath().length() - 2) + File.separator + siteConfiguration.getLocalRepositoryRoot(); } LOGGER.debug("Build path is " + path); return path; } protected HashMap<String, String> buildArgumentsMap(List<String> files) { HashMap<String, String> result = new HashMap<String, String>(); if (arguments != null) { result.putAll(arguments); } String filter = result.get(INCLUDE_FILTER_PARAM); if (filter != null) { List<String> filterFiles = new ArrayList<String>(); Pattern patter = Pattern.compile(filter); for (String file : files) { if (patter.matcher(file).matches()) { LOGGER.debug("File " + file + " Match " + filter); filterFiles.add(file); } else { LOGGER.debug("File Don't " + file + " don't match " + filter); } } result.put(INCLUDE_FILES_ARG, StringUtils.join(filterFiles, " ")); } return result; } public String getWorkingDir() { return workingDir; } public void setWorkingDir(String workingDir) { this.workingDir = workingDir; } public String getCommand() { return command; } public void setCommand(String command) { this.command = command; } public Map<String, String> getArguments() { return arguments; } public void setArguments(Map<String, String> arguments) { this.arguments = arguments; } public Map<String, String> getEnviroment() { return enviroment; } public void setEnviroment(Map<String, String> enviroment) { this.enviroment = enviroment; } public String getSourceFiles() { return sourceFiles; } public void setSourceFiles(String sourceFiles) { this.sourceFiles = sourceFiles; } public boolean isAsSingleCommand() { return asSingleCommand; } public void setAsSingleCommand(boolean asSingleCommand) { this.asSingleCommand = asSingleCommand; } private <T> List<T> mergeList(List<T>... mergeWith) { ArrayList<T> mergeTo = new ArrayList<T>(); for (List<T> toMerge : mergeWith) { if (toMerge != null) { mergeTo.addAll(toMerge); } } return mergeTo; } }