package org.jvnet.hudson.plugins.port_allocator;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.remoting.Callable;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.io.Serializable;
import java.net.ConnectException;
import java.net.SocketException;
import java.rmi.UnmarshalException;
import java.util.HashMap;
import java.util.Map;
/**
* GlassFish JMX port so that runaway GF instance can be terminated.
*
* @author Kohsuke Kawaguchi
*/
public class GlassFishJmxPortType extends PortType {
/**
* GlassFish admin user name.
*/
public final String userName;
/**
* GlassFish admin password.
*/
public final String password;
@DataBoundConstructor
public GlassFishJmxPortType(String name, String userName, String password) {
super(name);
this.userName = userName;
this.password = password;
}
@Override
public Port allocate(AbstractBuild<?, ?> build, final PortAllocationManager manager, int prefPort, final Launcher launcher, final BuildListener buildListener) throws IOException, InterruptedException {
final int n;
if(isFixedPort())
n = manager.allocate(build, getFixedPort());
else
n = manager.allocateRandom(build, prefPort);
/**
* Cleans up GlassFish instance.
*/
final class GlassFishCleanUpTask implements Callable<Void,IOException>, Serializable {
private final BuildListener buildListener;
public GlassFishCleanUpTask(BuildListener buildListener) {
this.buildListener = buildListener;
}
public Void call() throws IOException {
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:"+ n +"/jmxrmi");
Map<String,Object> envs = new HashMap<String,Object>();
envs.put(JMXConnector.CREDENTIALS,new String[]{userName, password});
MBeanServerConnection con;
try {
con = JMXConnectorFactory.connect(url,envs).getMBeanServerConnection();
} catch (IOException e) {
for(Throwable t=e; t!=null; t=t.getCause())
if(t instanceof ConnectException) {
// server not connectable. must have been shut down already
return null;
}
throw e; // other failure
}
try {
con.invoke(new ObjectName("amx:j2eeType=J2EEServer,name=server"),"stop",new Object[0],new String[0]);
} catch (UnmarshalException e) {
if(e.getCause() instanceof SocketException || e.getCause() instanceof IOException) {
// to be expected, as the above would shut down the server.
buildListener.getLogger().println("GlassFish was shut down");
} else {
throw e;
}
} catch (MalformedObjectNameException e) {
throw new AssertionError(e); // impossible
} catch (InstanceNotFoundException e) {
e.printStackTrace(buildListener.error("Unable to find J2EEServer mbean"));
} catch (ReflectionException e) {
e.printStackTrace(buildListener.error("Unable to access J2EEServer mbean"));
} catch (MBeanException e) {
e.printStackTrace(buildListener.error("Unable to call J2EEServer mbean"));
}
return null;
}
private static final long serialVersionUID = 1L;
}
return new Port(this) {
public int get() {
return n;
}
public void cleanUp() throws IOException, InterruptedException {
manager.free(n);
launcher.getChannel().call(new GlassFishCleanUpTask(buildListener));
}
};
}
public DescriptorImpl getDescriptor() {
return DescriptorImpl.INSTANCE;
}
public static final class DescriptorImpl extends PortTypeDescriptor {
private DescriptorImpl() {
super(GlassFishJmxPortType.class);
}
public GlassFishJmxPortType newInstance(StaplerRequest req, JSONObject formData) throws FormException {
// TODO: we need form binding from JSON
return new GlassFishJmxPortType(
formData.getString("name"),
formData.getString("username"),
formData.getString("password"));
}
public String getDisplayName() {
return "GlassFish JMX port";
}
public static final DescriptorImpl INSTANCE = new DescriptorImpl();
}
private static final long serialVersionUID = 1L;
}