You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2014/11/10 16:59:49 UTC

[3/4] incubator-brooklyn git commit: Read UsageListeners from config in brooklyn.properties

Read UsageListeners from config in brooklyn.properties


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

Branch: refs/heads/master
Commit: 7ee06ba3c67a6d5ea1cb494b75aabb20b00c13f0
Parents: e315409
Author: Aled Sage <al...@gmail.com>
Authored: Fri Nov 7 19:44:34 2014 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Nov 10 11:39:53 2014 +0000

----------------------------------------------------------------------
 .../management/internal/LocalUsageManager.java  |  29 +++++
 .../management/internal/UsageManager.java       |  11 ++
 .../management/usage/UsageListenerTest.java     | 108 +++++++++++++++++++
 3 files changed, 148 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7ee06ba3/core/src/main/java/brooklyn/management/internal/LocalUsageManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalUsageManager.java b/core/src/main/java/brooklyn/management/internal/LocalUsageManager.java
index 1bb4a8e..476ea3e 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalUsageManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalUsageManager.java
@@ -20,6 +20,7 @@ package brooklyn.management.internal;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -41,8 +42,12 @@ import brooklyn.location.basic.LocationInternal;
 import brooklyn.management.usage.ApplicationUsage;
 import brooklyn.management.usage.LocationUsage;
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.javalang.Reflections;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -59,6 +64,23 @@ public class LocalUsageManager implements UsageManager {
     
     private static final Logger log = LoggerFactory.getLogger(LocalUsageManager.class);
 
+    // Register a coercion from String->UsageListener, so that USAGE_LISTENERS defined in brooklyn.properties
+    // will be instantiated, given their class names.
+    static {
+        TypeCoercions.registerAdapter(String.class, UsageListener.class, new Function<String, UsageListener>() {
+            @Override public UsageListener apply(String input) {
+                // TODO Want to use classLoader = mgmt.getCatalog().getRootClassLoader();
+                ClassLoader classLoader = LocalUsageManager.class.getClassLoader();
+                Optional<Object> result = Reflections.invokeConstructorWithArgs(classLoader, input);
+                if (result.isPresent()) {
+                    return (UsageListener) result.get();
+                } else {
+                    throw new IllegalStateException("Failed to create UsageListener from class name '"+input+"' using no-arg constructor");
+                }
+            }
+        });
+    }
+    
     @VisibleForTesting
     public static final String APPLICATION_USAGE_KEY = "usage-application";
     
@@ -77,6 +99,13 @@ public class LocalUsageManager implements UsageManager {
 
     public LocalUsageManager(LocalManagementContext managementContext) {
         this.managementContext = checkNotNull(managementContext, "managementContext");
+        
+        Collection<UsageListener> listeners = managementContext.getBrooklynProperties().getConfig(UsageManager.USAGE_LISTENERS);
+        if (listeners != null) {
+            for (UsageListener listener : listeners) {
+                addUsageListener(listener);
+            }
+        }
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7ee06ba3/core/src/main/java/brooklyn/management/internal/UsageManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/UsageManager.java b/core/src/main/java/brooklyn/management/internal/UsageManager.java
index 35e602f..56a5ace 100644
--- a/core/src/main/java/brooklyn/management/internal/UsageManager.java
+++ b/core/src/main/java/brooklyn/management/internal/UsageManager.java
@@ -18,10 +18,13 @@
  */
 package brooklyn.management.internal;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import brooklyn.config.ConfigKey;
 import brooklyn.entity.Application;
+import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.location.Location;
 import brooklyn.management.usage.ApplicationUsage;
@@ -31,10 +34,18 @@ import brooklyn.management.usage.LocationUsage.LocationEvent;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
 
 @Beta
 public interface UsageManager {
 
+    @SuppressWarnings("serial")
+    public static final ConfigKey<List<UsageListener>> USAGE_LISTENERS = ConfigKeys.newConfigKey(
+            new TypeToken<List<UsageListener>>() {},
+            "brooklyn.usageManager.listeners", "Optional usage listeners (i.e. for metering)",
+            ImmutableList.<UsageListener>of());
+
     public interface UsageListener {
         public static final UsageListener NOOP = new UsageListener() {
             @Override public void onApplicationEvent(String applicationId, String applicationName, String entityType, 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7ee06ba3/software/base/src/test/java/brooklyn/management/usage/UsageListenerTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/management/usage/UsageListenerTest.java b/software/base/src/test/java/brooklyn/management/usage/UsageListenerTest.java
new file mode 100644
index 0000000..0cc27c7
--- /dev/null
+++ b/software/base/src/test/java/brooklyn/management/usage/UsageListenerTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.management.usage;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.Entities;
+import brooklyn.location.Location;
+import brooklyn.management.internal.ManagementContextInternal;
+import brooklyn.management.internal.UsageManager;
+import brooklyn.management.internal.UsageManager.UsageListener;
+import brooklyn.test.Asserts;
+import brooklyn.test.entity.LocalManagementContextForTests;
+import brooklyn.test.entity.TestApplication;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+public class UsageListenerTest {
+
+    // Also see {Application|Location}UsageTrackingTest for listener functionality
+    
+    private static final Logger LOG = LoggerFactory.getLogger(ApplicationUsageTrackingTest.class);
+
+    protected TestApplication app;
+    protected ManagementContextInternal mgmt;
+
+    protected boolean shouldSkipOnBoxBaseDirResolution() {
+        return true;
+    }
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        RecordingStaticUsageListener.clearInstances();
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        try {
+            if (mgmt != null) Entities.destroyAll(mgmt);
+        } catch (Throwable t) {
+            LOG.error("Caught exception in tearDown method", t);
+        } finally {
+            mgmt = null;
+            RecordingStaticUsageListener.clearInstances();
+        }
+    }
+
+    @Test
+    public void testAddUsageListenerViaProperties() throws Exception {
+        BrooklynProperties brooklynProperties = BrooklynProperties.Factory.newEmpty();
+        brooklynProperties.put(UsageManager.USAGE_LISTENERS, RecordingStaticUsageListener.class.getName());
+        mgmt = LocalManagementContextForTests.newInstance(brooklynProperties);
+        
+        app = TestApplication.Factory.newManagedInstanceForTests(mgmt);
+        app.start(ImmutableList.<Location>of());
+
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                List<List<?>> events = RecordingStaticUsageListener.getInstance().getApplicationEvents();
+                assertTrue(events.size() > 0, "events="+events); // expect some events
+            }});
+    }
+    
+    public static class RecordingStaticUsageListener extends RecordingUsageListener implements UsageListener {
+        private static final List<RecordingStaticUsageListener> STATIC_INSTANCES = Lists.newCopyOnWriteArrayList();
+        
+        public static RecordingStaticUsageListener getInstance() {
+            return Iterables.getOnlyElement(STATIC_INSTANCES);
+        }
+
+        public static void clearInstances() {
+            STATIC_INSTANCES.clear();
+        }
+        
+        public RecordingStaticUsageListener() {
+            // Bad to leak a ref to this before constructor finished, but we'll live with it because
+            // it's just test code!
+            STATIC_INSTANCES.add(this);
+        }
+    }
+}