Java tutorial
/* * The MIT License * * Copyright (c) 2012, Cisco Systems, Inc., Max Spring * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.cisco.step.jenkins.plugins.jenkow; import hudson.Util; import hudson.util.FormValidation; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletException; import org.activiti.engine.ProcessEngine; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.DeploymentBuilder; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.ProcessInstance; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; class WfUtil { private static final Logger LOGGER = Logger.getLogger(WfUtil.class.getName()); static FormValidation checkWorkflowName(String value) throws IOException, ServletException { return checkFile(value, JenkowPlugin.getInstance().getRepo().getWorkflowFile(value)); } private static FormValidation checkFile(String value, File f) { if (!StringUtils.isEmpty(value)) { if (!f.exists()) { String url = "descriptorByName/" + JenkowBuilder.class.getName() + "/createWorkflow?wfn=" + value; String msg = "Workflow " + value + " does not exist. " + "<button type=\"button\"" + " onclick=\"javascript:" + "var e=this;" + "new Ajax.Request" + "(" + "'" + url + "'," + "{onSuccess:function(x)" + "{notificationBar.show('Workflow created.',notificationBar.OK);" + "fireEvent($(e).up('TR.validation-error-area').previous().down('INPUT'),'change');" + "}" + "}" + ")" + "\"" + ">" + "Create it now" + "</button>"; return FormValidation.errorWithMarkup(msg); } if (!f.canRead()) return FormValidation.warning("Workflow " + value + " is not readable."); } return FormValidation.ok(); } static String launchWf(PrintStream log, String wfName, String parentName, Integer buildNo) { // test wfNames are full paths, doesn't work as workflow name int p = wfName.lastIndexOf('/'); if (p > -1) { wfName = wfName.substring(p + 1); p = wfName.lastIndexOf('.'); if (p > -1) wfName = wfName.substring(0, p); } LOGGER.finer("WfUtil.launchWf: workflowName=" + wfName); ClassLoader previous = Thread.currentThread().getContextClassLoader(); RuntimeService rtSvc = JenkowEngine.getEngine().getRuntimeService(); try { ProcessDefinition pDef = getDeployedWf(wfName); if (pDef == null) throw new RuntimeException("no deployed process definition for " + wfName); Map<String, Object> varMap = new HashMap<String, Object>(); // TODO 9: move jenkow variables into JenkowProcessData varMap.put("jenkow_build_parent", parentName); varMap.put("jenkow_build_number", buildNo); varMap.put("console", new ConsoleLogger(parentName, buildNo)); JobMD.setJobs(varMap, JobMD.newJobs()); log.println(Consts.UI_PREFIX + ": \"" + wfName + "\" started"); long t = System.currentTimeMillis(); System.out.println("starting process " + pDef.getId()); // TODO 9: why is this blocking???? ProcessInstance proc = rtSvc.startProcessInstanceById(pDef.getId(), varMap); // String procId = startProcess(pDef.getId(),varMap); String procId = proc.getId(); System.out.println("process started procId=" + procId + " (" + (System.currentTimeMillis() - t) + ")"); return procId; } finally { Thread.currentThread().setContextClassLoader(previous); } } static void deployAllToEngine() { File repoDir = JenkowWorkflowRepository.getRepositoryDir(); if (!repoDir.exists()) { LOGGER.info("no workflow source repository"); return; } LOGGER.info("deploying all workflow engine"); RepositoryService repoSvc = JenkowEngine.getEngine().getRepositoryService(); Map<String, Date> deplTimes = new HashMap<String, Date>(); for (Deployment depl : repoSvc.createDeploymentQuery().list()) { //System.out.println(" depl: id="+depl.getId()+" name="+depl.getName()+" time="+depl.getDeploymentTime()); deplTimes.put(depl.getId(), depl.getDeploymentTime()); } Map<String, Date> pDefTimes = new HashMap<String, Date>(); for (ProcessDefinition pDef : repoSvc.createProcessDefinitionQuery().latestVersion().list()) { //System.out.println(" pDef:"+pDef+" deplId="+pDef.getDeploymentId()+" key="+pDef.getKey()); Date t = deplTimes.get(pDef.getDeploymentId()); if (t != null) pDefTimes.put(pDef.getKey(), t); } for (Iterator it = FileUtils.iterateFiles(repoDir, new String[] { Consts.WORKFLOW_EXT }, /*recursive=*/true); it.hasNext();) { File wff = (File) it.next(); String wfn = wff.getName(); int p = wfn.lastIndexOf('.'); if (p > -1) wfn = wfn.substring(0, p); Date prevDeplTime = pDefTimes.get(wfn); //System.out.println(" f="+wff+" wfn="+wfn+" deplTime="+prevDeplTime+" wff.lastModified="+new Date(wff.lastModified())); if (prevDeplTime == null || prevDeplTime.before(new Date(wff.lastModified()))) { try { WfUtil.deployToEngine(wff); } catch (FileNotFoundException e) { LOGGER.log(Level.SEVERE, "file not found " + wff, e); } } } } static void deployToEngine(File wff) throws FileNotFoundException { LOGGER.info("deploying " + wff + " to workflow engine"); ProcessEngine eng = JenkowEngine.getEngine(); RuntimeService rtSvc = eng.getRuntimeService(); RepositoryService repoSvc = eng.getRepositoryService(); String wfn = wff + "20.xml"; // TODO 9: workaround for http://forums.activiti.org/en/viewtopic.php?f=8&t=3745&start=10 DeploymentBuilder db = repoSvc.createDeployment().addInputStream(wfn, new FileInputStream(wff)); // TODO 4: We should avoid redeploying here, if workflow file of a given version(?) is already deployed? Deployment d = db.deploy(); ProcessDefinition pDef = repoSvc.createProcessDefinitionQuery().deploymentId(d.getId()).singleResult(); LOGGER.fine("deployedToEngine(" + wff + ") --> " + pDef); } static ProcessDefinition getDeployedWf(String wfName) { RepositoryService repoSvc = JenkowEngine.getEngine().getRepositoryService(); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("deployed process definitions:"); for (ProcessDefinition pDef : repoSvc.createProcessDefinitionQuery().latestVersion().list()) { LOGGER.fine(" pDef:" + pDef + " id=" + pDef.getId() + " key=" + pDef.getKey() + " name=" + pDef.getName() + " resourceName=" + pDef.getResourceName() + " version=" + pDef.getVersion()); } } ProcessDefinition pDef = repoSvc.createProcessDefinitionQuery().processDefinitionKey(wfName).latestVersion() .singleResult(); LOGGER.fine("getDeployedWf(" + quoted(wfName) + ") --> " + pDef); return pDef; } static void generateWfDiagramTo(String wfName, OutputStream out) throws IOException { ProcessDefinition pDef = getDeployedWf(wfName); InputStream in = JenkowEngine.getEngine().getRepositoryService().getResourceAsStream(pDef.getDeploymentId(), pDef.getDiagramResourceName()); // TODO kk? should use copyStreamAndClose here? Util.copyStream(in, out); } // experimental // synchronized static String startProcess(final String pDefId, final Map<String,Object> vars) throws InterruptedException{ // ProcessEngine eng = JenkowEngine.getEngine(); // final RuntimeService rtSvc = eng.getRuntimeService(); // // System.out.println("current ids:"); // Set<String> ids = new HashSet<String>(); // for (ProcessInstance proc : rtSvc.createProcessInstanceQuery().list()){ // String id = proc.getId(); // System.out.println(" rId="+id); // ids.add(id); // } // for (HistoricProcessInstance proc : eng.getHistoryService().createHistoricProcessInstanceQuery().list()){ // String id = proc.getId(); // System.out.println(" hId="+id); // ids.add(id); // } // // System.out.println("starting process"); // new Thread(new Runnable(){ // @Override // public void run() { // rtSvc.startProcessInstanceById(pDefId,vars); // } // }).start(); // System.out.println("process started"); // // while (true){ // for (ProcessInstance proc : rtSvc.createProcessInstanceQuery().list()){ // String id = proc.getId(); // System.out.println(" found running id="+id); // if (!ids.contains(id)){ // return id; // } // } // for (HistoricProcessInstance proc : eng.getHistoryService().createHistoricProcessInstanceQuery().list()){ // String id = proc.getId(); // System.out.println(" found historic id="+id); // if (!ids.contains(id)){ // return id; // } // } // Thread.sleep(100); // } // } /** * Produces a valid workflow ID out of a given string. * Replaces each invalid character with an underscore. */ static String mkWorkflowId(String s) { if (s == null || s.length() < 1) return s; // TODO 5: figure out what's the actual definition for valid workflow IDs StringBuffer sb = new StringBuffer(); char c = s.charAt(0); sb.append(Character.isJavaIdentifierStart(c) ? c : '_'); for (int i = 1, n = s.length(); i < n; i++) { c = s.charAt(i); sb.append(Character.isJavaIdentifierPart(c) ? c : '_'); } return sb.toString(); } static String quoted(String s) { return (s == null) ? null : "\"" + s + "\""; } }