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 2015/10/21 11:12:33 UTC

[2/3] incubator-brooklyn git commit: TemplateProcessor: for location

TemplateProcessor: for location


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

Branch: refs/heads/master
Commit: 76b098bd1f01732647fb5f85ac2603cd0afb5c03
Parents: c2494dc
Author: Aled Sage <al...@gmail.com>
Authored: Tue Oct 20 14:59:58 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Oct 21 09:50:30 2015 +0100

----------------------------------------------------------------------
 .../util/core/text/TemplateProcessor.java       | 161 +++++++++++++++++--
 .../util/core/text/TemplateProcessorTest.java   |  18 +++
 2 files changed, 168 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/76b098bd/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
index 58efcd4..923f733 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/text/TemplateProcessor.java
@@ -18,6 +18,8 @@
  */
 package org.apache.brooklyn.util.core.text;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -33,6 +35,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.location.internal.LocationInternal;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.sensor.Sensors;
@@ -115,6 +118,11 @@ public class TemplateProcessor {
         return processTemplateContents(templateContents, new EntityAndMapTemplateModel(managementContext, extraSubstitutions));
     }
 
+    /** Processes template contents according to {@link EntityAndMapTemplateModel}. */
+    public static String processTemplateContents(String templateContents, Location location, Map<String,? extends Object> extraSubstitutions) {
+        return processTemplateContents(templateContents, new LocationAndMapTemplateModel((LocationInternal)location, extraSubstitutions));
+    }
+
     /**
      * A Freemarker {@link TemplateHashModel} which will correctly handle entries of the form "a.b" in this map,
      * matching against template requests for "${a.b}".
@@ -181,7 +189,7 @@ public class TemplateProcessor {
     
     /** FreeMarker {@link TemplateHashModel} which resolves keys inside the given entity or management context.
      * Callers are required to include dots for dot-separated keys.
-     * Freemarker will only due this when in inside bracket notation in an outer map, as in <code>${outer['a.b.']}</code>; 
+     * Freemarker will only do this when in inside bracket notation in an outer map, as in <code>${outer['a.b.']}</code>; 
      * as a result this is intended only for use by {@link EntityAndMapTemplateModel} where 
      * a caller has used bracked notation, as in <code>${mgmt['key.subkey']}</code>. */
     protected static final class EntityConfigTemplateModel implements TemplateHashModel {
@@ -189,13 +197,87 @@ public class TemplateProcessor {
         protected final ManagementContext mgmt;
 
         protected EntityConfigTemplateModel(EntityInternal entity) {
-            this.entity = entity;
+            this.entity = checkNotNull(entity, "entity");
             this.mgmt = entity.getManagementContext();
         }
 
-        protected EntityConfigTemplateModel(ManagementContext mgmt) {
-            this.entity = null;
-            this.mgmt = mgmt;
+        @Override
+        public boolean isEmpty() { return false; }
+
+        @Override
+        public TemplateModel get(String key) throws TemplateModelException {
+            try {
+                Object result = entity.getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                
+                if (result==null)
+                    result = mgmt.getConfig().getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                
+                if (result!=null)
+                    return wrapAsTemplateModel( result );
+                
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                throw new IllegalStateException("Error accessing config '"+key+"'"+" on "+entity+": "+e, e);
+            }
+            
+            return null;
+        }
+        
+        @Override
+        public String toString() {
+            return getClass().getName()+"["+entity+"]";
+        }
+    }
+
+    /** FreeMarker {@link TemplateHashModel} which resolves keys inside the given management context.
+     * Callers are required to include dots for dot-separated keys.
+     * Freemarker will only do this when in inside bracket notation in an outer map, as in <code>${outer['a.b.']}</code>; 
+     * as a result this is intended only for use by {@link EntityAndMapTemplateModel} where 
+     * a caller has used bracked notation, as in <code>${mgmt['key.subkey']}</code>. */
+    protected static final class MgmtConfigTemplateModel implements TemplateHashModel {
+        protected final ManagementContext mgmt;
+
+        protected MgmtConfigTemplateModel(ManagementContext mgmt) {
+            this.mgmt = checkNotNull(mgmt, "mgmt");
+        }
+
+        @Override
+        public boolean isEmpty() { return false; }
+
+        @Override
+        public TemplateModel get(String key) throws TemplateModelException {
+            try {
+                Object result = mgmt.getConfig().getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                
+                if (result!=null)
+                    return wrapAsTemplateModel( result );
+                
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                throw new IllegalStateException("Error accessing config '"+key+"': "+e, e);
+            }
+            
+            return null;
+        }
+        
+        @Override
+        public String toString() {
+            return getClass().getName()+"["+mgmt+"]";
+        }
+    }
+    
+    /** FreeMarker {@link TemplateHashModel} which resolves keys inside the given location.
+     * Callers are required to include dots for dot-separated keys.
+     * Freemarker will only do this when in inside bracket notation in an outer map, as in <code>${outer['a.b.']}</code>; 
+     * as a result this is intended only for use by {@link LocationAndMapTemplateModel} where 
+     * a caller has used bracked notation, as in <code>${mgmt['key.subkey']}</code>. */
+    protected static final class LocationConfigTemplateModel implements TemplateHashModel {
+        protected final LocationInternal location;
+        protected final ManagementContext mgmt;
+
+        protected LocationConfigTemplateModel(LocationInternal location) {
+            this.location = checkNotNull(location, "location");
+            this.mgmt = location.getManagementContext();
         }
 
         @Override
@@ -206,8 +288,8 @@ public class TemplateProcessor {
             try {
                 Object result = null;
                 
-                if (entity!=null)
-                    result = entity.getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                result = location.getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                
                 if (result==null && mgmt!=null)
                     result = mgmt.getConfig().getConfig(ConfigKeys.builder(Object.class).name(key).build());
                 
@@ -217,7 +299,7 @@ public class TemplateProcessor {
             } catch (Exception e) {
                 Exceptions.propagateIfFatal(e);
                 throw new IllegalStateException("Error accessing config '"+key+"'"
-                    + (entity!=null ? " on "+entity : "")+": "+e, e);
+                    + (location!=null ? " on "+location : "")+": "+e, e);
             }
             
             return null;
@@ -225,7 +307,7 @@ public class TemplateProcessor {
         
         @Override
         public String toString() {
-            return getClass().getName()+"["+entity+"]";
+            return getClass().getName()+"["+location+"]";
         }
     }
 
@@ -311,10 +393,10 @@ public class TemplateProcessor {
                 if (entity!=null)
                     return new EntityConfigTemplateModel(entity);
                 else
-                    return new EntityConfigTemplateModel(mgmt);
+                    return new MgmtConfigTemplateModel(mgmt);
             }
             if ("mgmt".equals(key)) {
-                return new EntityConfigTemplateModel(mgmt);
+                return new MgmtConfigTemplateModel(mgmt);
             }
 
             if ("driver".equals(key) && driver!=null)
@@ -351,6 +433,63 @@ public class TemplateProcessor {
         }
     }
 
+    /**
+     * Provides access to config on an entity or management context, using
+     * <code>${config['entity.config.key']}</code> or <code>${mgmt['brooklyn.properties.key']}</code> notation,
+     * and also allowing access to <code>getX()</code> methods on entity (interface) or driver
+     * using <code>${entity.x}</code> or <code><${driver.x}</code>.
+     * Optional extra properties can be supplied, treated as per {@link DotSplittingTemplateModel}.
+     */
+    protected static final class LocationAndMapTemplateModel implements TemplateHashModel {
+        protected final LocationInternal location;
+        protected final ManagementContext mgmt;
+        protected final DotSplittingTemplateModel extraSubstitutionsModel;
+
+        protected LocationAndMapTemplateModel(LocationInternal location, Map<String,? extends Object> extraSubstitutions) {
+            this.location = checkNotNull(location, "location");
+            this.mgmt = location.getManagementContext();
+            this.extraSubstitutionsModel = new DotSplittingTemplateModel(extraSubstitutions);
+        }
+
+        @Override
+        public boolean isEmpty() { return false; }
+
+        @Override
+        public TemplateModel get(String key) throws TemplateModelException {
+            if (extraSubstitutionsModel.contains(key))
+                return wrapAsTemplateModel( extraSubstitutionsModel.get(key) );
+
+            if ("location".equals(key))
+                return wrapAsTemplateModel( location );
+            if ("config".equals(key)) {
+                return new LocationConfigTemplateModel(location);
+            }
+            if ("mgmt".equals(key)) {
+                return new MgmtConfigTemplateModel(mgmt);
+            }
+
+            if (mgmt!=null) {
+                // TODO deprecated in 0.7.0, remove after next version
+                // ie not supported to access global props without qualification
+                Object result = mgmt.getConfig().getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                if (result!=null) { 
+                    log.warn("Deprecated access of global brooklyn.properties value for "+key+"; should be qualified with 'mgmt.'");
+                    return wrapAsTemplateModel( result );
+                }
+            }
+            
+            if ("javaSysProps".equals(key))
+                return wrapAsTemplateModel( System.getProperties() );
+
+            return null;
+        }
+        
+        @Override
+        public String toString() {
+            return getClass().getName()+"["+location+"]";
+        }
+    }
+
     /** Processes template contents with the given items in scope as per {@link EntityAndMapTemplateModel}. */
     public static String processTemplateContents(String templateContents, final EntityInternal entity, Map<String,? extends Object> extraSubstitutions) {
         return processTemplateContents(templateContents, new EntityAndMapTemplateModel(entity, extraSubstitutions));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/76b098bd/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java b/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java
index b2fd6a7..0f2d989 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/text/TemplateProcessorTest.java
@@ -26,6 +26,8 @@ import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.test.FixedLocaleTest;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
 import org.testng.Assert;
@@ -102,6 +104,22 @@ public class TemplateProcessorTest extends BrooklynAppUnitTestSupport {
     }
     
     @Test
+    public void testLocationGetterMethod() {
+        LocalhostMachineProvisioningLocation location = app.newLocalhostProvisioningLocation();
+        String templateContents = "${location.id}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, location, ImmutableMap.<String,Object>of());
+        assertEquals(result, location.getId());
+    }
+    
+    @Test
+    public void testLocationConfig() {
+        LocalhostMachineProvisioningLocation location = app.newLocalhostProvisioningLocation(ImmutableMap.of("mykey", "myval"));
+        String templateContents = "${config['mykey']}";//"+TestEntity.CONF_NAME.getName()+"']}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, location, ImmutableMap.<String,Object>of());
+        assertEquals(result, "myval");
+    }
+    
+    @Test
     public void testManagementContextConfig() {
         mgmt.getBrooklynProperties().put("globalmykey", "myval");
         String templateContents = "${mgmt.globalmykey}";