Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 6de3afc5d -> 4243d5311


brooklyn-software-osgi: add org.apache package prefix


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

Branch: refs/heads/master
Commit: 8601629a4f524dd2780663b96b6bc775c78a028a
Parents: d85719b
Author: Ciprian Ciubotariu <[email protected]>
Authored: Wed Aug 12 11:07:50 2015 +0300
Committer: Ciprian Ciubotariu <[email protected]>
Committed: Wed Aug 12 11:08:38 2015 +0300

----------------------------------------------------------------------
 .../entity/osgi/karaf/KarafContainer.java       | 137 ---------
 .../entity/osgi/karaf/KarafContainerImpl.java   | 298 -------------------
 .../brooklyn/entity/osgi/karaf/KarafDriver.java |  30 --
 .../entity/osgi/karaf/KarafSshDriver.java       | 149 ----------
 .../entity/osgi/karaf/KarafContainer.java       | 137 +++++++++
 .../entity/osgi/karaf/KarafContainerImpl.java   | 298 +++++++++++++++++++
 .../brooklyn/entity/osgi/karaf/KarafDriver.java |  30 ++
 .../entity/osgi/karaf/KarafSshDriver.java       | 149 ++++++++++
 .../osgi/karaf/KarafContainerEc2LiveTest.java   |  53 ----
 .../entity/osgi/karaf/KarafContainerTest.java   | 147 ---------
 .../osgi/karaf/KarafContainerEc2LiveTest.java   |  53 ++++
 .../entity/osgi/karaf/KarafContainerTest.java   | 147 +++++++++
 12 files changed, 814 insertions(+), 814 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainer.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainer.java 
b/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainer.java
deleted file mode 100644
index 7a0edb6..0000000
--- a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainer.java
+++ /dev/null
@@ -1,137 +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.entity.osgi.karaf;
-
-import java.net.URISyntaxException;
-import java.util.Map;
-
-import org.apache.brooklyn.catalog.Catalog;
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.MethodEffector;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.java.UsesJava;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.event.basic.BasicAttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.MapConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
-
-/**
- * This sets up a Karaf OSGi container
- */
-@Catalog(name="Karaf", description="Apache Karaf is a small OSGi based runtime 
which provides a lightweight container onto which various components and 
applications can be deployed.", iconUrl="classpath:///karaf-logo.png")
-@ImplementedBy(KarafContainerImpl.class)
-public interface KarafContainer extends SoftwareProcess, UsesJava, UsesJmx {
-    
-    // TODO Better way of setting/overriding defaults for config keys that are 
defined in super class SoftwareProcess
-
-    public static final String WRAP_SCHEME = "wrap";
-    public static final String FILE_SCHEME = "file";
-    public static final String MVN_SCHEME = "mvn";
-    public static final String HTTP_SCHEME = "http";
-
-    public static final MethodEffector<Map<Long,Map<String,?>>> LIST_BUNDLES = 
new MethodEffector(KarafContainer.class, "listBundles");
-    public static final MethodEffector<Long> INSTALL_BUNDLE = new 
MethodEffector<Long>(KarafContainer.class, "installBundle");
-    public static final MethodEffector<Void> UNINSTALL_BUNDLE = new 
MethodEffector<Void>(KarafContainer.class, "uninstallBundle");
-    public static final MethodEffector<Void> INSTALL_FEATURE = new 
MethodEffector<Void>(KarafContainer.class, "installFeature");
-    public static final MethodEffector<Void> UPDATE_SERVICE_PROPERTIES = new 
MethodEffector<Void>(KarafContainer.class, "updateServiceProperties");
-
-    @SetFromFlag("version")
-    public static final ConfigKey<String> SUGGESTED_VERSION = 
ConfigKeys.newConfigKeyWithDefault(
-            SoftwareProcess.SUGGESTED_VERSION, "2.3.0");
-
-    @SetFromFlag("downloadUrl")
-    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL 
= new BasicAttributeSensorAndConfigKey<String>(
-            SoftwareProcess.DOWNLOAD_URL, 
"http://apache.mirror.anlx.net/karaf/${version}/apache-karaf-${version}.tar.gz";);
-
-    @SetFromFlag("karafName")
-    public static final BasicAttributeSensorAndConfigKey<String> KARAF_NAME = 
new BasicAttributeSensorAndConfigKey<String>(
-            String.class, "karaf.name", "Karaf instance name", "root");
-
-    // TODO too complicated? Used by KarafContainer; was in JavaApp; where 
should it be in brave new world?
-    public static final MapConfigKey<Map<String,String>> NAMED_PROPERTY_FILES 
= new MapConfigKey(
-            Map.class, "karaf.runtime.files", "Property files to be generated, 
referenced by name relative to runDir");
-
-    @SetFromFlag("jmxUser")
-    public static final BasicAttributeSensorAndConfigKey<String> JMX_USER = 
new BasicAttributeSensorAndConfigKey<String>(
-            UsesJmx.JMX_USER, "karaf");
-    
-    @SetFromFlag("jmxPassword")
-    public static final BasicAttributeSensorAndConfigKey<String> JMX_PASSWORD 
= new BasicAttributeSensorAndConfigKey<String>(
-            UsesJmx.JMX_PASSWORD, "karaf");
-        
-    @SetFromFlag("jmxPort")
-    public static final PortAttributeSensorAndConfigKey JMX_PORT = new 
PortAttributeSensorAndConfigKey(
-            UsesJmx.JMX_PORT, "44444+");
-
-    @SetFromFlag("rmiRegistryPort")
-    public static final PortAttributeSensorAndConfigKey RMI_REGISTRY_PORT = 
UsesJmx.RMI_REGISTRY_PORT;
-    
-    @SetFromFlag("jmxContext")
-    public static final BasicAttributeSensorAndConfigKey<String> JMX_CONTEXT = 
new BasicAttributeSensorAndConfigKey<String>(
-            UsesJmx.JMX_CONTEXT, 
"karaf-"+KARAF_NAME.getConfigKey().getDefaultValue());
-
-    public static final BasicAttributeSensor<Map> KARAF_INSTANCES = new 
BasicAttributeSensor<Map>(
-            Map.class, "karaf.admin.instances", "Karaf admin instances");
-    public static final BasicAttributeSensor<Boolean> KARAF_ROOT = new 
BasicAttributeSensor<Boolean>(
-            Boolean.class, "karaf.admin.isRoot", "Karaf admin isRoot");
-    public static final BasicAttributeSensor<String> KARAF_JAVA_OPTS = new 
BasicAttributeSensor<String>(
-            String.class, "karaf.admin.java_opts", "Karaf Java opts");
-    public static final BasicAttributeSensor<String> KARAF_INSTALL_LOCATION  = 
new BasicAttributeSensor<String>(
-            String.class, "karaf.admin.location", "Karaf install location");
-    public static final BasicAttributeSensor<Integer> KARAF_PID = new 
BasicAttributeSensor<Integer>(
-            Integer.class, "karaf.admin.pid", "Karaf instance PID");
-    public static final BasicAttributeSensor<Integer> KARAF_SSH_PORT = new 
BasicAttributeSensor<Integer>(
-            Integer.class, "karaf.admin.ssh_port", "Karaf SSH Port");
-    public static final BasicAttributeSensor<Integer> KARAF_RMI_REGISTRY_PORT 
= new BasicAttributeSensor<Integer>(
-            Integer.class, "karaf.admin.rmi_registry_port", "Karaf instance 
RMI registry port");
-    public static final BasicAttributeSensor<Integer> KARAF_RMI_SERVER_PORT = 
new BasicAttributeSensor<Integer>(
-            Integer.class, "karaf.admin.rmi_server_port", "Karaf RMI (JMX) 
server port");
-    public static final BasicAttributeSensor<String> KARAF_STATE = new 
BasicAttributeSensor<String>(
-            String.class, "karaf.admin.state", "Karaf instance state");
-
-    @Effector(description="Updates the OSGi Service's properties, adding (and 
overriding) the given key-value pairs")
-    public void updateServiceProperties(
-            @EffectorParam(name="serviceName", description="Name of the OSGi 
service") String serviceName, 
-            Map<String,String> additionalVals);
-    
-    @Effector(description="Installs the given OSGi feature")
-    public void installFeature(
-            @EffectorParam(name="featureName", description="Name of the 
feature - see org.apache.karaf:type=features#installFeature()") final String 
featureName) 
-            throws Exception;
-
-    @Effector(description="Lists all the karaf bundles")
-    public Map<Long,Map<String,?>> listBundles();
-    
-    /**
-     * throws URISyntaxException If bundle name is not a valid URI
-     */
-    @Effector(description="Deploys the given bundle, returning the bundle id - 
see osgi.core:type=framework#installBundle()")
-    public long installBundle(
-            @EffectorParam(name="bundle", description="URI of bundle to be 
deployed") String bundle) throws URISyntaxException;
-
-    @Effector(description="Undeploys the bundle with the given id")
-    public void uninstallBundle(
-            @EffectorParam(name="bundleId", description="Id of the bundle") 
Long bundleId);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
 
b/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
deleted file mode 100644
index b73fd7f..0000000
--- 
a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
+++ /dev/null
@@ -1,298 +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.entity.osgi.karaf;
-
-import java.io.File;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-
-import javax.management.ObjectName;
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.CompositeDataSupport;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.TabularData;
-
-import org.osgi.jmx.JmxConstants;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.java.JmxSupport;
-import brooklyn.event.SensorEvent;
-import brooklyn.event.SensorEventListener;
-import brooklyn.event.feed.ConfigToAttributes;
-import brooklyn.event.feed.jmx.JmxAttributePollConfig;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.event.feed.jmx.JmxHelper;
-import brooklyn.event.feed.jmx.JmxValueFunctions;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.os.Os;
-import brooklyn.util.repeat.Repeater;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Maps;
-
-/**
- * This sets up a Karaf OSGi container
- */
-public class KarafContainerImpl extends SoftwareProcessImpl implements 
KarafContainer {
-    
-    // TODO Better way of setting/overriding defaults for config keys that are 
defined in super class SoftwareProcess
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(KarafContainerImpl.class);
-
-    public static final String KARAF_ADMIN = 
"org.apache.karaf:type=admin,name=%s";
-    public static final String KARAF_FEATURES = 
"org.apache.karaf:type=features,name=%s";
-
-    public static final String OSGI_BUNDLE_STATE = 
"osgi.core:type=bundleState,version=1.5";
-    public static final String OSGI_FRAMEWORK = 
"osgi.core:type=framework,version=1.5";
-    public static final String OSGI_COMPENDIUM = 
"osgi.compendium:service=cm,version=1.3";
-
-    protected JmxHelper jmxHelper;
-
-    private JmxFeed jmxFeed;
-    
-    public KarafContainerImpl() {
-        super();
-    }
-
-    @Override
-    public Class<KarafDriver> getDriverInterface() {
-        return KarafDriver.class;
-    }
-
-    @Override
-    public KarafDriver getDriver() {
-        return (KarafDriver) super.getDriver();
-    }
-    
-    @Override
-    public void init() {
-        super.init();
-        new JmxSupport(this, null).recommendJmxRmiCustomAgent();
-    }
-    
-    @Override
-    protected void postDriverStart() {
-        super.postDriverStart();
-        uploadPropertyFiles(getConfig(NAMED_PROPERTY_FILES));
-        
-        jmxHelper = new JmxHelper(this);
-        jmxHelper.connect(0); // i.e. don't block
-    }
-    
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-
-        //FIXME should have a better way of setting config -- firstly, not 
here!
-        //preferred style is to have config auto-applied to attributes, and 
have default values in their definition, not here
-        //use of "properties.{user,password}" is non-standard; is that 
requried? use default jmxUser, jmxPassword flags?
-        setAttribute(JMX_CONTEXT, String.format("karaf-%s", 
getConfig(KARAF_NAME.getConfigKey())));
-        
-        ConfigToAttributes.apply(this);
-
-        ObjectName karafAdminObjectName = 
JmxHelper.createObjectName(String.format(KARAF_ADMIN, 
getConfig(KARAF_NAME.getConfigKey())));
-        
-        jmxFeed = JmxFeed.builder()
-                .entity(this)
-                .helper(jmxHelper)
-                .period(500, TimeUnit.MILLISECONDS)
-                .pollAttribute(new JmxAttributePollConfig<Map>(KARAF_INSTANCES)
-                        .objectName(karafAdminObjectName)
-                        .attributeName("Instances")
-                        .onSuccess(new Function<Object, Map>() {
-                            @Override
-                            public Map apply(Object input) {
-                                return 
JmxValueFunctions.tabularDataToMap((TabularData)input);
-                            }
-                        })
-                        .onException(new Function<Exception,Map>() {
-                                @Override public Map apply(Exception input) {
-                                    // If MBean is unreachable, then mark as 
service-down
-                                    if 
(Boolean.TRUE.equals(getAttribute(SERVICE_UP))) {
-                                        LOG.debug("Entity "+this+" is not 
reachable on JMX");
-                                        setAttribute(SERVICE_UP, false);
-                                    }
-                                    return null;
-                                }}))
-                .build();
-
-        
-        
-        // INSTANCES aggregates data for the other sensors.
-        subscribe(this, KARAF_INSTANCES, new SensorEventListener<Map>() {
-                @Override public void onEvent(SensorEvent<Map> event) {
-                    Map map = event.getValue();
-                    if (map == null) return;
-                    
-                    setAttribute(SERVICE_UP, 
"Started".equals(map.get("State")));
-                    setAttribute(KARAF_ROOT, (Boolean) map.get("Is Root"));
-                    setAttribute(KARAF_JAVA_OPTS, (String) 
map.get("JavaOpts"));
-                    setAttribute(KARAF_INSTALL_LOCATION, (String) 
map.get("Location"));
-                    setAttribute(KARAF_NAME, (String) map.get("Name"));
-                    setAttribute(KARAF_PID, (Integer) map.get("Pid"));
-                    setAttribute(KARAF_SSH_PORT, (Integer) map.get("Ssh 
Port"));
-                    setAttribute(KARAF_RMI_REGISTRY_PORT, (Integer) 
map.get("RMI Registry Port"));
-                    setAttribute(KARAF_RMI_SERVER_PORT, (Integer) map.get("RMI 
Server Port"));
-                    setAttribute(KARAF_STATE, (String) map.get("State"));
-                }});
-        
-    }
-
-    @Override
-    protected void disconnectSensors() {
-        super.disconnectSensors();
-        if (jmxFeed != null) jmxFeed.stop();
-    }
-    
-    @Override
-    protected void preStop() {
-        super.preStop();
-        
-        if (jmxHelper != null) jmxHelper.terminate();
-    }
-
-    @Effector(description="Updates the OSGi Service's properties, adding (and 
overriding) the given key-value pairs")
-    public void updateServiceProperties(
-            @EffectorParam(name="serviceName", description="Name of the OSGi 
service") String serviceName, 
-            Map<String,String> additionalVals) {
-        TabularData table = (TabularData) jmxHelper.operation(OSGI_COMPENDIUM, 
"getProperties", serviceName);
-        
-        try {
-            for (Map.Entry<String, String> entry: additionalVals.entrySet()) {
-                String key = entry.getKey();
-                String value = entry.getValue();
-                CompositeData data = new CompositeDataSupport(
-                        JmxConstants.PROPERTY_TYPE,
-                        MutableMap.of(JmxConstants.KEY, key, 
JmxConstants.TYPE, "String", JmxConstants.VALUE, value));
-                table.remove(data.getAll(new String[] {JmxConstants.KEY}));
-                table.put(data);
-            }
-        } catch (OpenDataException e) {
-            throw Exceptions.propagate(e);
-        }
-        
-        LOG.info("Updating monterey-service configuration with changes {}", 
additionalVals);
-        if (LOG.isTraceEnabled()) LOG.trace("Updating monterey-service 
configuration with new configuration {}", table);
-        
-        jmxHelper.operation(OSGI_COMPENDIUM, "update", serviceName, table);
-    }
-    
-    @Effector(description="Updates the OSGi Service's properties, adding (and 
overriding) the given key-value pairs")
-    public void installFeature(
-            @EffectorParam(name="featureName", description="Name of the 
feature - see org.apache.karaf:type=features#installFeature()") final String 
featureName) throws Exception {
-        
-        LOG.info("Installing feature {} via JMX", featureName);
-
-        Repeater.create("Wait for Karaf, to install feature "+featureName)
-                .limitIterationsTo(40)
-                .every(500, TimeUnit.MILLISECONDS)
-                .until(new Callable<Boolean>() {
-                        public Boolean call() {
-                            jmxHelper.operation(String.format(KARAF_FEATURES, 
getConfig(KARAF_NAME.getConfigKey())), "installFeature", featureName);
-                            return true;
-                        }})
-                .rethrowException()
-                .run();
-    }
-
-    public Map<Long,Map<String,?>> listBundles() {
-        TabularData table = (TabularData) 
jmxHelper.operation(OSGI_BUNDLE_STATE, "listBundles");
-        Map<List<?>, Map<String, Object>> map = 
JmxValueFunctions.tabularDataToMapOfMaps(table);
-        
-        Map<Long,Map<String,?>> result = Maps.newLinkedHashMap();
-        for (Map.Entry<List<?>, Map<String, Object>> entry : map.entrySet()) {
-            result.put((Long)entry.getKey().get(0), entry.getValue());
-        }
-        return result;
-    }
-    
-    /**
-     * throws URISyntaxException If bundle name is not a valid URI
-     */
-    @Effector(description="Deploys the given bundle, returning the bundle id - 
see osgi.core:type=framework#installBundle()")
-    public long installBundle(
-            @EffectorParam(name="bundle", description="URI of bundle to be 
deployed") String bundle) throws URISyntaxException {
-        
-        // TODO Consider switching to use either:
-        //  - org.apache.karaf:type=bundles#install(String), or 
-        //  - dropping file into $RUN_DIR/deploy (but that would be async)
-
-        URI uri = new URI(bundle);
-        boolean wrap = false;
-        if (WRAP_SCHEME.equals(uri.getScheme())) {
-            bundle = bundle.substring(WRAP_SCHEME.length() + 1);
-            uri = new URI(bundle);
-            wrap = true;
-        }
-        if (FILE_SCHEME.equals(uri.getScheme())) {
-            LOG.info("Deploying bundle {} via file copy", bundle);
-            File source = new File(uri);
-            String target = getDriver().getRunDir() + "/" + source.getName();
-            getDriver().copyResource(source, target);
-            return (Long) jmxHelper.operation(OSGI_FRAMEWORK, "installBundle", 
(wrap ? WRAP_SCHEME + ":" : "") + FILE_SCHEME + "://" + target);
-        } else {
-            LOG.info("Deploying bundle {} via JMX", bundle);
-            return (Long) jmxHelper.operation(OSGI_FRAMEWORK, "installBundle", 
(wrap ? WRAP_SCHEME + ":" : "") + bundle);
-        }
-    }
-
-    @Effector(description="Undeploys the bundle with the given id")
-    public void uninstallBundle(
-            @EffectorParam(name="bundleId", description="Id of the bundle") 
Long bundleId) {
-        
-        // TODO Consider switching to use either:
-        //  - org.apache.karaf:type=bundles#install(String), or 
-        //  - dropping file into $RUN_DIR/deploy (but that would be async)
-
-        jmxHelper.operation(OSGI_FRAMEWORK, "uninstallBundle", bundleId);
-    }
-
-    protected void uploadPropertyFiles(Map<String,Map<String,String>> 
propertyFiles) {
-        if (propertyFiles == null) return;
-        
-        for (Map.Entry<String,Map<String,String>> entry : 
propertyFiles.entrySet()) {
-            String file = entry.getKey();
-            Map<String,String> contents = entry.getValue();
-
-            Properties props = new Properties();
-            for (Map.Entry<String,String> prop : contents.entrySet()) {
-                props.setProperty(prop.getKey(), prop.getValue());
-            }
-            
-            File local = Os.writePropertiesToTempFile(props, "karaf-"+getId(), 
".cfg");
-            local.setReadable(true);
-            try {
-                String remote = getDriver().getRunDir() + "/" + file;
-                getDriver().copyResource(local, remote);
-            } finally {
-                local.delete();
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafDriver.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafDriver.java 
b/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafDriver.java
deleted file mode 100644
index a3144fd..0000000
--- a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafDriver.java
+++ /dev/null
@@ -1,30 +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.entity.osgi.karaf;
-
-import java.io.File;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface KarafDriver extends JavaSoftwareProcessDriver {
-
-    public String getRunDir();
-
-    public int copyResource(File src, String destination);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafSshDriver.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafSshDriver.java 
b/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafSshDriver.java
deleted file mode 100644
index 0e529d9..0000000
--- a/software/osgi/src/main/java/brooklyn/entity/osgi/karaf/KarafSshDriver.java
+++ /dev/null
@@ -1,149 +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.entity.osgi.karaf;
-
-import static java.lang.String.format;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-
-import com.google.common.collect.ImmutableList;
-
-public class KarafSshDriver extends JavaSoftwareProcessSshDriver implements 
KarafDriver {
-
-    // TODO getJmxJavaSystemProperties(), don't set via JAVA_OPTS; set 
ourselves manually
-    // (karaf reads from props files)
-    // but do set "java.rmi.server.hostname"
-
-    public KarafSshDriver(KarafContainerImpl entity, SshMachineLocation 
machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    public KarafContainerImpl getEntity() {
-        return (KarafContainerImpl) super.getEntity();
-    }
-
-    @Override
-    protected String getLogFileLocation() {
-        return Os.mergePaths(getRunDir(), "data", "karaf.out");
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), 
resolver.getUnpackedDirectoryName(format("apache-karaf-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = ImmutableList.<String>builder()
-                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
-                .add(BashCommands.INSTALL_TAR)
-                .add("tar xzfv " + saveAs)
-                .build();
-
-        newScript(INSTALLING)
-                .body.append(commands)
-                .execute();
-    }
-
-    @Override
-    public void customize() {
-        Map<String, Object> ports = new HashMap<String, Object>();
-        ports.put("jmxPort", getJmxPort());
-        ports.put("rmiRegistryPort", getRmiRegistryPort());
-        Networking.checkPortsValid(ports);
-
-        newScript(CUSTOMIZING)
-                .body.append(
-                        format("cd %s", getRunDir()),
-                        format("cp -R %s/{bin,etc,lib,system,deploy} . || exit 
$!", getExpandedInstallDir()),
-                        format("sed -i.bk 's/rmiRegistryPort = 
1099/rmiRegistryPort = %s/g' etc/org.apache.karaf.management.cfg", 
getRmiRegistryPort()),
-                        format("sed -i.bk 's/rmiServerPort = 
44444/rmiServerPort = %s/g' etc/org.apache.karaf.management.cfg", getJmxPort())
-                    )
-                .execute();
-    }
-
-    @Override
-    public void launch() {
-        newScript(MutableMap.of(USE_PID_FILE, true), LAUNCHING)
-                .body.append("nohup ./bin/start")
-                .execute();
-    }
-
-    @Override
-    public boolean isRunning() {
-        // TODO Can we use the pidFile, auto-generated by launch?
-
-        Integer pid = entity.getAttribute(KarafContainer.KARAF_PID);
-        // This method is called on startup, before JMX is initialised, so pid 
won't always be available.
-        if (pid != null) {
-            return newScript(CHECK_RUNNING)
-                    .body.append(format("ps aux | grep 'karaf' | grep %s > 
/dev/null", pid))
-                    .execute() == 0;
-        } else {
-            // Simple method isn't available, use pid in instance.properties.
-            return newScript(CHECK_RUNNING)
-                    .body.append(
-                            format("cd %s/instances/",getRunDir()),
-                            "[ $(uname) = \"Darwin\" ] && pid=$(sed -n -e 
's/.*pid=\\([0-9]*\\)$/\\1/p' instance.properties) || pid=$(sed -r -n -e 
's/.*pid=([0-9]*)$/\\1/p' instance.properties)",
-                            "ps aux | grep 'karaf' | grep $(echo ${pid:-X}) > 
/dev/null"
-                        )
-                    .execute() == 0;
-        }
-    }
-
-    @Override
-    public void stop() {
-        newScript(STOPPING)
-                .environmentVariablesReset()
-                .body.append(format("%s/bin/stop",getRunDir()))
-                .execute();
-    }
-
-    @Override
-    public void kill() {
-        stop(); // TODO no pid file to easily do `kill -9`
-    }
-
-    @Override
-    protected List<String> getCustomJavaConfigOptions() {
-        return MutableList.<String>builder()
-                .addAll(super.getCustomJavaConfigOptions())
-                .add("-Xms200m")
-                .add("-Xmx800m")
-                .add("-XX:MaxPermSize=400m")
-                .build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
 
b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
new file mode 100644
index 0000000..8aa2ef5
--- /dev/null
+++ 
b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainer.java
@@ -0,0 +1,137 @@
+/*
+ * 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.entity.osgi.karaf;
+
+import java.net.URISyntaxException;
+import java.util.Map;
+
+import org.apache.brooklyn.catalog.Catalog;
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.MethodEffector;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.java.UsesJava;
+import brooklyn.entity.java.UsesJmx;
+import brooklyn.entity.proxying.ImplementedBy;
+import brooklyn.event.basic.BasicAttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.MapConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.util.flags.SetFromFlag;
+
+/**
+ * This sets up a Karaf OSGi container
+ */
+@Catalog(name="Karaf", description="Apache Karaf is a small OSGi based runtime 
which provides a lightweight container onto which various components and 
applications can be deployed.", iconUrl="classpath:///karaf-logo.png")
+@ImplementedBy(KarafContainerImpl.class)
+public interface KarafContainer extends SoftwareProcess, UsesJava, UsesJmx {
+    
+    // TODO Better way of setting/overriding defaults for config keys that are 
defined in super class SoftwareProcess
+
+    public static final String WRAP_SCHEME = "wrap";
+    public static final String FILE_SCHEME = "file";
+    public static final String MVN_SCHEME = "mvn";
+    public static final String HTTP_SCHEME = "http";
+
+    public static final MethodEffector<Map<Long,Map<String,?>>> LIST_BUNDLES = 
new MethodEffector(KarafContainer.class, "listBundles");
+    public static final MethodEffector<Long> INSTALL_BUNDLE = new 
MethodEffector<Long>(KarafContainer.class, "installBundle");
+    public static final MethodEffector<Void> UNINSTALL_BUNDLE = new 
MethodEffector<Void>(KarafContainer.class, "uninstallBundle");
+    public static final MethodEffector<Void> INSTALL_FEATURE = new 
MethodEffector<Void>(KarafContainer.class, "installFeature");
+    public static final MethodEffector<Void> UPDATE_SERVICE_PROPERTIES = new 
MethodEffector<Void>(KarafContainer.class, "updateServiceProperties");
+
+    @SetFromFlag("version")
+    public static final ConfigKey<String> SUGGESTED_VERSION = 
ConfigKeys.newConfigKeyWithDefault(
+            SoftwareProcess.SUGGESTED_VERSION, "2.3.0");
+
+    @SetFromFlag("downloadUrl")
+    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL 
= new BasicAttributeSensorAndConfigKey<String>(
+            SoftwareProcess.DOWNLOAD_URL, 
"http://apache.mirror.anlx.net/karaf/${version}/apache-karaf-${version}.tar.gz";);
+
+    @SetFromFlag("karafName")
+    public static final BasicAttributeSensorAndConfigKey<String> KARAF_NAME = 
new BasicAttributeSensorAndConfigKey<String>(
+            String.class, "karaf.name", "Karaf instance name", "root");
+
+    // TODO too complicated? Used by KarafContainer; was in JavaApp; where 
should it be in brave new world?
+    public static final MapConfigKey<Map<String,String>> NAMED_PROPERTY_FILES 
= new MapConfigKey(
+            Map.class, "karaf.runtime.files", "Property files to be generated, 
referenced by name relative to runDir");
+
+    @SetFromFlag("jmxUser")
+    public static final BasicAttributeSensorAndConfigKey<String> JMX_USER = 
new BasicAttributeSensorAndConfigKey<String>(
+            UsesJmx.JMX_USER, "karaf");
+    
+    @SetFromFlag("jmxPassword")
+    public static final BasicAttributeSensorAndConfigKey<String> JMX_PASSWORD 
= new BasicAttributeSensorAndConfigKey<String>(
+            UsesJmx.JMX_PASSWORD, "karaf");
+        
+    @SetFromFlag("jmxPort")
+    public static final PortAttributeSensorAndConfigKey JMX_PORT = new 
PortAttributeSensorAndConfigKey(
+            UsesJmx.JMX_PORT, "44444+");
+
+    @SetFromFlag("rmiRegistryPort")
+    public static final PortAttributeSensorAndConfigKey RMI_REGISTRY_PORT = 
UsesJmx.RMI_REGISTRY_PORT;
+    
+    @SetFromFlag("jmxContext")
+    public static final BasicAttributeSensorAndConfigKey<String> JMX_CONTEXT = 
new BasicAttributeSensorAndConfigKey<String>(
+            UsesJmx.JMX_CONTEXT, 
"karaf-"+KARAF_NAME.getConfigKey().getDefaultValue());
+
+    public static final BasicAttributeSensor<Map> KARAF_INSTANCES = new 
BasicAttributeSensor<Map>(
+            Map.class, "karaf.admin.instances", "Karaf admin instances");
+    public static final BasicAttributeSensor<Boolean> KARAF_ROOT = new 
BasicAttributeSensor<Boolean>(
+            Boolean.class, "karaf.admin.isRoot", "Karaf admin isRoot");
+    public static final BasicAttributeSensor<String> KARAF_JAVA_OPTS = new 
BasicAttributeSensor<String>(
+            String.class, "karaf.admin.java_opts", "Karaf Java opts");
+    public static final BasicAttributeSensor<String> KARAF_INSTALL_LOCATION  = 
new BasicAttributeSensor<String>(
+            String.class, "karaf.admin.location", "Karaf install location");
+    public static final BasicAttributeSensor<Integer> KARAF_PID = new 
BasicAttributeSensor<Integer>(
+            Integer.class, "karaf.admin.pid", "Karaf instance PID");
+    public static final BasicAttributeSensor<Integer> KARAF_SSH_PORT = new 
BasicAttributeSensor<Integer>(
+            Integer.class, "karaf.admin.ssh_port", "Karaf SSH Port");
+    public static final BasicAttributeSensor<Integer> KARAF_RMI_REGISTRY_PORT 
= new BasicAttributeSensor<Integer>(
+            Integer.class, "karaf.admin.rmi_registry_port", "Karaf instance 
RMI registry port");
+    public static final BasicAttributeSensor<Integer> KARAF_RMI_SERVER_PORT = 
new BasicAttributeSensor<Integer>(
+            Integer.class, "karaf.admin.rmi_server_port", "Karaf RMI (JMX) 
server port");
+    public static final BasicAttributeSensor<String> KARAF_STATE = new 
BasicAttributeSensor<String>(
+            String.class, "karaf.admin.state", "Karaf instance state");
+
+    @Effector(description="Updates the OSGi Service's properties, adding (and 
overriding) the given key-value pairs")
+    public void updateServiceProperties(
+            @EffectorParam(name="serviceName", description="Name of the OSGi 
service") String serviceName, 
+            Map<String,String> additionalVals);
+    
+    @Effector(description="Installs the given OSGi feature")
+    public void installFeature(
+            @EffectorParam(name="featureName", description="Name of the 
feature - see org.apache.karaf:type=features#installFeature()") final String 
featureName) 
+            throws Exception;
+
+    @Effector(description="Lists all the karaf bundles")
+    public Map<Long,Map<String,?>> listBundles();
+    
+    /**
+     * throws URISyntaxException If bundle name is not a valid URI
+     */
+    @Effector(description="Deploys the given bundle, returning the bundle id - 
see osgi.core:type=framework#installBundle()")
+    public long installBundle(
+            @EffectorParam(name="bundle", description="URI of bundle to be 
deployed") String bundle) throws URISyntaxException;
+
+    @Effector(description="Undeploys the bundle with the given id")
+    public void uninstallBundle(
+            @EffectorParam(name="bundleId", description="Id of the bundle") 
Long bundleId);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
 
b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
new file mode 100644
index 0000000..30be663
--- /dev/null
+++ 
b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerImpl.java
@@ -0,0 +1,298 @@
+/*
+ * 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.entity.osgi.karaf;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.TabularData;
+
+import org.osgi.jmx.JmxConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.java.JmxSupport;
+import brooklyn.event.SensorEvent;
+import brooklyn.event.SensorEventListener;
+import brooklyn.event.feed.ConfigToAttributes;
+import brooklyn.event.feed.jmx.JmxAttributePollConfig;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.event.feed.jmx.JmxHelper;
+import brooklyn.event.feed.jmx.JmxValueFunctions;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.os.Os;
+import brooklyn.util.repeat.Repeater;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Maps;
+
+/**
+ * This sets up a Karaf OSGi container
+ */
+public class KarafContainerImpl extends SoftwareProcessImpl implements 
KarafContainer {
+    
+    // TODO Better way of setting/overriding defaults for config keys that are 
defined in super class SoftwareProcess
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(KarafContainerImpl.class);
+
+    public static final String KARAF_ADMIN = 
"org.apache.karaf:type=admin,name=%s";
+    public static final String KARAF_FEATURES = 
"org.apache.karaf:type=features,name=%s";
+
+    public static final String OSGI_BUNDLE_STATE = 
"osgi.core:type=bundleState,version=1.5";
+    public static final String OSGI_FRAMEWORK = 
"osgi.core:type=framework,version=1.5";
+    public static final String OSGI_COMPENDIUM = 
"osgi.compendium:service=cm,version=1.3";
+
+    protected JmxHelper jmxHelper;
+
+    private JmxFeed jmxFeed;
+    
+    public KarafContainerImpl() {
+        super();
+    }
+
+    @Override
+    public Class<KarafDriver> getDriverInterface() {
+        return KarafDriver.class;
+    }
+
+    @Override
+    public KarafDriver getDriver() {
+        return (KarafDriver) super.getDriver();
+    }
+    
+    @Override
+    public void init() {
+        super.init();
+        new JmxSupport(this, null).recommendJmxRmiCustomAgent();
+    }
+    
+    @Override
+    protected void postDriverStart() {
+        super.postDriverStart();
+        uploadPropertyFiles(getConfig(NAMED_PROPERTY_FILES));
+        
+        jmxHelper = new JmxHelper(this);
+        jmxHelper.connect(0); // i.e. don't block
+    }
+    
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+
+        //FIXME should have a better way of setting config -- firstly, not 
here!
+        //preferred style is to have config auto-applied to attributes, and 
have default values in their definition, not here
+        //use of "properties.{user,password}" is non-standard; is that 
requried? use default jmxUser, jmxPassword flags?
+        setAttribute(JMX_CONTEXT, String.format("karaf-%s", 
getConfig(KARAF_NAME.getConfigKey())));
+        
+        ConfigToAttributes.apply(this);
+
+        ObjectName karafAdminObjectName = 
JmxHelper.createObjectName(String.format(KARAF_ADMIN, 
getConfig(KARAF_NAME.getConfigKey())));
+        
+        jmxFeed = JmxFeed.builder()
+                .entity(this)
+                .helper(jmxHelper)
+                .period(500, TimeUnit.MILLISECONDS)
+                .pollAttribute(new JmxAttributePollConfig<Map>(KARAF_INSTANCES)
+                        .objectName(karafAdminObjectName)
+                        .attributeName("Instances")
+                        .onSuccess(new Function<Object, Map>() {
+                            @Override
+                            public Map apply(Object input) {
+                                return 
JmxValueFunctions.tabularDataToMap((TabularData)input);
+                            }
+                        })
+                        .onException(new Function<Exception,Map>() {
+                                @Override public Map apply(Exception input) {
+                                    // If MBean is unreachable, then mark as 
service-down
+                                    if 
(Boolean.TRUE.equals(getAttribute(SERVICE_UP))) {
+                                        LOG.debug("Entity "+this+" is not 
reachable on JMX");
+                                        setAttribute(SERVICE_UP, false);
+                                    }
+                                    return null;
+                                }}))
+                .build();
+
+        
+        
+        // INSTANCES aggregates data for the other sensors.
+        subscribe(this, KARAF_INSTANCES, new SensorEventListener<Map>() {
+                @Override public void onEvent(SensorEvent<Map> event) {
+                    Map map = event.getValue();
+                    if (map == null) return;
+                    
+                    setAttribute(SERVICE_UP, 
"Started".equals(map.get("State")));
+                    setAttribute(KARAF_ROOT, (Boolean) map.get("Is Root"));
+                    setAttribute(KARAF_JAVA_OPTS, (String) 
map.get("JavaOpts"));
+                    setAttribute(KARAF_INSTALL_LOCATION, (String) 
map.get("Location"));
+                    setAttribute(KARAF_NAME, (String) map.get("Name"));
+                    setAttribute(KARAF_PID, (Integer) map.get("Pid"));
+                    setAttribute(KARAF_SSH_PORT, (Integer) map.get("Ssh 
Port"));
+                    setAttribute(KARAF_RMI_REGISTRY_PORT, (Integer) 
map.get("RMI Registry Port"));
+                    setAttribute(KARAF_RMI_SERVER_PORT, (Integer) map.get("RMI 
Server Port"));
+                    setAttribute(KARAF_STATE, (String) map.get("State"));
+                }});
+        
+    }
+
+    @Override
+    protected void disconnectSensors() {
+        super.disconnectSensors();
+        if (jmxFeed != null) jmxFeed.stop();
+    }
+    
+    @Override
+    protected void preStop() {
+        super.preStop();
+        
+        if (jmxHelper != null) jmxHelper.terminate();
+    }
+
+    @Effector(description="Updates the OSGi Service's properties, adding (and 
overriding) the given key-value pairs")
+    public void updateServiceProperties(
+            @EffectorParam(name="serviceName", description="Name of the OSGi 
service") String serviceName, 
+            Map<String,String> additionalVals) {
+        TabularData table = (TabularData) jmxHelper.operation(OSGI_COMPENDIUM, 
"getProperties", serviceName);
+        
+        try {
+            for (Map.Entry<String, String> entry: additionalVals.entrySet()) {
+                String key = entry.getKey();
+                String value = entry.getValue();
+                CompositeData data = new CompositeDataSupport(
+                        JmxConstants.PROPERTY_TYPE,
+                        MutableMap.of(JmxConstants.KEY, key, 
JmxConstants.TYPE, "String", JmxConstants.VALUE, value));
+                table.remove(data.getAll(new String[] {JmxConstants.KEY}));
+                table.put(data);
+            }
+        } catch (OpenDataException e) {
+            throw Exceptions.propagate(e);
+        }
+        
+        LOG.info("Updating monterey-service configuration with changes {}", 
additionalVals);
+        if (LOG.isTraceEnabled()) LOG.trace("Updating monterey-service 
configuration with new configuration {}", table);
+        
+        jmxHelper.operation(OSGI_COMPENDIUM, "update", serviceName, table);
+    }
+    
+    @Effector(description="Updates the OSGi Service's properties, adding (and 
overriding) the given key-value pairs")
+    public void installFeature(
+            @EffectorParam(name="featureName", description="Name of the 
feature - see org.apache.karaf:type=features#installFeature()") final String 
featureName) throws Exception {
+        
+        LOG.info("Installing feature {} via JMX", featureName);
+
+        Repeater.create("Wait for Karaf, to install feature "+featureName)
+                .limitIterationsTo(40)
+                .every(500, TimeUnit.MILLISECONDS)
+                .until(new Callable<Boolean>() {
+                        public Boolean call() {
+                            jmxHelper.operation(String.format(KARAF_FEATURES, 
getConfig(KARAF_NAME.getConfigKey())), "installFeature", featureName);
+                            return true;
+                        }})
+                .rethrowException()
+                .run();
+    }
+
+    public Map<Long,Map<String,?>> listBundles() {
+        TabularData table = (TabularData) 
jmxHelper.operation(OSGI_BUNDLE_STATE, "listBundles");
+        Map<List<?>, Map<String, Object>> map = 
JmxValueFunctions.tabularDataToMapOfMaps(table);
+        
+        Map<Long,Map<String,?>> result = Maps.newLinkedHashMap();
+        for (Map.Entry<List<?>, Map<String, Object>> entry : map.entrySet()) {
+            result.put((Long)entry.getKey().get(0), entry.getValue());
+        }
+        return result;
+    }
+    
+    /**
+     * throws URISyntaxException If bundle name is not a valid URI
+     */
+    @Effector(description="Deploys the given bundle, returning the bundle id - 
see osgi.core:type=framework#installBundle()")
+    public long installBundle(
+            @EffectorParam(name="bundle", description="URI of bundle to be 
deployed") String bundle) throws URISyntaxException {
+        
+        // TODO Consider switching to use either:
+        //  - org.apache.karaf:type=bundles#install(String), or 
+        //  - dropping file into $RUN_DIR/deploy (but that would be async)
+
+        URI uri = new URI(bundle);
+        boolean wrap = false;
+        if (WRAP_SCHEME.equals(uri.getScheme())) {
+            bundle = bundle.substring(WRAP_SCHEME.length() + 1);
+            uri = new URI(bundle);
+            wrap = true;
+        }
+        if (FILE_SCHEME.equals(uri.getScheme())) {
+            LOG.info("Deploying bundle {} via file copy", bundle);
+            File source = new File(uri);
+            String target = getDriver().getRunDir() + "/" + source.getName();
+            getDriver().copyResource(source, target);
+            return (Long) jmxHelper.operation(OSGI_FRAMEWORK, "installBundle", 
(wrap ? WRAP_SCHEME + ":" : "") + FILE_SCHEME + "://" + target);
+        } else {
+            LOG.info("Deploying bundle {} via JMX", bundle);
+            return (Long) jmxHelper.operation(OSGI_FRAMEWORK, "installBundle", 
(wrap ? WRAP_SCHEME + ":" : "") + bundle);
+        }
+    }
+
+    @Effector(description="Undeploys the bundle with the given id")
+    public void uninstallBundle(
+            @EffectorParam(name="bundleId", description="Id of the bundle") 
Long bundleId) {
+        
+        // TODO Consider switching to use either:
+        //  - org.apache.karaf:type=bundles#install(String), or 
+        //  - dropping file into $RUN_DIR/deploy (but that would be async)
+
+        jmxHelper.operation(OSGI_FRAMEWORK, "uninstallBundle", bundleId);
+    }
+
+    protected void uploadPropertyFiles(Map<String,Map<String,String>> 
propertyFiles) {
+        if (propertyFiles == null) return;
+        
+        for (Map.Entry<String,Map<String,String>> entry : 
propertyFiles.entrySet()) {
+            String file = entry.getKey();
+            Map<String,String> contents = entry.getValue();
+
+            Properties props = new Properties();
+            for (Map.Entry<String,String> prop : contents.entrySet()) {
+                props.setProperty(prop.getKey(), prop.getValue());
+            }
+            
+            File local = Os.writePropertiesToTempFile(props, "karaf-"+getId(), 
".cfg");
+            local.setReadable(true);
+            try {
+                String remote = getDriver().getRunDir() + "/" + file;
+                getDriver().copyResource(local, remote);
+            } finally {
+                local.delete();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafDriver.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafDriver.java
 
b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafDriver.java
new file mode 100644
index 0000000..80e972d
--- /dev/null
+++ 
b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafDriver.java
@@ -0,0 +1,30 @@
+/*
+ * 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.entity.osgi.karaf;
+
+import java.io.File;
+
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+
+public interface KarafDriver extends JavaSoftwareProcessDriver {
+
+    public String getRunDir();
+
+    public int copyResource(File src, String destination);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafSshDriver.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafSshDriver.java
 
b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafSshDriver.java
new file mode 100644
index 0000000..3d8281a
--- /dev/null
+++ 
b/software/osgi/src/main/java/org/apache/brooklyn/entity/osgi/karaf/KarafSshDriver.java
@@ -0,0 +1,149 @@
+/*
+ * 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.entity.osgi.karaf;
+
+import static java.lang.String.format;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+
+import com.google.common.collect.ImmutableList;
+
+public class KarafSshDriver extends JavaSoftwareProcessSshDriver implements 
KarafDriver {
+
+    // TODO getJmxJavaSystemProperties(), don't set via JAVA_OPTS; set 
ourselves manually
+    // (karaf reads from props files)
+    // but do set "java.rmi.server.hostname"
+
+    public KarafSshDriver(KarafContainerImpl entity, SshMachineLocation 
machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    public KarafContainerImpl getEntity() {
+        return (KarafContainerImpl) super.getEntity();
+    }
+
+    @Override
+    protected String getLogFileLocation() {
+        return Os.mergePaths(getRunDir(), "data", "karaf.out");
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), 
resolver.getUnpackedDirectoryName(format("apache-karaf-%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = ImmutableList.<String>builder()
+                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
+                .add(BashCommands.INSTALL_TAR)
+                .add("tar xzfv " + saveAs)
+                .build();
+
+        newScript(INSTALLING)
+                .body.append(commands)
+                .execute();
+    }
+
+    @Override
+    public void customize() {
+        Map<String, Object> ports = new HashMap<String, Object>();
+        ports.put("jmxPort", getJmxPort());
+        ports.put("rmiRegistryPort", getRmiRegistryPort());
+        Networking.checkPortsValid(ports);
+
+        newScript(CUSTOMIZING)
+                .body.append(
+                        format("cd %s", getRunDir()),
+                        format("cp -R %s/{bin,etc,lib,system,deploy} . || exit 
$!", getExpandedInstallDir()),
+                        format("sed -i.bk 's/rmiRegistryPort = 
1099/rmiRegistryPort = %s/g' etc/org.apache.karaf.management.cfg", 
getRmiRegistryPort()),
+                        format("sed -i.bk 's/rmiServerPort = 
44444/rmiServerPort = %s/g' etc/org.apache.karaf.management.cfg", getJmxPort())
+                    )
+                .execute();
+    }
+
+    @Override
+    public void launch() {
+        newScript(MutableMap.of(USE_PID_FILE, true), LAUNCHING)
+                .body.append("nohup ./bin/start")
+                .execute();
+    }
+
+    @Override
+    public boolean isRunning() {
+        // TODO Can we use the pidFile, auto-generated by launch?
+
+        Integer pid = entity.getAttribute(KarafContainer.KARAF_PID);
+        // This method is called on startup, before JMX is initialised, so pid 
won't always be available.
+        if (pid != null) {
+            return newScript(CHECK_RUNNING)
+                    .body.append(format("ps aux | grep 'karaf' | grep %s > 
/dev/null", pid))
+                    .execute() == 0;
+        } else {
+            // Simple method isn't available, use pid in instance.properties.
+            return newScript(CHECK_RUNNING)
+                    .body.append(
+                            format("cd %s/instances/",getRunDir()),
+                            "[ $(uname) = \"Darwin\" ] && pid=$(sed -n -e 
's/.*pid=\\([0-9]*\\)$/\\1/p' instance.properties) || pid=$(sed -r -n -e 
's/.*pid=([0-9]*)$/\\1/p' instance.properties)",
+                            "ps aux | grep 'karaf' | grep $(echo ${pid:-X}) > 
/dev/null"
+                        )
+                    .execute() == 0;
+        }
+    }
+
+    @Override
+    public void stop() {
+        newScript(STOPPING)
+                .environmentVariablesReset()
+                .body.append(format("%s/bin/stop",getRunDir()))
+                .execute();
+    }
+
+    @Override
+    public void kill() {
+        stop(); // TODO no pid file to easily do `kill -9`
+    }
+
+    @Override
+    protected List<String> getCustomJavaConfigOptions() {
+        return MutableList.<String>builder()
+                .addAll(super.getCustomJavaConfigOptions())
+                .add("-Xms200m")
+                .add("-Xmx800m")
+                .add("-XX:MaxPermSize=400m")
+                .build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerEc2LiveTest.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerEc2LiveTest.java
 
b/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerEc2LiveTest.java
deleted file mode 100644
index 9c2bd89..0000000
--- 
a/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerEc2LiveTest.java
+++ /dev/null
@@ -1,53 +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.entity.osgi.karaf;
-
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.location.Location;
-import brooklyn.util.text.Identifiers;
-
-import com.google.common.collect.ImmutableList;
-
-public class KarafContainerEc2LiveTest extends AbstractEc2LiveTest {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = 
LoggerFactory.getLogger(KarafContainerEc2LiveTest.class);
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        KarafContainer karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
-                .configure("name", Identifiers.makeRandomId(8))
-                .configure("displayName", "Karaf Test")
-                .configure("jmxPort", "8099+")
-                .configure("rmiRegistryPort", "9099+"));
-        
-        app.start(ImmutableList.of(loc));
-
-        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
KarafContainer.SERVICE_UP, true);
-    }
-    
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this 
really does have test methods  
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerTest.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerTest.java
 
b/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerTest.java
deleted file mode 100644
index eb5c561..0000000
--- 
a/software/osgi/src/test/java/brooklyn/entity/osgi/karaf/KarafContainerTest.java
+++ /dev/null
@@ -1,147 +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.entity.osgi.karaf;
-
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
-
-import java.net.URL;
-import java.util.Map;
-
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.test.TestResourceUnavailableException;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.BrooklynAppLiveTestSupport;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.software.SshEffectorTasks;
-import brooklyn.location.NoMachinesAvailableException;
-import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-import brooklyn.test.Asserts;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.text.Identifiers;
-
-import com.google.common.collect.ImmutableList;
-
-public class KarafContainerTest extends BrooklynAppLiveTestSupport {
-
-    private static final String HELLO_WORLD_JAR = "/hello-world.jar";
-
-    LocalhostMachineProvisioningLocation localhost;
-    KarafContainer karaf;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        super.setUp();
-        localhost = app.newLocalhostProvisioningLocation();
-    }
-
-    // FIXME Test failing in jenkins; not sure why. The karaf log shows the 
mbeans never being
-    // registered so we are never able to connect to them over jmx.
-    @Test(groups = {"Integration", "WIP"})
-    public void canStartupAndShutdown() throws Exception {
-        karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
-                .configure("name", Identifiers.makeRandomId(8))
-                .configure("displayName", "Karaf Test"));
-        
-        app.start(ImmutableList.of(localhost));
-        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, true);
-        
-        Entities.dumpInfo(karaf);
-        final int pid = karaf.getAttribute(KarafContainer.KARAF_PID);
-        Entities.submit(app, 
SshEffectorTasks.requirePidRunning(pid).machine(localhost.obtain())).get();
-        
-        karaf.stop();
-        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, false);
-        
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                try {
-                    Assert.assertFalse(Entities.submit(app, 
SshEffectorTasks.isPidRunning(pid).machine(localhost.obtain())).get());
-                } catch (NoMachinesAvailableException e) {
-                    throw Exceptions.propagate(e);
-                }
-            }});
-    }
-    
-    @Test(groups = {"Integration", "WIP"})
-    public void canStartupAndShutdownExplicitJmx() throws Exception {
-        karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
-                .configure("name", Identifiers.makeRandomId(8))
-                .configure("displayName", "Karaf Test")
-                .configure("rmiRegistryPort", "8099+")
-                .configure("jmxPort", "9099+"));
-        
-        app.start(ImmutableList.of(localhost));
-        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, true);
-        
-        karaf.stop();
-        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, false);
-    }
-    
-    @Test(groups = {"Integration", "WIP"})
-    public void canStartupAndShutdownLegacyJmx() throws Exception {
-        karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
-                .configure("name", Identifiers.makeRandomId(8))
-                .configure("displayName", "Karaf Test")
-                .configure("jmxPort", "8099+")
-                .configure("rmiRegistryPort", "9099+"));
-            // NB: now the above parameters have the opposite semantics to 
before
-        
-        app.start(ImmutableList.of(localhost));
-        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, true);
-        
-        karaf.stop();
-        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, false);
-    }
-    
-    // FIXME Test failing in jenkins; not sure why. The karaf log shows the 
mbeans never being
-    // registered so we are never able to connect to them over jmx.
-    @Test(groups = {"Integration", "WIP"})
-    public void testCanInstallAndUninstallBundle() throws Exception {
-        
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), 
HELLO_WORLD_JAR);
-        URL jarUrl = getClass().getResource(HELLO_WORLD_JAR);
-        assertNotNull(jarUrl);
-
-        karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
-            .configure("name", Identifiers.makeRandomId(8))
-            .configure("displayName", "Karaf Test")
-            .configure("jmxPort", "8099+")
-            .configure("rmiRegistryPort", "9099+"));
-        
-        app.start(ImmutableList.of(localhost));
-        
-        long bundleId = karaf.installBundle("wrap:"+jarUrl.toString());
-        
-        Map<Long, Map<String,?>> bundles = karaf.listBundles();
-        Map<String,?> bundle = bundles.get(bundleId);
-        assertNotNull(bundle, "expected="+bundleId+"; 
actual="+bundles.keySet());
-
-        // Undeploy: expect bundle to no longer be listed        
-        karaf.uninstallBundle(bundleId);
-        
-        Map<Long, Map<String,?>> bundles2 = karaf.listBundles();
-        Map<String,?> bundle2 = bundles2.get(bundleId);
-        assertNull(bundle2, "expectedAbsent="+bundleId+"; 
actual="+bundles2.keySet());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerEc2LiveTest.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerEc2LiveTest.java
 
b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerEc2LiveTest.java
new file mode 100644
index 0000000..d6c69d9
--- /dev/null
+++ 
b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerEc2LiveTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.entity.osgi.karaf;
+
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.collect.ImmutableList;
+
+public class KarafContainerEc2LiveTest extends AbstractEc2LiveTest {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = 
LoggerFactory.getLogger(KarafContainerEc2LiveTest.class);
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        KarafContainer karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
+                .configure("name", Identifiers.makeRandomId(8))
+                .configure("displayName", "Karaf Test")
+                .configure("jmxPort", "8099+")
+                .configure("rmiRegistryPort", "9099+"));
+        
+        app.start(ImmutableList.of(loc));
+
+        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
KarafContainer.SERVICE_UP, true);
+    }
+    
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this 
really does have test methods  
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8601629a/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
----------------------------------------------------------------------
diff --git 
a/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
 
b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
new file mode 100644
index 0000000..03c9bc6
--- /dev/null
+++ 
b/software/osgi/src/test/java/org/apache/brooklyn/entity/osgi/karaf/KarafContainerTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.entity.osgi.karaf;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.software.SshEffectorTasks;
+import brooklyn.location.NoMachinesAvailableException;
+import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.test.Asserts;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.collect.ImmutableList;
+
+public class KarafContainerTest extends BrooklynAppLiveTestSupport {
+
+    private static final String HELLO_WORLD_JAR = "/hello-world.jar";
+
+    LocalhostMachineProvisioningLocation localhost;
+    KarafContainer karaf;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+        localhost = app.newLocalhostProvisioningLocation();
+    }
+
+    // FIXME Test failing in jenkins; not sure why. The karaf log shows the 
mbeans never being
+    // registered so we are never able to connect to them over jmx.
+    @Test(groups = {"Integration", "WIP"})
+    public void canStartupAndShutdown() throws Exception {
+        karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
+                .configure("name", Identifiers.makeRandomId(8))
+                .configure("displayName", "Karaf Test"));
+        
+        app.start(ImmutableList.of(localhost));
+        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, true);
+        
+        Entities.dumpInfo(karaf);
+        final int pid = karaf.getAttribute(KarafContainer.KARAF_PID);
+        Entities.submit(app, 
SshEffectorTasks.requirePidRunning(pid).machine(localhost.obtain())).get();
+        
+        karaf.stop();
+        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, false);
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                try {
+                    Assert.assertFalse(Entities.submit(app, 
SshEffectorTasks.isPidRunning(pid).machine(localhost.obtain())).get());
+                } catch (NoMachinesAvailableException e) {
+                    throw Exceptions.propagate(e);
+                }
+            }});
+    }
+    
+    @Test(groups = {"Integration", "WIP"})
+    public void canStartupAndShutdownExplicitJmx() throws Exception {
+        karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
+                .configure("name", Identifiers.makeRandomId(8))
+                .configure("displayName", "Karaf Test")
+                .configure("rmiRegistryPort", "8099+")
+                .configure("jmxPort", "9099+"));
+        
+        app.start(ImmutableList.of(localhost));
+        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, true);
+        
+        karaf.stop();
+        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, false);
+    }
+    
+    @Test(groups = {"Integration", "WIP"})
+    public void canStartupAndShutdownLegacyJmx() throws Exception {
+        karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
+                .configure("name", Identifiers.makeRandomId(8))
+                .configure("displayName", "Karaf Test")
+                .configure("jmxPort", "8099+")
+                .configure("rmiRegistryPort", "9099+"));
+            // NB: now the above parameters have the opposite semantics to 
before
+        
+        app.start(ImmutableList.of(localhost));
+        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, true);
+        
+        karaf.stop();
+        EntityTestUtils.assertAttributeEqualsEventually(karaf, 
Attributes.SERVICE_UP, false);
+    }
+    
+    // FIXME Test failing in jenkins; not sure why. The karaf log shows the 
mbeans never being
+    // registered so we are never able to connect to them over jmx.
+    @Test(groups = {"Integration", "WIP"})
+    public void testCanInstallAndUninstallBundle() throws Exception {
+        
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), 
HELLO_WORLD_JAR);
+        URL jarUrl = getClass().getResource(HELLO_WORLD_JAR);
+        assertNotNull(jarUrl);
+
+        karaf = 
app.createAndManageChild(EntitySpec.create(KarafContainer.class)
+            .configure("name", Identifiers.makeRandomId(8))
+            .configure("displayName", "Karaf Test")
+            .configure("jmxPort", "8099+")
+            .configure("rmiRegistryPort", "9099+"));
+        
+        app.start(ImmutableList.of(localhost));
+        
+        long bundleId = karaf.installBundle("wrap:"+jarUrl.toString());
+        
+        Map<Long, Map<String,?>> bundles = karaf.listBundles();
+        Map<String,?> bundle = bundles.get(bundleId);
+        assertNotNull(bundle, "expected="+bundleId+"; 
actual="+bundles.keySet());
+
+        // Undeploy: expect bundle to no longer be listed        
+        karaf.uninstallBundle(bundleId);
+        
+        Map<Long, Map<String,?>> bundles2 = karaf.listBundles();
+        Map<String,?> bundle2 = bundles2.get(bundleId);
+        assertNull(bundle2, "expectedAbsent="+bundleId+"; 
actual="+bundles2.keySet());
+    }
+}

Reply via email to