├── plugin ├── src │ └── main │ │ ├── resources │ │ └── index.jelly │ │ ├── webapp │ │ ├── activiti-logo.xcf │ │ └── images │ │ │ ├── 24x24 │ │ │ └── activiti.png │ │ │ └── 48x48 │ │ │ └── activiti.png │ │ └── java │ │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── activiti_explorer │ │ ├── XmlPatcher.java │ │ └── ActivitiExplorer.java └── pom.xml ├── dto ├── src │ └── main │ │ └── java │ │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── activiti_explorer │ │ └── dto │ │ └── UserDTO.java └── pom.xml ├── activiti-explorer-override ├── src │ └── main │ │ └── java │ │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── jenkow │ │ └── activiti │ │ └── override │ │ ├── JenkinsMainMenuBar.java │ │ ├── JenkinsManagementMenuBar.java │ │ ├── ExplorerApp2.java │ │ ├── JenkinsProcessEngineFactory.java │ │ ├── JenkinsComponentFactories.java │ │ ├── ServletContextDataSource.java │ │ ├── JenkinsUser.java │ │ └── JenkinsLoginHandler.java └── pom.xml └── pom.xml /plugin/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 |
2 | Embeds Activiti Explorer inside Jenkins 3 |
4 | -------------------------------------------------------------------------------- /plugin/src/main/webapp/activiti-logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/activiti-explorer-plugin/master/plugin/src/main/webapp/activiti-logo.xcf -------------------------------------------------------------------------------- /plugin/src/main/webapp/images/24x24/activiti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/activiti-explorer-plugin/master/plugin/src/main/webapp/images/24x24/activiti.png -------------------------------------------------------------------------------- /plugin/src/main/webapp/images/48x48/activiti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/activiti-explorer-plugin/master/plugin/src/main/webapp/images/48x48/activiti.png -------------------------------------------------------------------------------- /dto/src/main/java/org/jenkinsci/plugins/activiti_explorer/dto/UserDTO.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.activiti_explorer.dto; 2 | 3 | /** 4 | * @author Kohsuke Kawaguchi 5 | */ 6 | public class UserDTO { 7 | public String id, firstName, lastName, fullName, email; 8 | 9 | public boolean isAdmin, isUser; 10 | } 11 | -------------------------------------------------------------------------------- /activiti-explorer-override/src/main/java/org/jenkinsci/plugins/jenkow/activiti/override/JenkinsMainMenuBar.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.jenkow.activiti.override; 2 | 3 | import org.activiti.explorer.ui.alfresco.AlfrescoMainMenuBar; 4 | import org.activiti.explorer.ui.mainlayout.MainMenuBar; 5 | 6 | /** 7 | * Customize the main menu bar to get rid of the profile link 8 | * 9 | * @author Kohsuke Kawaguchi 10 | * @see AlfrescoMainMenuBar 11 | */ 12 | public class JenkinsMainMenuBar extends MainMenuBar { 13 | @Override 14 | protected boolean useProfile() { 15 | // profile is not editable 16 | return false; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /activiti-explorer-override/src/main/java/org/jenkinsci/plugins/jenkow/activiti/override/JenkinsManagementMenuBar.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.jenkow.activiti.override; 2 | 3 | import org.activiti.explorer.ui.alfresco.AlfrescoManagementMenuBar; 4 | import org.activiti.explorer.ui.management.ManagementMenuBar; 5 | 6 | /** 7 | * Get rid of the users and groups UI because we won't let those things edited in Activiti 8 | * 9 | * @author Kohsuke Kawaguchi 10 | * @see AlfrescoManagementMenuBar 11 | */ 12 | public class JenkinsManagementMenuBar extends ManagementMenuBar { 13 | protected void addUsersToolbarEntry() { 14 | } 15 | 16 | protected void addGroupToolbarEntry() { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dto/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.jenkins-ci.plugins 7 | activiti-explorer-plugin-parent 8 | 1.0-SNAPSHOT 9 | 10 | 11 | activiti-explorer-dto 12 | Serializable objects that are passed between AE and Jenkins to carry information back and forth 13 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /activiti-explorer-override/src/main/java/org/jenkinsci/plugins/jenkow/activiti/override/ExplorerApp2.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.jenkow.activiti.override; 2 | 3 | import org.activiti.explorer.ExplorerApp; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | /** 9 | * @author Kohsuke Kawaguchi 10 | */ 11 | public class ExplorerApp2 extends ExplorerApp { 12 | @Override 13 | public void onRequestStart(HttpServletRequest request, HttpServletResponse response) { 14 | // AE caches the logged in user into a session, which means it won't notice when the user logs out in Jenkins 15 | // or logs in. Our JenkinsLoginHandler is efficient, no need to cache this. 16 | setUser(null); 17 | 18 | super.onRequestStart(request, response); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /activiti-explorer-override/src/main/java/org/jenkinsci/plugins/jenkow/activiti/override/JenkinsProcessEngineFactory.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.jenkow.activiti.override; 2 | 3 | import org.activiti.engine.ProcessEngine; 4 | import org.springframework.beans.factory.FactoryBean; 5 | import org.springframework.web.context.ServletContextAware; 6 | 7 | import javax.servlet.ServletContext; 8 | 9 | /** 10 | * @author Kohsuke Kawaguchi 11 | */ 12 | public class JenkinsProcessEngineFactory implements FactoryBean, ServletContextAware { 13 | private ServletContext servletContext; 14 | 15 | @Override 16 | public ProcessEngine getObject() throws Exception { 17 | return (ProcessEngine)servletContext.getAttribute(ProcessEngine.class.getName()); 18 | } 19 | 20 | @Override 21 | public Class getObjectType() { 22 | return ProcessEngine.class; 23 | } 24 | 25 | @Override 26 | public boolean isSingleton() { 27 | return true; 28 | } 29 | 30 | @Override 31 | public void setServletContext(ServletContext servletContext) { 32 | this.servletContext = servletContext; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /activiti-explorer-override/src/main/java/org/jenkinsci/plugins/jenkow/activiti/override/JenkinsComponentFactories.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.jenkow.activiti.override; 2 | 3 | import org.activiti.explorer.ComponentFactories; 4 | import org.activiti.explorer.Environments; 5 | import org.activiti.explorer.ui.custom.ToolBar; 6 | import org.activiti.explorer.ui.mainlayout.MainMenuBarFactory; 7 | import org.activiti.explorer.ui.management.ManagementMenuBarFactory; 8 | 9 | /** 10 | * More hook for injecting custom UI components. 11 | * 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | public class JenkinsComponentFactories extends ComponentFactories { 15 | public JenkinsComponentFactories() { 16 | // TODO: send patch to Activiti to clean up this hack 17 | factories.put(MainMenuBarFactory.class, new MainMenuBarFactory(){ 18 | @Override 19 | protected Class getDefaultComponentClass() { 20 | return JenkinsMainMenuBar.class; 21 | } 22 | }); 23 | factories.put(ManagementMenuBarFactory.class, new ManagementMenuBarFactory() { 24 | @Override 25 | protected Class getDefaultComponentClass() { 26 | return JenkinsManagementMenuBar.class; 27 | } 28 | }); 29 | setEnvironment(Environments.ACTIVITI); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /activiti-explorer-override/src/main/java/org/jenkinsci/plugins/jenkow/activiti/override/ServletContextDataSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.jenkow.activiti.override; 2 | 3 | import org.springframework.beans.factory.FactoryBean; 4 | import org.springframework.web.context.ServletContextAware; 5 | 6 | import javax.servlet.ServletContext; 7 | import javax.sql.DataSource; 8 | 9 | /** 10 | * Returns {@link DataSource} injected through {@link ServletContext} attribute. 11 | * 12 | * This is how the jenkow plugin passes in the {@link DataSource} to the embedded activiti explorer. 13 | * 14 | * @author Kohsuke Kawaguchi 15 | */ 16 | public class ServletContextDataSource implements FactoryBean, ServletContextAware { 17 | private ServletContext servletContext; 18 | 19 | @Override 20 | public void setServletContext(ServletContext servletContext) { 21 | this.servletContext = servletContext; 22 | } 23 | 24 | @Override 25 | public Object getObject() throws Exception { 26 | Object o = servletContext.getAttribute(ServletContextDataSource.class.getName()); 27 | if (o==null) 28 | throw new IllegalStateException("ServletContext doesn't contain a DataSource"); 29 | return o; 30 | } 31 | 32 | @Override 33 | public Class getObjectType() { 34 | return DataSource.class; 35 | } 36 | 37 | @Override 38 | public boolean isSingleton() { 39 | return true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /activiti-explorer-override/src/main/java/org/jenkinsci/plugins/jenkow/activiti/override/JenkinsUser.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.jenkow.activiti.override; 2 | 3 | import org.activiti.explorer.identity.LoggedInUser; 4 | import org.jenkinsci.plugins.activiti_explorer.dto.UserDTO; 5 | 6 | /** 7 | * @author Kohsuke Kawaguchi 8 | */ 9 | public class JenkinsUser implements LoggedInUser { 10 | private final UserDTO dto; 11 | 12 | public JenkinsUser(UserDTO dto) { 13 | if (dto ==null) 14 | throw new IllegalArgumentException("No information given"); 15 | this.dto = dto; 16 | } 17 | 18 | public String getId() { 19 | return dto.id; 20 | } 21 | 22 | public String getFirstName() { 23 | return dto.firstName; 24 | } 25 | 26 | public String getLastName() { 27 | return dto.lastName; 28 | } 29 | 30 | public String getFullName() { 31 | return dto.fullName; 32 | } 33 | 34 | public String getPassword() { 35 | return null; 36 | } 37 | 38 | public boolean isAdmin() { 39 | return dto.isAdmin; 40 | } 41 | 42 | public boolean isUser() { 43 | return dto.isUser; 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return getId().hashCode(); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) { 53 | if (obj instanceof LoggedInUser) 54 | return ((LoggedInUser)obj).getId().equals(getId()); 55 | return false; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /activiti-explorer-override/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.jenkins-ci.plugins 7 | activiti-explorer-plugin-parent 8 | 1.0-SNAPSHOT 9 | 10 | 11 | activiti-explorer-override 12 | Additional code to be injected into Activiti Explorer to tweak its behaviour 13 | 14 | 15 | 16 | org.springframework 17 | spring-beans 18 | 3.1.2.RELEASE 19 | provided 20 | 21 | 22 | org.activiti 23 | activiti-engine 24 | ${activiti.version} 25 | provided 26 | 27 | 28 | ${project.groupId} 29 | activiti-explorer-dto 30 | ${project.version} 31 | 32 | 33 | org.activiti 34 | activiti-webapp-explorer2 35 | jar 36 | ${activiti.version} 37 | provided 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /plugin/src/main/java/org/jenkinsci/plugins/activiti_explorer/XmlPatcher.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.activiti_explorer; 2 | 3 | import org.dom4j.Document; 4 | import org.dom4j.DocumentException; 5 | import org.dom4j.Element; 6 | import org.dom4j.io.OutputFormat; 7 | import org.dom4j.io.SAXReader; 8 | import org.dom4j.io.XMLWriter; 9 | 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | 14 | /** 15 | * @author Kohsuke Kawaguchi 16 | */ 17 | abstract class XmlPatcher { 18 | private final File xml; 19 | protected Document dom; 20 | 21 | public XmlPatcher(File xml) throws IOException, DocumentException { 22 | this.xml = xml; 23 | run(); 24 | } 25 | 26 | protected Element findBean(String id) { 27 | Element bean = (Element)dom.selectSingleNode(String.format("/*/*[@id='%s' or @name='%s']", id,id)); 28 | if (bean==null) 29 | throw new IllegalStateException("Can't find the "+id+" bean in "+xml); 30 | return bean; 31 | } 32 | 33 | protected void overrideBeanTo(String id, String className) { 34 | Element pe = findBean(id); 35 | pe.elements().clear(); 36 | pe.attributes().clear(); 37 | pe.addAttribute("id", id); 38 | pe.addAttribute("class", className); 39 | } 40 | 41 | protected void swapClass(String id, String className) { 42 | Element pe = findBean(id); 43 | pe.addAttribute("class", className); 44 | } 45 | 46 | protected void removeBean(String id) { 47 | findBean(id).detach(); 48 | } 49 | 50 | public abstract void patch(); 51 | 52 | public void run() throws DocumentException, IOException { 53 | dom = new SAXReader().read(xml); 54 | 55 | patch(); 56 | 57 | FileOutputStream out = new FileOutputStream(xml); 58 | try { 59 | new XMLWriter(out, OutputFormat.createPrettyPrint()).write(dom); 60 | } finally { 61 | out.close(); 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.jenkins-ci.plugins 7 | plugin 8 | 1.455 9 | 10 | 11 | 12 | activiti-explorer-plugin-parent 13 | 1.0-SNAPSHOT 14 | pom 15 | https://wiki.jenkins-ci.org/display/JENKINS/Activiti+Explorer+Plugin 16 | 17 | 18 | plugin 19 | dto 20 | activiti-explorer-override 21 | 22 | 23 | 24 | 5.11 25 | 26 | 27 | 28 | 29 | The MIT License (MIT) 30 | http://www.opensource.org/licenses/mit-license.php 31 | repo 32 | 33 | 34 | 35 | 36 | scm:git:ssh://github.com/jenkinsci/activiti-explorer-plugin.git 37 | scm:git:ssh://git@github.com/jenkinsci/activiti-explorer-plugin.git 38 | https://github.com/jenkinsci/activiti-explorer-plugin 39 | 40 | 41 | 42 | 43 | repo.jenkins-ci.org 44 | http://repo.jenkins-ci.org/public/ 45 | 46 | 47 | repo.activiti 48 | https://maven.alfresco.com/nexus/content/groups/public/ 49 | 50 | 51 | 52 | 53 | repo.jenkins-ci.org 54 | http://repo.jenkins-ci.org/public/ 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /activiti-explorer-override/src/main/java/org/jenkinsci/plugins/jenkow/activiti/override/JenkinsLoginHandler.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.jenkow.activiti.override; 2 | 3 | import org.activiti.explorer.ui.login.LoginHandler; 4 | import org.activiti.explorer.identity.LoggedInUser; 5 | import org.jenkinsci.plugins.activiti_explorer.dto.UserDTO; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | import java.util.Map; 10 | 11 | /** 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | public class JenkinsLoginHandler implements LoginHandler { 15 | /** 16 | * Authenticate the user with the given username and given password. 17 | * 18 | * @return the logged in user. Return null of authentication failed. 19 | */ 20 | public LoggedInUser authenticate(String userName, String password) { 21 | throw new UnsupportedOperationException(); 22 | } 23 | 24 | /** 25 | * Authenticate the current user. Use this to eg. shared autentication, 26 | * which can be done without the user actually having to provide 27 | * credentials. 28 | * 29 | * @return The logged in user. Return null, if no user can be logged in 30 | * automatically. When null is returned, user will be requested to provide 31 | * credentials. 32 | */ 33 | public LoggedInUser authenticate(HttpServletRequest request, HttpServletResponse response) { 34 | return new JenkinsUser((UserDTO)request.getSession().getAttribute("jenkins.user")); 35 | } 36 | 37 | /** 38 | * Called when the user is logged out, should clear all context related 39 | * to authorization and authentication for the current logged in user. 40 | */ 41 | public void logout(LoggedInUser userTologout) { 42 | 43 | } 44 | 45 | /** 46 | * Called when request started. Allows eg. validating of authentication or 47 | * renewing. 48 | */ 49 | public void onRequestStart(HttpServletRequest request, HttpServletResponse response) {} 50 | 51 | /** 52 | * Called when request started. Allows eg. validating of authentication or 53 | * renewing. 54 | */ 55 | public void onRequestEnd(HttpServletRequest request, HttpServletResponse response) {} 56 | 57 | } 58 | -------------------------------------------------------------------------------- /plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.jenkins-ci.plugins 5 | activiti-explorer-plugin-parent 6 | 1.0-SNAPSHOT 7 | 8 | 9 | activiti-explorer 10 | hpi 11 | 12 | 13 | 14 | ${project.groupId} 15 | activiti-explorer-dto 16 | ${project.version} 17 | 18 | 19 | com.cisco.step.jenkins.plugins 20 | jenkow-plugin 21 | 0.2.6-SNAPSHOT 22 | 23 | 24 | com.cloudbees 25 | vietnam4j-core 26 | 1.7 27 | 28 | 29 | ${project.groupId} 30 | activiti-explorer-override 31 | 1.0-SNAPSHOT 32 | 33 | 34 | org.jenkins-ci.modules 35 | sshd 36 | 1.1 37 | provided 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.jenkins-ci.tools 45 | maven-hpi-plugin 46 | 1.93 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-dependency-plugin 51 | 2.5.1 52 | 53 | 54 | copy 55 | generate-resources 56 | 57 | copy 58 | 59 | 60 | 61 | 62 | org.activiti 63 | activiti-webapp-explorer2 64 | war 65 | ${activiti.version} 66 | ${project.build.directory}/classes 67 | activiti-explorer.war 68 | 69 | 70 | ${project.groupId} 71 | activiti-explorer-override 72 | jar 73 | ${project.version} 74 | ${project.build.directory}/classes 75 | activiti-explorer-override.jar 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | repo.jenkins-ci.org 89 | http://repo.jenkins-ci.org/public/ 90 | 91 | 92 | repo.activiti 93 | https://maven.alfresco.com/nexus/content/groups/public/ 94 | 95 | 96 | 97 | 98 | 99 | repo.jenkins-ci.org 100 | http://repo.jenkins-ci.org/public/ 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /plugin/src/main/java/org/jenkinsci/plugins/activiti_explorer/ActivitiExplorer.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.activiti_explorer; 2 | 3 | import com.cisco.step.jenkins.plugins.jenkow.JenkowBuilder.DescriptorImpl; 4 | import com.cisco.step.jenkins.plugins.jenkow.JenkowEngine; 5 | import com.cloudbees.vietnam4j.ProxiedWebApplication; 6 | import hudson.Extension; 7 | import hudson.Util; 8 | import hudson.model.UnprotectedRootAction; 9 | import hudson.model.User; 10 | import jenkins.model.Jenkins; 11 | import org.acegisecurity.Authentication; 12 | import org.activiti.engine.ProcessEngine; 13 | import org.apache.commons.io.IOUtils; 14 | import org.dom4j.DocumentException; 15 | import org.jenkinsci.plugins.activiti_explorer.dto.UserDTO; 16 | import org.jenkinsci.plugins.jenkow.activiti.override.JenkinsProcessEngineFactory; 17 | import org.jenkinsci.plugins.jenkow.activiti.override.ServletContextDataSource; 18 | import org.kohsuke.stapler.StaplerRequest; 19 | import org.kohsuke.stapler.StaplerResponse; 20 | 21 | import javax.inject.Inject; 22 | import javax.servlet.ServletException; 23 | import javax.servlet.http.HttpServletRequest; 24 | import javax.servlet.http.HttpSession; 25 | import java.io.File; 26 | import java.io.FileOutputStream; 27 | import java.io.IOException; 28 | import java.net.URL; 29 | import java.net.URLClassLoader; 30 | import java.util.jar.JarEntry; 31 | import java.util.jar.JarInputStream; 32 | 33 | /** 34 | * Activiti Explorer web application embedded inside Jenkins. 35 | * 36 | * @author Kohsuke Kawaguchi 37 | */ 38 | @Extension 39 | public class ActivitiExplorer implements UnprotectedRootAction { 40 | private ProxiedWebApplication webApp; 41 | 42 | @Inject 43 | DescriptorImpl descriptor; 44 | 45 | public String getIconFileName() { 46 | return "/plugin/activiti-explorer/images/24x24/activiti.png"; 47 | } 48 | 49 | public String getDisplayName() { 50 | return "Activiti Explorer"; 51 | } 52 | 53 | public String getUrlName() { 54 | return "activiti-explorer"; 55 | } 56 | 57 | public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException { 58 | ProxiedWebApplication webApp = getProxyWebApplication(req); 59 | 60 | HttpSession session = req.getSession(); 61 | HttpSession ps = webApp.getProxiedSession(session); 62 | UserDTO oldUser = (UserDTO)ps.getAttribute("jenkins.user"); 63 | UserDTO newUser = createUserInfo(); 64 | if (!mapToId(oldUser).equals(mapToId(newUser))) { 65 | // force a new session. AE isn't designed to anticipate the user change without invalidating a session, 66 | // but Jenkins does that. So when we see that the user has changed in Jenkins, force a new session 67 | // (but only in AE.) 68 | webApp.clearProxiedSession(session); 69 | ps = webApp.getProxiedSession(session); 70 | } 71 | 72 | ps.setAttribute("jenkins.user", newUser); 73 | 74 | 75 | webApp.handleRequest(req, rsp); 76 | } 77 | 78 | private String mapToId(UserDTO o) { 79 | return o==null ? "\u0000" : o.id; 80 | } 81 | 82 | /** 83 | * Creates {@link UserDTO} that represents the currently logged-in user. 84 | */ 85 | private UserDTO createUserInfo() { 86 | Authentication a = Jenkins.getAuthentication(); 87 | User u = User.current(); 88 | 89 | UserDTO user = new UserDTO(); 90 | user.id = a.getName(); 91 | user.firstName = u != null ? u.getFullName() : a.getName(); 92 | user.lastName = ""; 93 | user.fullName = u != null ? u.getFullName() : a.getName(); 94 | user.isAdmin = Jenkins.getInstance().getACL().hasPermission(a,Jenkins.ADMINISTER); 95 | user.isUser = true; 96 | 97 | return user; 98 | } 99 | 100 | /** 101 | * Extracts a war file into the specified directory. 102 | */ 103 | private void extract(URL war, File dir) throws IOException { 104 | if (dir.exists()) 105 | Util.deleteRecursive(dir); 106 | 107 | JarInputStream jar = new JarInputStream(war.openStream()); 108 | try { 109 | JarEntry e; 110 | while ((e=jar.getNextJarEntry())!=null) { 111 | File dst = new File(dir,e.getName()); 112 | if (e.isDirectory()) 113 | dst.mkdirs(); 114 | else { 115 | dst.getParentFile().mkdirs(); 116 | FileOutputStream out = new FileOutputStream(dst); 117 | try { 118 | IOUtils.copy(jar, out); 119 | } finally { 120 | out.close(); 121 | } 122 | 123 | if (e.getTime()>=0) 124 | dst.setLastModified(e.getTime()); 125 | } 126 | } 127 | } finally { 128 | jar.close(); 129 | } 130 | } 131 | 132 | /** 133 | * Patch activiti-explorer war file so that we can inject our stuff into it. 134 | */ 135 | private void patch(File war) throws DocumentException, IOException { 136 | new XmlPatcher(new File(war,"WEB-INF/activiti-standalone-context.xml")) { 137 | public void patch() { 138 | // patch data source in 139 | overrideBeanTo("dataSource", ServletContextDataSource.class.getName()); 140 | 141 | // single sign-on 142 | // can't load the class yet, so string 143 | overrideBeanTo("activitiLoginHandler", "org.jenkinsci.plugins.jenkow.activiti.override.JenkinsLoginHandler"); 144 | 145 | // inject our own fully configured ProcessEngine 146 | overrideBeanTo("processEngine", JenkinsProcessEngineFactory.class.getName()); 147 | 148 | // no more demo data generation 149 | removeBean("demoDataGenerator"); 150 | } 151 | }; 152 | new XmlPatcher(new File(war,"WEB-INF/activiti-ui-context.xml")) { 153 | public void patch() { 154 | // tweak the navigation bar 155 | overrideBeanTo("componentFactories", "org.jenkinsci.plugins.jenkow.activiti.override.JenkinsComponentFactories"); 156 | 157 | swapClass("explorerApp","org.jenkinsci.plugins.jenkow.activiti.override.ExplorerApp2"); 158 | } 159 | }; 160 | } 161 | 162 | private synchronized ProxiedWebApplication getProxyWebApplication(StaplerRequest req) throws ServletException { 163 | if (webApp==null) { 164 | try { 165 | final ClassLoader ourLoader = getClass().getClassLoader(); 166 | 167 | File war = new File(Jenkins.getInstance().getRootDir(), "cache/activiti-explorer"); 168 | extract(ourLoader.getResource("activiti-explorer.war"),war); 169 | patch(war); 170 | webApp = new ProxiedWebApplication( 171 | war, 172 | req.getContextPath()+'/'+getUrlName()); 173 | 174 | webApp.setParentLoaderHasPriority(true); 175 | 176 | webApp.addClassPath(ourLoader.getResource("activiti-explorer-override.jar")); 177 | // inject DataSource 178 | webApp.getProxiedServletContext().setAttribute(ServletContextDataSource.class.getName(), 179 | descriptor.getDatabase().getDataSource()); 180 | webApp.getProxiedServletContext().setAttribute(ProcessEngine.class.getName(), 181 | JenkowEngine.getEngine()); 182 | 183 | // pass through to the servlet container so that Activiti won't get confused 184 | // by what Jenkins loads (e.g., log4j version inconsistency) 185 | // but we do expose DTO classes to share them between two apps. 186 | webApp.setParentClassLoader(new URLClassLoader(new URL[0],HttpServletRequest.class.getClassLoader()) { 187 | @Override 188 | protected Class findClass(String name) throws ClassNotFoundException { 189 | if (name.startsWith("org.jenkinsci.plugins.activiti_explorer.dto.") 190 | || name.startsWith("org.activiti.engine.")) { 191 | return getClass().getClassLoader().loadClass(name); 192 | } 193 | throw new ClassNotFoundException(name); 194 | } 195 | }); 196 | 197 | webApp.start(); 198 | } catch (Exception e) { 199 | throw new ServletException(e); 200 | } 201 | } 202 | return webApp; 203 | } 204 | } 205 | --------------------------------------------------------------------------------