package hudson.plugins.jboss; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletException; import hudson.CopyOnWrite; import hudson.Extension; import hudson.Launcher; import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.Builder; import hudson.util.FormValidation; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; /** * This plugin is for simple management of JBoss instances. * * @author Juliusz Brzostek */ public class JBossBuilder extends Builder { private final String serverName; private final Operation operation; /** * Currently hard-coded localhost address. * In future it can be more flexible. */ private final String hostName = "127.0.0.1"; @DataBoundConstructor public JBossBuilder(Operation operation, String serverName) { this.operation = operation; this.serverName = serverName; } public String getServerName() { return this.serverName; } public Operation getOperation() { return this.operation; } @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { ServerBean server = getDescriptor().findServer(serverName); if (server == null || operation == null) { listener.fatalError("Wrong configuration of the plugin. Step error."); return false; } ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); try { switch (operation.getType()) { case START_AND_WAIT: if (JMXUtils.checkServerStatus(hostName, server.getJndiPort(), listener, 3, true)) { listener.getLogger().println("JBoss AS already started."); return true; } listener.getLogger().println("Going to start server with timeout " + server.getTimeout()*60 + " seconds..."); boolean ret = CommandsUtils.start(server, operation.getProperties(), build, launcher, listener) && JMXUtils.checkServerStatus(hostName, server.getJndiPort(), listener, server.getTimeout()*60, false); if (ret) { listener.getLogger().println("JBoss AS started!"); } else { listener.getLogger().println( String.format("JBoss AS is not stared before timeout (%d min) has expired!", server.getTimeout())); } return ret; case START: if (JMXUtils.checkServerStatus(hostName, server.getJndiPort(), listener, 3, true)) { listener.getLogger().println("JBoss AS already started."); return true; } return CommandsUtils.start(server, operation.getProperties(), build, launcher, listener); case SHUTDOWN: if (!JMXUtils.checkServerStatus(hostName, server.getJndiPort(), listener, 3, true)) { listener.getLogger().println("JBoss AS is not working."); return true; } return CommandsUtils.stop(server, launcher, listener); case CHECK_DEPLOY: JMXUtils.checkServerStatus(hostName, server.getJndiPort(), listener, 3, false); boolean result = false; if (Util.fixEmpty(operation.getProperties()) != null) { String[] modules = Util.tokenize(operation.getProperties()); result = JMXUtils.checkDeploy(hostName, server.getJndiPort(), listener, 3, modules); } else { listener.getLogger().println("No modules provided."); result = true; } if (!result && operation.isStopOnFailure()) { listener.getLogger().println("StopOnFailure flag is set, going to down server..."); CommandsUtils.stop(server, launcher, listener); } return result; default: listener.fatalError("Uexpected type of operation."); return false; } } finally { Thread.currentThread().setContextClassLoader(contextClassLoader); } } @Override public DescriptorImpl getDescriptor() { return (DescriptorImpl)super.getDescriptor(); } /** * Descriptor for {@link JBossBuilder}. Used as a singleton. */ @Extension public static final class DescriptorImpl extends BuildStepDescriptor<Builder> { /** * Home directory of JBoss. */ private String homeDir; /** * List of defined servers. */ @CopyOnWrite private List<ServerBean> servers = new ArrayList<ServerBean>(); public DescriptorImpl() { load(); } /** * Performs validation of JBoss home directory * * @value * This parameter receives the value that the user has typed. * @return * Indicates the outcome of the validation. This is sent to the browser. */ public FormValidation doCheckHomeDir( @QueryParameter final String jbossHomeString) throws IOException, ServletException { if(jbossHomeString == null || jbossHomeString.length() == 0) { return FormValidation.error("Please set path to JBoss home."); } File jbossHomeFile = new File(jbossHomeString); if (!jbossHomeFile.exists()) { return FormValidation.error("Path doesn't exist."); } if (!jbossHomeFile.isDirectory()) { return FormValidation.error("Path is not valid directory."); } for (String subDir : new String[]{"bin", "server"}) { File subFile = new File(jbossHomeFile, subDir); if (!subFile.exists() || !subFile.isDirectory()) { return FormValidation.error("It's not look like correct JBoss home directory."); } } return FormValidation.ok(); } public FormValidation doCheckServerName( @QueryParameter final String value) throws IOException, ServletException { if(value == null || value.length() == 0) { return FormValidation.error("Server name can not be empty."); } return FormValidation.ok(); } public FormValidation doCheckJndiPort( @QueryParameter final String value) throws IOException, ServletException { if(value == null || value.length() == 0) { return FormValidation.error("JNDI port is mandatory."); } int jndiPortNr = 0; try { jndiPortNr = Integer.parseInt(value); } catch (NumberFormatException e) { return FormValidation.error("JNDI port is not valid number."); } if (jndiPortNr <= 1024) { return FormValidation.error("JNDI port can not be lowest then 1024."); } return FormValidation.ok(); } public FormValidation doCheckTimeout( @QueryParameter final String value) throws IOException, ServletException { if(value == null || value.length() == 0) { return FormValidation.error("Timeout is mandatory."); } int timeout = 0; try { timeout = Integer.parseInt(value); } catch (NumberFormatException e) { return FormValidation.error("Timeout is not valid number."); } if (timeout < 5) { return FormValidation.warning("Timeout is very low, are you sure JBoss will start in this time?"); } return FormValidation.ok(); } @Override public boolean isApplicable(Class<? extends AbstractProject> aClass) { return true; } /** * Builder name. */ public String getDisplayName() { return "JBoss Management"; } @Override public boolean configure(StaplerRequest req, JSONObject parameters) throws FormException { homeDir = parameters.getString("homeDir"); servers.clear(); JSONObject optServersObject = parameters.optJSONObject("servers"); if (optServersObject != null) { servers.add(new ServerBean( homeDir, optServersObject.getString("serverName"), optServersObject.getInt("jndiPort"), optServersObject.getInt("timeout"))); } else { JSONArray optServersArray = parameters.optJSONArray("servers"); if (optServersArray != null) { for (int i=0; i < optServersArray.size(); i++) { JSONObject serverObject = (JSONObject) optServersArray.get(i); servers.add(new ServerBean( homeDir, serverObject.getString("serverName"), serverObject.getInt("jndiPort"), serverObject.getInt("timeout"))); } } } save(); return super.configure(req, parameters); } public String getHomeDir() { return homeDir; } public List<ServerBean> getServers() { return this.servers; } public OperationEnum[] getOperations() { return OperationEnum.all; } protected ServerBean findServer(String serverProfileName) { for (ServerBean server : this.servers) { if (serverProfileName.equals(server.getServerName())) { return server; } } return null; } } public static class ServerBean { private final String homeDir; private final String serverName; private final int jndiPort; private final int timeout; public ServerBean(final String homeDir, final String serverName, final int jndiPort, final int timeout) { this.homeDir = homeDir; this.serverName = serverName; this.jndiPort =jndiPort; this.timeout = timeout; } public String getHomeDir() { return this.homeDir; } public String getServerName() { return this.serverName; } public int getJndiPort() { return this.jndiPort; } public int getTimeout() { return this.timeout; } @Override public String toString() { return new StringBuilder() .append("ServerBean=") .append(serverName) .append(":") .append(jndiPort) .append(" timeout=") .append(timeout).toString(); } } }