com.cisco.step.jenkins.plugins.jenkow.WfUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.cisco.step.jenkins.plugins.jenkow.WfUtil.java

Source

/*
 * 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 + "\"";
    }
}