You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/18 17:04:00 UTC

[51/64] [abbrv] incubator-brooklyn git commit: BROOKLYN-162 - apply org.apache package prefix to jmx util/agent projects

BROOKLYN-162 - apply org.apache package prefix to jmx util/agent projects


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/e6ac83be
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/e6ac83be
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/e6ac83be

Branch: refs/heads/master
Commit: e6ac83be8f4e5c0e7dc70c46fa6fb854d90428e7
Parents: e114a25
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Aug 18 14:10:57 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 18 14:51:57 2015 +0100

----------------------------------------------------------------------
 .../java/brooklyn/entity/java/JmxSupport.java   |   5 +-
 .../brooklyn/entity/java/JmxmpSslSupport.java   |   3 +-
 .../java/brooklyn/event/feed/jmx/JmxHelper.java |   2 +-
 .../java/brooklyn/entity/java/JavaOptsTest.java |   3 +-
 .../entity/java/VanillaJavaAppTest.java         |   3 +-
 utils/jmx/jmxmp-ssl-agent/pom.xml               |   4 +-
 .../brooklyn/util/jmx/jmxmp/JmxmpAgent.java     | 335 ------------------
 .../brooklyn/util/jmx/jmxmp/JmxmpAgent.java     | 337 +++++++++++++++++++
 .../util/jmx/jmxmp/JmxmpAgentSslTest.java       | 256 --------------
 .../brooklyn/util/jmx/jmxmp/JmxmpClient.java    |  88 -----
 .../util/jmx/jmxmp/JmxmpAgentSslTest.java       | 257 ++++++++++++++
 .../brooklyn/util/jmx/jmxmp/JmxmpClient.java    |  89 +++++
 utils/jmx/jmxrmi-agent/pom.xml                  |   4 +-
 .../brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java   | 188 -----------
 .../brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java   | 190 +++++++++++
 .../brooklyn/util/jmx/jmxrmi/JmxRmiClient.java  |  47 ---
 .../brooklyn/util/jmx/jmxrmi/JmxRmiClient.java  |  47 +++
 17 files changed, 930 insertions(+), 928 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java b/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java
index b519804..58b148b 100644
--- a/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java
+++ b/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java
@@ -43,14 +43,13 @@ import org.apache.brooklyn.location.basic.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
+import org.apache.brooklyn.util.jmx.jmxrmi.JmxRmiAgent;
 import org.apache.brooklyn.util.maven.MavenArtifact;
 import org.apache.brooklyn.util.maven.MavenRetriever;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.text.Strings;
 
-import brooklyn.util.jmx.jmxmp.JmxmpAgent;
-import brooklyn.util.jmx.jmxrmi.JmxRmiAgent;
-
 import com.google.common.base.Preconditions;
 import com.google.common.net.HostAndPort;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java b/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java
index 51587ab..99601e8 100644
--- a/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java
+++ b/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java
@@ -31,10 +31,9 @@ import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.util.collections.MutableMap.Builder;
 import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
 import org.apache.brooklyn.util.net.Urls;
 
-import brooklyn.util.jmx.jmxmp.JmxmpAgent;
-
 import com.google.common.base.Preconditions;
 
 public class JmxmpSslSupport {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java b/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java
index 7a4a3a0..4438c2d 100644
--- a/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java
+++ b/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java
@@ -65,6 +65,7 @@ import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.apache.brooklyn.util.crypto.SslTrustUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
 import org.apache.brooklyn.util.repeat.Repeater;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;
@@ -73,7 +74,6 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.java.JmxSupport;
 import brooklyn.entity.java.UsesJmx;
-import brooklyn.util.jmx.jmxmp.JmxmpAgent;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java b/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
index bfe8af8..0bc08b0 100644
--- a/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
@@ -46,10 +46,9 @@ import org.apache.brooklyn.location.basic.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
 import org.apache.brooklyn.util.text.Strings;
 
-import brooklyn.util.jmx.jmxmp.JmxmpAgent;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.MapDifference.ValueDifference;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
index da65c68..c0fd3e3 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
@@ -50,6 +50,7 @@ import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.crypto.SslTrustUtils;
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
@@ -63,8 +64,6 @@ import brooklyn.event.feed.jmx.JmxHelper;
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.PortRanges;
 
-import brooklyn.util.jmx.jmxmp.JmxmpAgent;
-
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/pom.xml
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/pom.xml b/utils/jmx/jmxmp-ssl-agent/pom.xml
index 10a45d9..77b5e41 100644
--- a/utils/jmx/jmxmp-ssl-agent/pom.xml
+++ b/utils/jmx/jmxmp-ssl-agent/pom.xml
@@ -107,8 +107,8 @@
                 <configuration>
                     <archive>
                         <manifestEntries>
-                            <Premain-Class>brooklyn.util.jmx.jmxmp.JmxmpAgent</Premain-Class>
-                            <Agent-Class>brooklyn.util.jmx.jmxmp.JmxmpAgent</Agent-Class>
+                            <Premain-Class>org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent</Premain-Class>
+                            <Agent-Class>org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent</Agent-Class>
                         </manifestEntries>
                     </archive>
                 </configuration>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/main/java/brooklyn/util/jmx/jmxmp/JmxmpAgent.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/src/main/java/brooklyn/util/jmx/jmxmp/JmxmpAgent.java b/utils/jmx/jmxmp-ssl-agent/src/main/java/brooklyn/util/jmx/jmxmp/JmxmpAgent.java
deleted file mode 100644
index f9697f8..0000000
--- a/utils/jmx/jmxmp-ssl-agent/src/main/java/brooklyn/util/jmx/jmxmp/JmxmpAgent.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.util.jmx.jmxmp;
-
-import java.io.FileInputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.rmi.registry.LocateRegistry;
-import java.security.KeyStore;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.management.MBeanServer;
-import javax.management.remote.JMXConnectorServer;
-import javax.management.remote.JMXConnectorServerFactory;
-import javax.management.remote.JMXServiceURL;
-import javax.management.remote.rmi.RMIConnectorServer;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-
-/**
- * This exposes JMX access over JMXMP, suitable for high-security environments,
- * with support for going through firewalls as well as encrypting and authenticating securely.
- * <p>
- * Listens on 11099 unless overridden by system property brooklyn.jmxmp.port.
- * <p>
- * Use the usual com.sun.management.jmxremote.ssl to enable both SSL _and_ authentication
- * (setting brooklyn.jmxmp.ssl.authenticate false if you need to disable authentication for some reason); 
- * unless you disable client-side server authentication you will need to supply brooklyn.jmxmp.ssl.keyStore, 
- * and similarly unless server-side client auth is off you'll need the corresponding trustStore 
- * (both pointing to files on the local file system).
- * <p>
- * Service comes up on:  service:jmx:jmxmp://${HOSTNAME}:${PORT}
- * <p>
- * If {@link #RMI_REGISTRY_PORT_PROPERTY} is also set, this agent will start a normal JMX/RMI server bound to
- * all interfaces, which is contactable on:  service:jmx:rmi:///jndi/rmi://${HOSTNAME}:${RMI_REGISTRY_PORT}/jmxrmi 
- * <p>
- * NB: To use JConsole with this endpoing, you need the jmxremote_optional JAR, and the
- * following command (even more complicated if using SSL):
- * java -classpath $JAVA_HOME/lib/jconsole.jar:$HOME/.m2/repository/javax/management/jmxremote_optional/1.0.1_04/jmxremote_optional-1.0.1_04.jar sun.tools.jconsole.JConsole
- */
-public class JmxmpAgent {
-
-    /** port to listen on; default to {@link #JMXMP_DEFAULT_PORT} */
-    public static final String JMXMP_PORT_PROPERTY = "brooklyn.jmxmp.port";
-    /** hostname to advertise, and if {@value #JMX_SERVER_ADDRESS_WILDCARD_PROPERTY} is false also the hostname/interface to bind to */
-    public static final String RMI_HOSTNAME_PROPERTY = "java.rmi.server.hostname";
-    /** whether JMX should bind to all interfaces */
-    public static final String JMX_SERVER_ADDRESS_WILDCARD_PROPERTY = "jmx.remote.server.address.wildcard";
-
-    /** optional port for RMI registry to listen on; if not supplied, RMI is disabled. 1099 is a common choice. 
-     * it will *always* use an anonymous high-numbered port as the rmi server it redirects to
-     * (ie it behaves like the default JMX agent, not the custom JmxRmiAgent). */
-    public static final String RMI_REGISTRY_PORT_PROPERTY = "brooklyn.jmxmp.rmi-port";
-
-    /** whether to use SSL (TLS) encryption; requires a keystore to be set */
-    public static final String USE_SSL_PROPERTY = "com.sun.management.jmxremote.ssl";
-    /** whether to use SSL (TLS) certificates to authenticate the client; 
-     * requires a truststore to be set, and requires {@link #USE_SSL_PROPERTY} true 
-     * (different to 'com.sun.management.jmxremote.authenticate' because something else
-     * insists on intercepting that and uses it for passwords); 
-     * defaults to true iff {@link #USE_SSL_PROPERTY} is set because 
-     * who wouldn't want client authentication if you're encrypting the link */
-    public static final String AUTHENTICATE_CLIENTS_PROPERTY = "brooklyn.jmxmp.ssl.authenticate";
-    
-    public static final String JMXMP_KEYSTORE_FILE_PROPERTY = "brooklyn.jmxmp.ssl.keyStore";
-    public static final String JMXMP_KEYSTORE_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.keyStorePassword";
-    public static final String JMXMP_KEYSTORE_KEY_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.keyStore.keyPassword";
-    public static final String JMXMP_KEYSTORE_TYPE_PROPERTY = "brooklyn.jmxmp.ssl.keyStoreType";
-    
-    public static final String JMXMP_TRUSTSTORE_FILE_PROPERTY = "brooklyn.jmxmp.ssl.trustStore";
-    public static final String JMXMP_TRUSTSTORE_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.trustStorePassword";
-    public static final String JMXMP_TRUSTSTORE_TYPE_PROPERTY = "brooklyn.jmxmp.ssl.trustStoreType";
-
-    // properties above affect behaviour; those below are simply used in code
-    
-    
-    public static final String TLS_NEED_AUTHENTICATE_CLIENTS_PROPERTY = "jmx.remote.tls.need.client.authentication";
-    public static final String TLS_WANT_AUTHENTICATE_CLIENTS_PROPERTY = "jmx.remote.tls.want.client.authentication";
-    public static final String TLS_SOCKET_FACTORY_PROPERTY = "jmx.remote.tls.socket.factory";
-    
-    public static final String TLS_JMX_REMOTE_PROFILES = "TLS";
-    public static final int JMXMP_DEFAULT_PORT = 11099;
-
-    public static void premain(String agentArgs) {
-        doMain(agentArgs);
-    }
-    
-    public static void agentmain(String agentArgs) {
-        doMain(agentArgs);
-    }
-    
-    public static void doMain(final String agentArgs) {
-        // do the work in a daemon thread so that if the main class terminates abnormally,
-        // such that shutdown hooks aren't called, we don't keep the application running
-        // (e.g. if the app is compiled with java7 then run with java6, with a java6 agent here;
-        // that causes the agent to launch, the main to fail, but the process to keep going)
-        Thread t = new Thread() {
-            public void run() {
-                doMainForeground(agentArgs);
-            }
-        };
-        t.setDaemon(true);
-        t.start();
-    }
-
-    public static void doMainForeground(String agentArgs) {
-        final List<JMXConnectorServer> connectors = new JmxmpAgent().startConnectors(System.getProperties());
-        if (!connectors.isEmpty()) {
-            Runtime.getRuntime().addShutdownHook(new Thread("jmxmp-agent-shutdownHookThread") {
-                @Override public void run() {
-                    for (JMXConnectorServer connector: connectors) {
-                        try {
-                            connector.stop();
-                        } catch (Exception e) {
-                            System.err.println("Error closing jmxmp connector "+connector+" in shutdown hook (continuing): "+e);
-                        }
-                    }
-                }});
-        }
-    }
-
-    public List<JMXConnectorServer> startConnectors(Properties properties) {
-        List<JMXConnectorServer> connectors = new ArrayList<JMXConnectorServer>();
-        addIfNotNull(startJmxmpConnector(properties), connectors);
-        addIfNotNull(startNormalJmxRmiConnectorIfRequested(properties), connectors);
-        return connectors;
-    }
-    
-    private static <T> void addIfNotNull(T item, List<T> list) {
-        if (item!=null) list.add(item);
-    }
-
-    public JMXConnectorServer startJmxmpConnector(Properties properties) {
-        try {
-            final int port = Integer.parseInt(properties.getProperty(JMXMP_PORT_PROPERTY, ""+JMXMP_DEFAULT_PORT));
-            
-            String hostname = getLocalhostHostname(properties);
-            JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:jmxmp://"+hostname+":"+port);
-            
-            Map<String,Object> env = new LinkedHashMap<String, Object>();
-            propagate(properties, env, JMX_SERVER_ADDRESS_WILDCARD_PROPERTY, null);
-
-            if (asBoolean(properties, USE_SSL_PROPERTY, false, true)) {
-                setSslEnvFromProperties(env, properties);
-            } else {
-                if (asBoolean(properties, AUTHENTICATE_CLIENTS_PROPERTY, false, true)) {
-                    throw new IllegalStateException("Client authentication not supported when not using SSL");
-                }
-            }
-            MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
-            
-            JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, env, platformMBeanServer);
-            connector.start();
-
-            System.out.println("JmxmpAgent active at: "+serviceUrl);
-            
-            return connector;
-        } catch (RuntimeException e) {
-            System.err.println("Unable to start JmxmpAgent: "+e);
-            throw e;
-        } catch (Exception e) {
-            System.err.println("Unable to start JmxmpAgent: "+e);
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** optionally starts a normal JMXRMI connector in addition */
-    public JMXConnectorServer startNormalJmxRmiConnectorIfRequested(Properties properties) {
-        try {
-            String rmiPortS = properties.getProperty(RMI_REGISTRY_PORT_PROPERTY);
-            if (rmiPortS==null || rmiPortS.length()==0)
-                return null;
-
-            int rmiPort = Integer.parseInt(rmiPortS);
-            LocateRegistry.createRegistry(rmiPort);
-            MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
-            String svc =
-                "service:jmx:rmi:///jndi/rmi://localhost:"+rmiPort+"/jmxrmi";
-
-            JMXServiceURL url = new JMXServiceURL(svc);
-            RMIConnectorServer rmiServer = new RMIConnectorServer(url, null, mbeanServer);
-            rmiServer.start();
-            return rmiServer;
-        } catch (Exception e) {
-            System.err.println("Unable to start JmxmpAgent: "+e);
-            throw new RuntimeException(e);
-        }
-    }
-
-    public static String getLocalhostHostname(Properties properties) throws UnknownHostException {
-        String hostname = properties==null ? null : properties.getProperty(RMI_HOSTNAME_PROPERTY);
-        if (hostname==null || hostname.isEmpty()) {
-            try {
-                hostname = InetAddress.getLocalHost().getHostName();
-            } catch (Exception e) {
-                System.err.println("Misconfigured hostname when setting JmxmpAgent; reverting to 127.0.0.1: "+e);
-                hostname = "127.0.0.1";
-            }
-        }
-        return hostname;
-    }
-
-    /** copies the value of key from the source to the target, if set;
-     * otherwise sets the defaultValueIfNotNull (final arg) if that is not null;
-     * returns whether anything is set
-     */
-    private static boolean propagate(Properties source, Map<String, Object> target, String key, Object defaultValueIfNotNull) {
-        Object v = source.getProperty(key);
-        if (v==null) v = defaultValueIfNotNull;
-        if (v==null) return false;
-        target.put(key, v);
-        return true;
-    }
-    
-    /** returns boolean interpretation of a string, 
-     * defaulting to valueIfUnknownText (last arg) if the value is unset or unrecognised, 
-     * throwing exception if that is null and value is unset or unrecognised */
-    private boolean asBoolean(Properties properties, String key, Boolean valueIfNull, Boolean valueIfUnknownText) {
-        Object v = properties.get(key);
-        if (v==null) {
-            if (valueIfNull==null) throw new IllegalStateException("Property '"+key+"' is required.");
-            return valueIfNull;
-        }
-        String vv = v.toString();
-        if ("true".equalsIgnoreCase(vv)) return true;
-        if ("false".equalsIgnoreCase(vv)) return false;
-        if (valueIfUnknownText==null)
-            throw new IllegalStateException("Property '"+key+"' has illegal value '"+vv+"'; should be true or false");
-        return valueIfUnknownText;
-    }
-    
-    public void setSslEnvFromProperties(Map<String, Object> env, Properties properties) throws Exception {
-        env.put("jmx.remote.profiles", TLS_JMX_REMOTE_PROFILES); 
-        
-        boolean authenticating = asBoolean(properties, AUTHENTICATE_CLIENTS_PROPERTY, true, null); 
-        if (authenticating) {
-            env.put(AUTHENTICATE_CLIENTS_PROPERTY, "true");
-            // NB: the above seem to be ignored (horrid API!); we need the ones below set
-            propagate(properties, env, TLS_NEED_AUTHENTICATE_CLIENTS_PROPERTY, "true");
-            // also note, the above seems to be overridden by below internally !
-            // (setting WANT=false and NEED=true allows access if no trust managers are specified)
-            propagate(properties, env, TLS_WANT_AUTHENTICATE_CLIENTS_PROPERTY, "true");
-        }
-        
-        
-        if (!propagate(properties, env, TLS_SOCKET_FACTORY_PROPERTY, null)) {
-            String keyStoreFile = properties.getProperty(JMXMP_KEYSTORE_FILE_PROPERTY);
-            String keyStorePass = properties.getProperty(JMXMP_KEYSTORE_PASSWORD_PROPERTY, "");
-            String keyStoreType = properties.getProperty(JMXMP_KEYSTORE_TYPE_PROPERTY, KeyStore.getDefaultType());
-            String keyStoreKeyPass = properties.getProperty(JMXMP_KEYSTORE_KEY_PASSWORD_PROPERTY, "");
-            
-            KeyStore ks = KeyStore.getInstance(keyStoreType);
-            if (keyStoreFile!=null)
-                ks.load(new FileInputStream(keyStoreFile), keyStorePass.toCharArray());
-            else
-                ks.load(null, null);
-            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
-            kmf.init(ks, keyStoreKeyPass.toCharArray());
-            
-            String trustStoreFile = properties.getProperty(JMXMP_TRUSTSTORE_FILE_PROPERTY);
-            String trustStorePass = properties.getProperty(JMXMP_TRUSTSTORE_PASSWORD_PROPERTY, "");
-            String trustStoreType = properties.getProperty(JMXMP_TRUSTSTORE_TYPE_PROPERTY, KeyStore.getDefaultType());
-            
-            TrustManager[] tms;
-            if (trustStoreFile!=null) {
-                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-                KeyStore ts = KeyStore.getInstance(trustStoreType);
-                ts.load(new FileInputStream(trustStoreFile), trustStorePass.toCharArray());
-                tmf.init(ts);
-//                tms = tmf.getTrustManagers();
-                // line above causes tests to fail!  bug in JMXMP TLS impl?
-                tms = new TrustManager[] { newInspectAllTrustManager((X509TrustManager) tmf.getTrustManagers()[0]) };
-            } else {
-                tms = null;
-                if (authenticating) 
-                    System.err.println("Authentication required but no truststore supplied to JmxmpAgent. Client connections will likely fail.");
-            }
-            
-            SSLContext ctx = SSLContext.getInstance("TLSv1");
-            ctx.init(kmf.getKeyManagers(), tms, null);
-            SSLSocketFactory ssf = ctx.getSocketFactory(); 
-            env.put(TLS_SOCKET_FACTORY_PROPERTY, ssf); 
-        }
-    }
-
-    public static final TrustManager newInspectAllTrustManager(final X509TrustManager delegate) {
-        return new X509TrustManager() {
-            public X509Certificate[] getAcceptedIssuers() {
-                // overriding this method fixes bug where non-accepted issuers have an "accept all" policy, in JMXMP/TLS
-                return new X509Certificate[0];
-            }
-            @Override
-            public void checkClientTrusted(X509Certificate[] chain, String authType)
-                    throws java.security.cert.CertificateException {
-                delegate.checkClientTrusted(chain, authType);
-            }
-            @Override
-            public void checkServerTrusted(X509Certificate[] chain, String authType)
-                    throws java.security.cert.CertificateException {
-                delegate.checkServerTrusted(chain, authType);
-            }
-        };
-    };
-    
-    public static void main(String[] args) {
-        premain("");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/main/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgent.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/src/main/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgent.java b/utils/jmx/jmxmp-ssl-agent/src/main/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgent.java
new file mode 100644
index 0000000..0ac40bc
--- /dev/null
+++ b/utils/jmx/jmxmp-ssl-agent/src/main/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgent.java
@@ -0,0 +1,337 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.jmx.jmxmp;
+
+import java.io.FileInputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.rmi.registry.LocateRegistry;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.management.MBeanServer;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
+
+
+/**
+ * This exposes JMX access over JMXMP, suitable for high-security environments,
+ * with support for going through firewalls as well as encrypting and authenticating securely.
+ * <p>
+ * Listens on 11099 unless overridden by system property brooklyn.jmxmp.port.
+ * <p>
+ * Use the usual com.sun.management.jmxremote.ssl to enable both SSL _and_ authentication
+ * (setting brooklyn.jmxmp.ssl.authenticate false if you need to disable authentication for some reason); 
+ * unless you disable client-side server authentication you will need to supply brooklyn.jmxmp.ssl.keyStore, 
+ * and similarly unless server-side client auth is off you'll need the corresponding trustStore 
+ * (both pointing to files on the local file system).
+ * <p>
+ * Service comes up on:  service:jmx:jmxmp://${HOSTNAME}:${PORT}
+ * <p>
+ * If {@link #RMI_REGISTRY_PORT_PROPERTY} is also set, this agent will start a normal JMX/RMI server bound to
+ * all interfaces, which is contactable on:  service:jmx:rmi:///jndi/rmi://${HOSTNAME}:${RMI_REGISTRY_PORT}/jmxrmi 
+ * <p>
+ * NB: To use JConsole with this endpoing, you need the jmxremote_optional JAR, and the
+ * following command (even more complicated if using SSL):
+ * java -classpath $JAVA_HOME/lib/jconsole.jar:$HOME/.m2/repository/javax/management/jmxremote_optional/1.0.1_04/jmxremote_optional-1.0.1_04.jar sun.tools.jconsole.JConsole
+ */
+public class JmxmpAgent {
+
+    /** port to listen on; default to {@link #JMXMP_DEFAULT_PORT} */
+    public static final String JMXMP_PORT_PROPERTY = "brooklyn.jmxmp.port";
+    /** hostname to advertise, and if {@value #JMX_SERVER_ADDRESS_WILDCARD_PROPERTY} is false also the hostname/interface to bind to */
+    public static final String RMI_HOSTNAME_PROPERTY = "java.rmi.server.hostname";
+    /** whether JMX should bind to all interfaces */
+    public static final String JMX_SERVER_ADDRESS_WILDCARD_PROPERTY = "jmx.remote.server.address.wildcard";
+
+    /** optional port for RMI registry to listen on; if not supplied, RMI is disabled. 1099 is a common choice. 
+     * it will *always* use an anonymous high-numbered port as the rmi server it redirects to
+     * (ie it behaves like the default JMX agent, not the custom JmxRmiAgent). */
+    public static final String RMI_REGISTRY_PORT_PROPERTY = "brooklyn.jmxmp.rmi-port";
+
+    /** whether to use SSL (TLS) encryption; requires a keystore to be set */
+    public static final String USE_SSL_PROPERTY = "com.sun.management.jmxremote.ssl";
+    /** whether to use SSL (TLS) certificates to authenticate the client; 
+     * requires a truststore to be set, and requires {@link #USE_SSL_PROPERTY} true 
+     * (different to 'com.sun.management.jmxremote.authenticate' because something else
+     * insists on intercepting that and uses it for passwords); 
+     * defaults to true iff {@link #USE_SSL_PROPERTY} is set because 
+     * who wouldn't want client authentication if you're encrypting the link */
+    public static final String AUTHENTICATE_CLIENTS_PROPERTY = "brooklyn.jmxmp.ssl.authenticate";
+    
+    public static final String JMXMP_KEYSTORE_FILE_PROPERTY = "brooklyn.jmxmp.ssl.keyStore";
+    public static final String JMXMP_KEYSTORE_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.keyStorePassword";
+    public static final String JMXMP_KEYSTORE_KEY_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.keyStore.keyPassword";
+    public static final String JMXMP_KEYSTORE_TYPE_PROPERTY = "brooklyn.jmxmp.ssl.keyStoreType";
+    
+    public static final String JMXMP_TRUSTSTORE_FILE_PROPERTY = "brooklyn.jmxmp.ssl.trustStore";
+    public static final String JMXMP_TRUSTSTORE_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.trustStorePassword";
+    public static final String JMXMP_TRUSTSTORE_TYPE_PROPERTY = "brooklyn.jmxmp.ssl.trustStoreType";
+
+    // properties above affect behaviour; those below are simply used in code
+    
+    
+    public static final String TLS_NEED_AUTHENTICATE_CLIENTS_PROPERTY = "jmx.remote.tls.need.client.authentication";
+    public static final String TLS_WANT_AUTHENTICATE_CLIENTS_PROPERTY = "jmx.remote.tls.want.client.authentication";
+    public static final String TLS_SOCKET_FACTORY_PROPERTY = "jmx.remote.tls.socket.factory";
+    
+    public static final String TLS_JMX_REMOTE_PROFILES = "TLS";
+    public static final int JMXMP_DEFAULT_PORT = 11099;
+
+    public static void premain(String agentArgs) {
+        doMain(agentArgs);
+    }
+    
+    public static void agentmain(String agentArgs) {
+        doMain(agentArgs);
+    }
+    
+    public static void doMain(final String agentArgs) {
+        // do the work in a daemon thread so that if the main class terminates abnormally,
+        // such that shutdown hooks aren't called, we don't keep the application running
+        // (e.g. if the app is compiled with java7 then run with java6, with a java6 agent here;
+        // that causes the agent to launch, the main to fail, but the process to keep going)
+        Thread t = new Thread() {
+            public void run() {
+                doMainForeground(agentArgs);
+            }
+        };
+        t.setDaemon(true);
+        t.start();
+    }
+
+    public static void doMainForeground(String agentArgs) {
+        final List<JMXConnectorServer> connectors = new JmxmpAgent().startConnectors(System.getProperties());
+        if (!connectors.isEmpty()) {
+            Runtime.getRuntime().addShutdownHook(new Thread("jmxmp-agent-shutdownHookThread") {
+                @Override public void run() {
+                    for (JMXConnectorServer connector: connectors) {
+                        try {
+                            connector.stop();
+                        } catch (Exception e) {
+                            System.err.println("Error closing jmxmp connector "+connector+" in shutdown hook (continuing): "+e);
+                        }
+                    }
+                }});
+        }
+    }
+
+    public List<JMXConnectorServer> startConnectors(Properties properties) {
+        List<JMXConnectorServer> connectors = new ArrayList<JMXConnectorServer>();
+        addIfNotNull(startJmxmpConnector(properties), connectors);
+        addIfNotNull(startNormalJmxRmiConnectorIfRequested(properties), connectors);
+        return connectors;
+    }
+    
+    private static <T> void addIfNotNull(T item, List<T> list) {
+        if (item!=null) list.add(item);
+    }
+
+    public JMXConnectorServer startJmxmpConnector(Properties properties) {
+        try {
+            final int port = Integer.parseInt(properties.getProperty(JMXMP_PORT_PROPERTY, ""+JMXMP_DEFAULT_PORT));
+            
+            String hostname = getLocalhostHostname(properties);
+            JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:jmxmp://"+hostname+":"+port);
+            
+            Map<String,Object> env = new LinkedHashMap<String, Object>();
+            propagate(properties, env, JMX_SERVER_ADDRESS_WILDCARD_PROPERTY, null);
+
+            if (asBoolean(properties, USE_SSL_PROPERTY, false, true)) {
+                setSslEnvFromProperties(env, properties);
+            } else {
+                if (asBoolean(properties, AUTHENTICATE_CLIENTS_PROPERTY, false, true)) {
+                    throw new IllegalStateException("Client authentication not supported when not using SSL");
+                }
+            }
+            MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
+            
+            JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, env, platformMBeanServer);
+            connector.start();
+
+            System.out.println("JmxmpAgent active at: "+serviceUrl);
+            
+            return connector;
+        } catch (RuntimeException e) {
+            System.err.println("Unable to start JmxmpAgent: "+e);
+            throw e;
+        } catch (Exception e) {
+            System.err.println("Unable to start JmxmpAgent: "+e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** optionally starts a normal JMXRMI connector in addition */
+    public JMXConnectorServer startNormalJmxRmiConnectorIfRequested(Properties properties) {
+        try {
+            String rmiPortS = properties.getProperty(RMI_REGISTRY_PORT_PROPERTY);
+            if (rmiPortS==null || rmiPortS.length()==0)
+                return null;
+
+            int rmiPort = Integer.parseInt(rmiPortS);
+            LocateRegistry.createRegistry(rmiPort);
+            MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
+            String svc =
+                "service:jmx:rmi:///jndi/rmi://localhost:"+rmiPort+"/jmxrmi";
+
+            JMXServiceURL url = new JMXServiceURL(svc);
+            RMIConnectorServer rmiServer = new RMIConnectorServer(url, null, mbeanServer);
+            rmiServer.start();
+            return rmiServer;
+        } catch (Exception e) {
+            System.err.println("Unable to start JmxmpAgent: "+e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String getLocalhostHostname(Properties properties) throws UnknownHostException {
+        String hostname = properties==null ? null : properties.getProperty(RMI_HOSTNAME_PROPERTY);
+        if (hostname==null || hostname.isEmpty()) {
+            try {
+                hostname = InetAddress.getLocalHost().getHostName();
+            } catch (Exception e) {
+                System.err.println("Misconfigured hostname when setting JmxmpAgent; reverting to 127.0.0.1: "+e);
+                hostname = "127.0.0.1";
+            }
+        }
+        return hostname;
+    }
+
+    /** copies the value of key from the source to the target, if set;
+     * otherwise sets the defaultValueIfNotNull (final arg) if that is not null;
+     * returns whether anything is set
+     */
+    private static boolean propagate(Properties source, Map<String, Object> target, String key, Object defaultValueIfNotNull) {
+        Object v = source.getProperty(key);
+        if (v==null) v = defaultValueIfNotNull;
+        if (v==null) return false;
+        target.put(key, v);
+        return true;
+    }
+    
+    /** returns boolean interpretation of a string, 
+     * defaulting to valueIfUnknownText (last arg) if the value is unset or unrecognised, 
+     * throwing exception if that is null and value is unset or unrecognised */
+    private boolean asBoolean(Properties properties, String key, Boolean valueIfNull, Boolean valueIfUnknownText) {
+        Object v = properties.get(key);
+        if (v==null) {
+            if (valueIfNull==null) throw new IllegalStateException("Property '"+key+"' is required.");
+            return valueIfNull;
+        }
+        String vv = v.toString();
+        if ("true".equalsIgnoreCase(vv)) return true;
+        if ("false".equalsIgnoreCase(vv)) return false;
+        if (valueIfUnknownText==null)
+            throw new IllegalStateException("Property '"+key+"' has illegal value '"+vv+"'; should be true or false");
+        return valueIfUnknownText;
+    }
+    
+    public void setSslEnvFromProperties(Map<String, Object> env, Properties properties) throws Exception {
+        env.put("jmx.remote.profiles", TLS_JMX_REMOTE_PROFILES); 
+        
+        boolean authenticating = asBoolean(properties, AUTHENTICATE_CLIENTS_PROPERTY, true, null); 
+        if (authenticating) {
+            env.put(AUTHENTICATE_CLIENTS_PROPERTY, "true");
+            // NB: the above seem to be ignored (horrid API!); we need the ones below set
+            propagate(properties, env, TLS_NEED_AUTHENTICATE_CLIENTS_PROPERTY, "true");
+            // also note, the above seems to be overridden by below internally !
+            // (setting WANT=false and NEED=true allows access if no trust managers are specified)
+            propagate(properties, env, TLS_WANT_AUTHENTICATE_CLIENTS_PROPERTY, "true");
+        }
+        
+        
+        if (!propagate(properties, env, TLS_SOCKET_FACTORY_PROPERTY, null)) {
+            String keyStoreFile = properties.getProperty(JMXMP_KEYSTORE_FILE_PROPERTY);
+            String keyStorePass = properties.getProperty(JMXMP_KEYSTORE_PASSWORD_PROPERTY, "");
+            String keyStoreType = properties.getProperty(JMXMP_KEYSTORE_TYPE_PROPERTY, KeyStore.getDefaultType());
+            String keyStoreKeyPass = properties.getProperty(JMXMP_KEYSTORE_KEY_PASSWORD_PROPERTY, "");
+            
+            KeyStore ks = KeyStore.getInstance(keyStoreType);
+            if (keyStoreFile!=null)
+                ks.load(new FileInputStream(keyStoreFile), keyStorePass.toCharArray());
+            else
+                ks.load(null, null);
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
+            kmf.init(ks, keyStoreKeyPass.toCharArray());
+            
+            String trustStoreFile = properties.getProperty(JMXMP_TRUSTSTORE_FILE_PROPERTY);
+            String trustStorePass = properties.getProperty(JMXMP_TRUSTSTORE_PASSWORD_PROPERTY, "");
+            String trustStoreType = properties.getProperty(JMXMP_TRUSTSTORE_TYPE_PROPERTY, KeyStore.getDefaultType());
+            
+            TrustManager[] tms;
+            if (trustStoreFile!=null) {
+                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+                KeyStore ts = KeyStore.getInstance(trustStoreType);
+                ts.load(new FileInputStream(trustStoreFile), trustStorePass.toCharArray());
+                tmf.init(ts);
+//                tms = tmf.getTrustManagers();
+                // line above causes tests to fail!  bug in JMXMP TLS impl?
+                tms = new TrustManager[] { newInspectAllTrustManager((X509TrustManager) tmf.getTrustManagers()[0]) };
+            } else {
+                tms = null;
+                if (authenticating) 
+                    System.err.println("Authentication required but no truststore supplied to JmxmpAgent. Client connections will likely fail.");
+            }
+            
+            SSLContext ctx = SSLContext.getInstance("TLSv1");
+            ctx.init(kmf.getKeyManagers(), tms, null);
+            SSLSocketFactory ssf = ctx.getSocketFactory(); 
+            env.put(TLS_SOCKET_FACTORY_PROPERTY, ssf); 
+        }
+    }
+
+    public static final TrustManager newInspectAllTrustManager(final X509TrustManager delegate) {
+        return new X509TrustManager() {
+            public X509Certificate[] getAcceptedIssuers() {
+                // overriding this method fixes bug where non-accepted issuers have an "accept all" policy, in JMXMP/TLS
+                return new X509Certificate[0];
+            }
+            @Override
+            public void checkClientTrusted(X509Certificate[] chain, String authType)
+                    throws java.security.cert.CertificateException {
+                delegate.checkClientTrusted(chain, authType);
+            }
+            @Override
+            public void checkServerTrusted(X509Certificate[] chain, String authType)
+                    throws java.security.cert.CertificateException {
+                delegate.checkServerTrusted(chain, authType);
+            }
+        };
+    };
+    
+    public static void main(String[] args) {
+        premain("");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
deleted file mode 100644
index 771ba6d..0000000
--- a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.util.jmx.jmxmp;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.security.KeyPair;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Security;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.LinkedHashMap;
-import java.util.Properties;
-
-import javax.management.remote.JMXConnectorServer;
-
-import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
-import org.apache.brooklyn.core.util.crypto.SecureKeys;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-public class JmxmpAgentSslTest {
-
-    KeyPair caRootKey;
-    FluentKeySigner caRootSigner;
-    X509Certificate caRootCert;
-
-    KeyPair caChildKey;
-    X509Certificate caChildCert;
-    FluentKeySigner caChildSigner;
-
-    KeyPair grandchildKey;
-    X509Certificate grandchildCert;
-
-    KeyPair child2Key;
-    X509Certificate child2Cert;
-
-    KeyPair selfSign1Key;
-    X509Certificate selfSign1Cert;
-
-    KeyPair selfSign2Key;
-    X509Certificate selfSign2Cert;        
-
-    KeyStore serverKeystore;
-    KeyStore serverTruststore;
-    KeyStore clientTruststore;
-    KeyStore clientKeystore;
-
-    JMXConnectorServer server;
-    
-    static { Security.addProvider(new BouncyCastleProvider()); }
-    
-    @BeforeMethod
-    public void setup() throws Exception {
-        caRootSigner = new FluentKeySigner("ca-root").selfsign();
-        caRootKey = caRootSigner.getKey();
-        caRootCert = caRootSigner.getAuthorityCertificate();
-
-        caChildKey = SecureKeys.newKeyPair();
-        caChildCert = caRootSigner.newCertificateFor("ca-child", caChildKey);
-        caChildSigner = new FluentKeySigner("ca-child", caChildKey).
-                authorityKeyIdentifier(new AuthorityKeyIdentifierStructure(caChildCert));
-
-        grandchildKey = SecureKeys.newKeyPair();
-        grandchildCert = caChildSigner.newCertificateFor("grandchild", grandchildKey);
-
-        child2Key = SecureKeys.newKeyPair();
-        child2Cert = 
-                caRootSigner.
-                newCertificateFor("child-2", child2Key);
-
-        selfSign1Key = SecureKeys.newKeyPair();
-        selfSign1Cert = 
-                new FluentKeySigner("self-1", selfSign1Key).
-                newCertificateFor("self-1", selfSign1Key);
-
-        selfSign2Key = SecureKeys.newKeyPair();
-        selfSign2Cert = 
-                new FluentKeySigner("self-2", selfSign2Key).
-                newCertificateFor("self-2", selfSign2Key);        
-
-        serverKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
-        serverKeystore.load(null, null);
-
-        serverTruststore = KeyStore.getInstance(KeyStore.getDefaultType());
-        serverTruststore.load(null, null);
-
-        clientTruststore = KeyStore.getInstance(KeyStore.getDefaultType());
-        clientTruststore.load(null, null);
-
-        clientKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
-        clientKeystore.load(null, null);
-    }
-
-    @AfterMethod
-    public void teardown() throws Exception {
-        if (server!=null) server.stop();
-        server = null;
-    }
-    
-    private Properties saveStoresAndGetConnectorProperties() throws 
-            KeyStoreException, IOException, NoSuchAlgorithmException,
-            CertificateException, FileNotFoundException {
-        String keystoreFile = File.createTempFile("server-keystore", ".jmx.test").getAbsolutePath();
-        String truststoreFile = File.createTempFile("server-truststore", ".jmx.test").getAbsolutePath();
-        if (serverKeystore!=null) serverKeystore.store( new FileOutputStream(keystoreFile), new char[0]);
-        if (serverTruststore!=null) serverTruststore.store( new FileOutputStream(truststoreFile), new char[0]);
-        Properties p = new Properties();
-        p.put(JmxmpAgent.JMXMP_KEYSTORE_FILE_PROPERTY, keystoreFile);
-        p.put(JmxmpAgent.JMXMP_TRUSTSTORE_FILE_PROPERTY, truststoreFile);
-        p.put(JmxmpAgent.USE_SSL_PROPERTY, "true");
-        p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "true");
-        return p;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Test
-    public void testNoAuth() throws Exception {
-        serverKeystore = null;  
-        serverTruststore = null;
-        clientKeystore = null;
-        clientTruststore = null;
-
-        Properties p = saveStoresAndGetConnectorProperties();
-        p.put(JmxmpAgent.USE_SSL_PROPERTY, "false");
-        p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "false");
-        
-        server = new JmxmpAgent().startJmxmpConnector(p);
-        new JmxmpClient().connect("service:jmx:jmxmp://localhost:11099", new LinkedHashMap());
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Test(expectedExceptions = { IllegalStateException.class })
-    public void testAuthWithoutSslFails() throws Exception {
-        serverKeystore = null;  
-        serverTruststore = null;
-        clientKeystore = null;
-        clientTruststore = null;
-
-        Properties p = saveStoresAndGetConnectorProperties();
-        p.put(JmxmpAgent.USE_SSL_PROPERTY, "false");
-        p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "true");
-        
-        server = new JmxmpAgent().startJmxmpConnector(p);
-        new JmxmpClient().connect("service:jmx:jmxmp://localhost:11099", new LinkedHashMap());
-    }
-
-    @Test
-    public void testAllGoodSignatures() throws Exception {
-        serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{},  
-                new java.security.cert.Certificate[]{ child2Cert, caRootCert });
-        serverTruststore.setCertificateEntry("ca-child", caChildCert);
-        
-        clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {},
-                new java.security.cert.Certificate[]{ grandchildCert });
-        clientTruststore.setCertificateEntry("ca-root", caRootCert);
-
-        Properties p = saveStoresAndGetConnectorProperties();
-        server = new JmxmpAgent().startJmxmpConnector(p);
-        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
-                clientKeystore, "", clientTruststore);
-    }
-
-    @Test(expectedExceptions = { Exception.class })
-    public void testWrongServerKey() throws Exception {
-        /** not a trusted key */
-        serverKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[]{},  
-                new java.security.cert.Certificate[]{ selfSign1Cert });
-        serverTruststore.setCertificateEntry("ca-child", caChildCert);
-        
-        clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {},
-                new java.security.cert.Certificate[]{ grandchildCert });
-        clientTruststore.setCertificateEntry("ca-root", caRootCert);
-
-        Properties p = saveStoresAndGetConnectorProperties();
-        server = new JmxmpAgent().startJmxmpConnector(p);
-        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
-                clientKeystore, "", clientTruststore);
-    }
-
-    @Test(expectedExceptions = { Exception.class })
-    public void testLyingServerChain() throws Exception {
-        /** caChildCert hasn't signed this */
-        serverKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[]{},  
-                new java.security.cert.Certificate[]{ selfSign1Cert, caChildCert });
-        serverTruststore.setCertificateEntry("ca-child", caChildCert);
-        
-        clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {},
-                new java.security.cert.Certificate[]{ grandchildCert, caChildCert });
-        clientTruststore.setCertificateEntry("ca-root", caRootCert);
-
-        Properties p = saveStoresAndGetConnectorProperties();
-        server = new JmxmpAgent().startJmxmpConnector(p);
-        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
-                clientKeystore, "", clientTruststore);
-    }
-
-    @Test(expectedExceptions = { Exception.class })
-    public void testWrongClientKey() throws Exception {
-        serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{},  
-                new java.security.cert.Certificate[]{ child2Cert, caRootCert });
-        serverTruststore.setCertificateEntry("ca-child", caChildCert);
-        
-        /** this key should not have access */
-        clientKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[] {},
-                new java.security.cert.Certificate[]{ selfSign1Cert });
-        clientTruststore.setCertificateEntry("ca-root", caRootCert);
-
-        Properties p = saveStoresAndGetConnectorProperties();
-        server = new JmxmpAgent().startJmxmpConnector(p);
-        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
-                clientKeystore, "", clientTruststore);
-    }
-
-    @Test(expectedExceptions = { Exception.class })
-    public void testLyingClientChain() throws Exception {
-        serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{},  
-                new java.security.cert.Certificate[]{ child2Cert, caRootCert });
-        serverTruststore.setCertificateEntry("ca-child", caChildCert);
-        
-        /** caChildCert hasn't signed this */
-        clientKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[] {},
-                new java.security.cert.Certificate[]{ selfSign1Cert, caChildCert });
-        clientTruststore.setCertificateEntry("ca-root", caRootCert);
-
-        Properties p = saveStoresAndGetConnectorProperties();
-        server = new JmxmpAgent().startJmxmpConnector(p);
-        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
-                clientKeystore, "", clientTruststore);
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java
deleted file mode 100644
index dbad7b8..0000000
--- a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.util.jmx.jmxmp;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.security.InvalidKeyException;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SignatureException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.management.MBeanServerConnection;
-import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXConnectorFactory;
-import javax.management.remote.JMXServiceURL;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-
-import org.apache.brooklyn.core.util.crypto.SecureKeys;
-import org.apache.brooklyn.util.crypto.SslTrustUtils;
-
-@SuppressWarnings({"rawtypes","unchecked"})
-public class JmxmpClient {
-
-    public void connect(String urlString, Map env) throws MalformedURLException, IOException {
-        JMXServiceURL url = new JMXServiceURL(urlString);
-        System.out.println("JmxmpClient connecting to "+url);
-        JMXConnector jmxc = JMXConnectorFactory.connect(url, env); 
-        
-        MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); 
-        String domains[] = mbsc.getDomains(); 
-        for (int i = 0; i < domains.length; i++) { 
-            System.out.println("Domain[" + i + "] = " + domains[i]); 
-        } 
-
-        jmxc.close();
-    } 
-
-    /** tries to connect to the given JMX url over tls, 
-     * optionally using the given keystore (if null using a randomly generated key)
-     * and optionally using the given truststore (if null trusting all) */
-    public void connectTls(String urlString, KeyStore keyStore, String keyStorePass, KeyStore trustStore) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, InvalidKeyException, CertificateException, SecurityException, SignatureException, IOException, KeyManagementException { 
-        Map env = new LinkedHashMap(); 
-
-        env.put("jmx.remote.profiles", JmxmpAgent.TLS_JMX_REMOTE_PROFILES);
-
-        if (keyStore==null) throw new NullPointerException("keyStore must be supplied");
-        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); //"SunX509");
-        kmf.init(keyStore, (keyStorePass!=null ? keyStorePass : "").toCharArray());
-
-        TrustManager tms = trustStore!=null ? SecureKeys.getTrustManager(trustStore) : SslTrustUtils.TRUST_ALL;
-
-        SSLContext ctx = SSLContext.getInstance("TLSv1");
-        ctx.init(kmf.getKeyManagers(), new TrustManager[] { tms }, null);
-        SSLSocketFactory ssf = ctx.getSocketFactory(); 
-        env.put(JmxmpAgent.TLS_SOCKET_FACTORY_PROPERTY, ssf); 
-
-        connect(urlString, env); 
-    }
-
-    public static void main(String[] args) throws Exception {
-        new JmxmpClient().connect("service:jmx:jmxmp://localhost:1099", null);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
new file mode 100644
index 0000000..9aa1bad
--- /dev/null
+++ b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.jmx.jmxmp;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.LinkedHashMap;
+import java.util.Properties;
+
+import javax.management.remote.JMXConnectorServer;
+
+import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class JmxmpAgentSslTest {
+
+    KeyPair caRootKey;
+    FluentKeySigner caRootSigner;
+    X509Certificate caRootCert;
+
+    KeyPair caChildKey;
+    X509Certificate caChildCert;
+    FluentKeySigner caChildSigner;
+
+    KeyPair grandchildKey;
+    X509Certificate grandchildCert;
+
+    KeyPair child2Key;
+    X509Certificate child2Cert;
+
+    KeyPair selfSign1Key;
+    X509Certificate selfSign1Cert;
+
+    KeyPair selfSign2Key;
+    X509Certificate selfSign2Cert;        
+
+    KeyStore serverKeystore;
+    KeyStore serverTruststore;
+    KeyStore clientTruststore;
+    KeyStore clientKeystore;
+
+    JMXConnectorServer server;
+    
+    static { Security.addProvider(new BouncyCastleProvider()); }
+    
+    @BeforeMethod
+    public void setup() throws Exception {
+        caRootSigner = new FluentKeySigner("ca-root").selfsign();
+        caRootKey = caRootSigner.getKey();
+        caRootCert = caRootSigner.getAuthorityCertificate();
+
+        caChildKey = SecureKeys.newKeyPair();
+        caChildCert = caRootSigner.newCertificateFor("ca-child", caChildKey);
+        caChildSigner = new FluentKeySigner("ca-child", caChildKey).
+                authorityKeyIdentifier(new AuthorityKeyIdentifierStructure(caChildCert));
+
+        grandchildKey = SecureKeys.newKeyPair();
+        grandchildCert = caChildSigner.newCertificateFor("grandchild", grandchildKey);
+
+        child2Key = SecureKeys.newKeyPair();
+        child2Cert = 
+                caRootSigner.
+                newCertificateFor("child-2", child2Key);
+
+        selfSign1Key = SecureKeys.newKeyPair();
+        selfSign1Cert = 
+                new FluentKeySigner("self-1", selfSign1Key).
+                newCertificateFor("self-1", selfSign1Key);
+
+        selfSign2Key = SecureKeys.newKeyPair();
+        selfSign2Cert = 
+                new FluentKeySigner("self-2", selfSign2Key).
+                newCertificateFor("self-2", selfSign2Key);        
+
+        serverKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
+        serverKeystore.load(null, null);
+
+        serverTruststore = KeyStore.getInstance(KeyStore.getDefaultType());
+        serverTruststore.load(null, null);
+
+        clientTruststore = KeyStore.getInstance(KeyStore.getDefaultType());
+        clientTruststore.load(null, null);
+
+        clientKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
+        clientKeystore.load(null, null);
+    }
+
+    @AfterMethod
+    public void teardown() throws Exception {
+        if (server!=null) server.stop();
+        server = null;
+    }
+    
+    private Properties saveStoresAndGetConnectorProperties() throws 
+            KeyStoreException, IOException, NoSuchAlgorithmException,
+            CertificateException, FileNotFoundException {
+        String keystoreFile = File.createTempFile("server-keystore", ".jmx.test").getAbsolutePath();
+        String truststoreFile = File.createTempFile("server-truststore", ".jmx.test").getAbsolutePath();
+        if (serverKeystore!=null) serverKeystore.store( new FileOutputStream(keystoreFile), new char[0]);
+        if (serverTruststore!=null) serverTruststore.store( new FileOutputStream(truststoreFile), new char[0]);
+        Properties p = new Properties();
+        p.put(JmxmpAgent.JMXMP_KEYSTORE_FILE_PROPERTY, keystoreFile);
+        p.put(JmxmpAgent.JMXMP_TRUSTSTORE_FILE_PROPERTY, truststoreFile);
+        p.put(JmxmpAgent.USE_SSL_PROPERTY, "true");
+        p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "true");
+        return p;
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Test
+    public void testNoAuth() throws Exception {
+        serverKeystore = null;  
+        serverTruststore = null;
+        clientKeystore = null;
+        clientTruststore = null;
+
+        Properties p = saveStoresAndGetConnectorProperties();
+        p.put(JmxmpAgent.USE_SSL_PROPERTY, "false");
+        p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "false");
+        
+        server = new JmxmpAgent().startJmxmpConnector(p);
+        new JmxmpClient().connect("service:jmx:jmxmp://localhost:11099", new LinkedHashMap());
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Test(expectedExceptions = { IllegalStateException.class })
+    public void testAuthWithoutSslFails() throws Exception {
+        serverKeystore = null;  
+        serverTruststore = null;
+        clientKeystore = null;
+        clientTruststore = null;
+
+        Properties p = saveStoresAndGetConnectorProperties();
+        p.put(JmxmpAgent.USE_SSL_PROPERTY, "false");
+        p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "true");
+        
+        server = new JmxmpAgent().startJmxmpConnector(p);
+        new JmxmpClient().connect("service:jmx:jmxmp://localhost:11099", new LinkedHashMap());
+    }
+
+    @Test
+    public void testAllGoodSignatures() throws Exception {
+        serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{},  
+                new java.security.cert.Certificate[]{ child2Cert, caRootCert });
+        serverTruststore.setCertificateEntry("ca-child", caChildCert);
+        
+        clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {},
+                new java.security.cert.Certificate[]{ grandchildCert });
+        clientTruststore.setCertificateEntry("ca-root", caRootCert);
+
+        Properties p = saveStoresAndGetConnectorProperties();
+        server = new JmxmpAgent().startJmxmpConnector(p);
+        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
+                clientKeystore, "", clientTruststore);
+    }
+
+    @Test(expectedExceptions = { Exception.class })
+    public void testWrongServerKey() throws Exception {
+        /** not a trusted key */
+        serverKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[]{},  
+                new java.security.cert.Certificate[]{ selfSign1Cert });
+        serverTruststore.setCertificateEntry("ca-child", caChildCert);
+        
+        clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {},
+                new java.security.cert.Certificate[]{ grandchildCert });
+        clientTruststore.setCertificateEntry("ca-root", caRootCert);
+
+        Properties p = saveStoresAndGetConnectorProperties();
+        server = new JmxmpAgent().startJmxmpConnector(p);
+        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
+                clientKeystore, "", clientTruststore);
+    }
+
+    @Test(expectedExceptions = { Exception.class })
+    public void testLyingServerChain() throws Exception {
+        /** caChildCert hasn't signed this */
+        serverKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[]{},  
+                new java.security.cert.Certificate[]{ selfSign1Cert, caChildCert });
+        serverTruststore.setCertificateEntry("ca-child", caChildCert);
+        
+        clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {},
+                new java.security.cert.Certificate[]{ grandchildCert, caChildCert });
+        clientTruststore.setCertificateEntry("ca-root", caRootCert);
+
+        Properties p = saveStoresAndGetConnectorProperties();
+        server = new JmxmpAgent().startJmxmpConnector(p);
+        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
+                clientKeystore, "", clientTruststore);
+    }
+
+    @Test(expectedExceptions = { Exception.class })
+    public void testWrongClientKey() throws Exception {
+        serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{},  
+                new java.security.cert.Certificate[]{ child2Cert, caRootCert });
+        serverTruststore.setCertificateEntry("ca-child", caChildCert);
+        
+        /** this key should not have access */
+        clientKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[] {},
+                new java.security.cert.Certificate[]{ selfSign1Cert });
+        clientTruststore.setCertificateEntry("ca-root", caRootCert);
+
+        Properties p = saveStoresAndGetConnectorProperties();
+        server = new JmxmpAgent().startJmxmpConnector(p);
+        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
+                clientKeystore, "", clientTruststore);
+    }
+
+    @Test(expectedExceptions = { Exception.class })
+    public void testLyingClientChain() throws Exception {
+        serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{},  
+                new java.security.cert.Certificate[]{ child2Cert, caRootCert });
+        serverTruststore.setCertificateEntry("ca-child", caChildCert);
+        
+        /** caChildCert hasn't signed this */
+        clientKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[] {},
+                new java.security.cert.Certificate[]{ selfSign1Cert, caChildCert });
+        clientTruststore.setCertificateEntry("ca-root", caRootCert);
+
+        Properties p = saveStoresAndGetConnectorProperties();
+        server = new JmxmpAgent().startJmxmpConnector(p);
+        new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099",
+                clientKeystore, "", clientTruststore);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java
new file mode 100644
index 0000000..3c7d664
--- /dev/null
+++ b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.jmx.jmxmp;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.util.crypto.SslTrustUtils;
+import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent;
+
+@SuppressWarnings({"rawtypes","unchecked"})
+public class JmxmpClient {
+
+    public void connect(String urlString, Map env) throws MalformedURLException, IOException {
+        JMXServiceURL url = new JMXServiceURL(urlString);
+        System.out.println("JmxmpClient connecting to "+url);
+        JMXConnector jmxc = JMXConnectorFactory.connect(url, env); 
+        
+        MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); 
+        String domains[] = mbsc.getDomains(); 
+        for (int i = 0; i < domains.length; i++) { 
+            System.out.println("Domain[" + i + "] = " + domains[i]); 
+        } 
+
+        jmxc.close();
+    } 
+
+    /** tries to connect to the given JMX url over tls, 
+     * optionally using the given keystore (if null using a randomly generated key)
+     * and optionally using the given truststore (if null trusting all) */
+    public void connectTls(String urlString, KeyStore keyStore, String keyStorePass, KeyStore trustStore) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, InvalidKeyException, CertificateException, SecurityException, SignatureException, IOException, KeyManagementException { 
+        Map env = new LinkedHashMap(); 
+
+        env.put("jmx.remote.profiles", JmxmpAgent.TLS_JMX_REMOTE_PROFILES);
+
+        if (keyStore==null) throw new NullPointerException("keyStore must be supplied");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); //"SunX509");
+        kmf.init(keyStore, (keyStorePass!=null ? keyStorePass : "").toCharArray());
+
+        TrustManager tms = trustStore!=null ? SecureKeys.getTrustManager(trustStore) : SslTrustUtils.TRUST_ALL;
+
+        SSLContext ctx = SSLContext.getInstance("TLSv1");
+        ctx.init(kmf.getKeyManagers(), new TrustManager[] { tms }, null);
+        SSLSocketFactory ssf = ctx.getSocketFactory(); 
+        env.put(JmxmpAgent.TLS_SOCKET_FACTORY_PROPERTY, ssf); 
+
+        connect(urlString, env); 
+    }
+
+    public static void main(String[] args) throws Exception {
+        new JmxmpClient().connect("service:jmx:jmxmp://localhost:1099", null);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxrmi-agent/pom.xml
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxrmi-agent/pom.xml b/utils/jmx/jmxrmi-agent/pom.xml
index e9ea011..d725405 100644
--- a/utils/jmx/jmxrmi-agent/pom.xml
+++ b/utils/jmx/jmxrmi-agent/pom.xml
@@ -52,8 +52,8 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <Premain-Class>brooklyn.util.jmx.jmxrmi.JmxRmiAgent</Premain-Class>
-                        <Agent-Class>brooklyn.util.jmx.jmxrmi.JmxRmiAgent</Agent-Class>
+                        <Premain-Class>org.apache.brooklyn.util.jmx.jmxrmi.JmxRmiAgent</Premain-Class>
+                        <Agent-Class>org.apache.brooklyn.util.jmx.jmxrmi.JmxRmiAgent</Agent-Class>
                     </instructions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxrmi-agent/src/main/java/brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxrmi-agent/src/main/java/brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java b/utils/jmx/jmxrmi-agent/src/main/java/brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java
deleted file mode 100644
index 089de45..0000000
--- a/utils/jmx/jmxrmi-agent/src/main/java/brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.util.jmx.jmxrmi;
-
-import java.lang.management.ManagementFactory;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.rmi.registry.LocateRegistry;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.management.MBeanServer;
-import javax.management.remote.JMXConnectorServer;
-import javax.management.remote.JMXConnectorServerFactory;
-import javax.management.remote.JMXServiceURL;
-
-/**
- * This exposes JMX support for going through firewalls by starting an RMI registry server
- * on a well-known port.
- * <p>
- * This implementation DOES NOT support port-forwarding however. The same hostname used internally
- * (specified in {@link #RMI_HOSTNAME_PROPERTY} or autodetected by java) must also be addressable
- * by the JMX client. This is due to how the property is used internally by java during the 
- * RMI registry re-direction.
- * <p>
- * If you require that the client connects to a different hostname/IP than the one where the
- * service is bound, consider using the Brooklyn JmxmpAgent, as this will not work!
- * <p>
- * This listens on {@value #RMI_REGISTRY_PORT_PROPERTY} unless overridden by system property 
- * {@link #RMI_REGISTRY_PORT_PROPERTY} ({@value #RMI_REGISTRY_PORT_PROPERTY}).
- *
- * @see brooklyn.util.jmx.jmxmp.JmxmpAgent
- * @see https://blogs.oracle.com/jmxetc/entry/connecting_through_firewall_using_jmx
- * @see https://blogs.oracle.com/jmxetc/entry/more_on_premain_and_jmx
- */
-public class JmxRmiAgent {
-
-    /** Port for RMI registry to listen on. Default to {@link #RMI_REGISTRY_DEFAULT_PORT}. */
-    public static final String RMI_REGISTRY_PORT_PROPERTY = "brooklyn.jmx-agent.rmi-port";
-    public static final String RMI_REGISTRY_DEFAULT_PORT = "9001";
-
-    /** Port for JMX server (sometimes called JMX_RMI server) to listen on. Default to {@link #JMX_SERVER_DEFAULT_PORT}. */
-    public static final String JMX_SERVER_PORT_PROPERTY = "brooklyn.jmx-agent.jmx-port";
-    public static final String JMX_SERVER_DEFAULT_PORT = "11099";
-
-    /** Hostname to advertise, and if {@value #JMX_SERVER_ADDRESS_WILDCARD_PROPERTY} is false also the hostname/interface to bind to. 
-     *  Should never be 0.0.0.0 as it is publicly advertised. */
-    public static final String RMI_HOSTNAME_PROPERTY = "java.rmi.server.hostname";
-
-    /** Whether JMX should bind to all interfaces. */
-    public static final String JMX_SERVER_ADDRESS_WILDCARD_PROPERTY = "jmx.remote.server.address.wildcard";
-
-    /**
-     * The entry point, uses the JDK dynamic agent loading feature.
-     */
-    public static void premain(String agentArgs) {
-        doMain(agentArgs);
-    }
-    
-    public static void agentmain(String agentArgs) {
-        doMain(agentArgs);
-    }
-    
-    public static void doMain(final String agentArgs) {
-        // taken from JmxmpAgent in sister project
-        
-        // do the work in a daemon thread so that if the main class terminates abnormally,
-        // such that shutdown hooks aren't called, we don't keep the application running
-        // (e.g. if the app is compiled with java7 then run with java6, with a java6 agent here;
-        // that causes the agent to launch, the main to fail, but the process to keep going)
-        Thread t = new Thread() {
-            public void run() {
-                doMainForeground(agentArgs);
-            }
-        };
-        t.setDaemon(true);
-        t.start();
-    }
-
-    public static void doMainForeground(String agentArgs) {
-        final JMXConnectorServer connector = new JmxRmiAgent().startServer(System.getProperties());
-        if (connector != null) {
-            Runtime.getRuntime().addShutdownHook(new Thread("jmxrmi-agent-shutdownHookThread") {
-                @Override public void run() {
-                    try {
-                        connector.stop();
-                    } catch (Exception e) {
-                        System.err.println("Error closing jmxrmi connector in shutdown hook (continuing): "+e);
-                    }
-                }});
-        }
-    }
-
-    public JMXConnectorServer startServer(Properties properties) {
-        try {
-            // Ensure cryptographically strong random number generator used
-            // to choose the object number - see java.rmi.server.ObjID
-            System.setProperty("java.rmi.server.randomIDs", "true");
-
-            // Start an RMI registry on port specified
-            final int rmiPort = Integer.parseInt(System.getProperty(RMI_REGISTRY_PORT_PROPERTY, RMI_REGISTRY_DEFAULT_PORT));
-            final int jmxPort = Integer.parseInt(System.getProperty(JMX_SERVER_PORT_PROPERTY, JMX_SERVER_DEFAULT_PORT));
-            final String hostname = getLocalhostHostname(properties);
-            
-            System.out.println("Setting up JmxRmiAgent for: "+hostname+" "+rmiPort+" / "+jmxPort);
-            
-            LocateRegistry.createRegistry(rmiPort);
-
-            // Retrieve the PlatformMBeanServer.
-            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-
-            // Environment map.
-            Map<String, Object> env = new LinkedHashMap<String, Object>();
-            propagate(properties, env, JMX_SERVER_ADDRESS_WILDCARD_PROPERTY, "true");
-
-            // TODO Security
-
-            // Create an RMI connector server.
-            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://" + hostname + ":" + jmxPort + "/jndi/rmi://" + hostname + ":" + rmiPort + "/jmxrmi");
-
-            // Now create the server from the JMXServiceURL
-            JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
-
-            // Start the RMI connector server.
-            connector.start();
-            System.out.println("JmxRmiAgent JMXConnectorServer active at: " + url);
-
-            return connector;
-        } catch (RuntimeException e) {
-            System.err.println("Unable to start JMXConnectorServer: " + e);
-            throw e;
-        } catch (Exception e) {
-            System.err.println("Unable to start JMXConnectorServer: " + e);
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Copies the value of key from the source to the target, if set. Otherwise
-     * sets the {@code defaultValueIfNotNull} if that is not null.
-     * 
-     * @return whether anything is set
-     */
-    private static boolean propagate(Properties source, Map<String, Object> target, String key, Object defaultValueIfNotNull) {
-        Object v = source.getProperty(key);
-        if (v == null) v = defaultValueIfNotNull;
-        if (v == null) return false;
-        target.put(key, v);
-        return true;
-    }
-
-    private String getLocalhostHostname(Properties properties) throws UnknownHostException {
-        String hostname = properties == null ? null : properties.getProperty(RMI_HOSTNAME_PROPERTY);
-        if ("0.0.0.0".equals(hostname)) {
-            System.err.println("WARN: invalid hostname 0.0.0.0 specified for JmxRmiAgent; " +
-                    "it typically must be an address or hostname which is bindable on the machine where " +
-                    "this service is running AND accessible by a client machine (access will likely be impossible)");
-        }
-        if (hostname == null || hostname.isEmpty()) {
-            hostname = InetAddress.getLocalHost().getHostName();
-        }
-        return hostname;
-    }
-
-    /**
-     * Convenience main method.
-     */
-    public static void main(String[] args) throws Exception {
-        premain("");
-    }
-}