You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ge...@apache.org on 2016/12/20 11:10:21 UTC

[03/13] brooklyn-server git commit: Deferred DSL evaluation, allowing for chaining

Deferred DSL evaluation, allowing for chaining


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

Branch: refs/heads/master
Commit: d71141ef995351ff172ade6e00f6f251a4479ee9
Parents: 2e0ee18
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Dec 8 12:29:51 2016 +0200
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Tue Dec 13 09:15:35 2016 +0200

----------------------------------------------------------------------
 .../spi/dsl/BrooklynDslInterpreter.java         |  24 ++--
 .../camp/brooklyn/spi/dsl/DslCallable.java      |  26 ++++
 .../spi/dsl/DslDeferredFunctionCall.java        | 124 +++++++++++++++++++
 .../brooklyn/spi/dsl/methods/DslComponent.java  |   3 +-
 .../camp/brooklyn/dsl/DslYamlBlockingTest.java  |   3 +-
 5 files changed, 167 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d71141ef/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java
index f43d33c..5e61b43 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslInterpreter.java
@@ -32,13 +32,12 @@ import org.apache.brooklyn.camp.spi.resolve.PlanInterpreter.PlanInterpreterAdapt
 import org.apache.brooklyn.camp.spi.resolve.interpret.PlanInterpretationNode;
 import org.apache.brooklyn.camp.spi.resolve.interpret.PlanInterpretationNode.Role;
 import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.Reflections;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-
 /**
  * {@link PlanInterpreter} which understands the $brooklyn DSL
  */
@@ -175,19 +174,22 @@ public class BrooklynDslInterpreter extends PlanInterpreterAdapter {
             o = BrooklynDslCommon.Functions.class;
             fn = Strings.removeFromStart(fn, "function.");
         }
+        List<Object> args = new ArrayList<>();
+        for (Object arg: f.getArgs()) {
+            args.add( deepEvaluation ? evaluate(arg, true) : arg );
+        }
         try {
-            List<Object> args = new ArrayList<>();
-            for (Object arg: f.getArgs()) {
-                args.add( deepEvaluation ? evaluate(arg, true) : arg );
+            if (o instanceof BrooklynDslDeferredSupplier && !(o instanceof DslCallable)) {
+                return new DslDeferredFunctionCall((BrooklynDslDeferredSupplier<?>) o, fn, args);
+            } else {
+                // Would prefer to keep the invocation logic encapsulated in DslDeferredFunctionCall, but
+                // for backwards compatibility will evaluate as much as possible eagerly (though it shouldn't matter in theory).
+                return DslDeferredFunctionCall.invokeOn(o, fn, args);
             }
-            Optional<Object> v = Reflections.invokeMethodWithArgs(o, fn, args);
-            if (v.isPresent()) return v.get();
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
-            throw Exceptions.propagate(new InvocationTargetException(e, "Error invoking '"+fn+"' on '"+o+"'"));
+            throw Exceptions.propagate(new InvocationTargetException(e, "Error invoking '"+fn+"' on '"+o+"' with arguments "+args+""));
         }
-        
-        throw new IllegalArgumentException("No such function '"+fn+"' on "+o);
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d71141ef/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslCallable.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslCallable.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslCallable.java
new file mode 100644
index 0000000..4eeddb7
--- /dev/null
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslCallable.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 The Apache Software Foundation.
+ *
+ * Licensed 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.camp.brooklyn.spi.dsl;
+
+import org.apache.brooklyn.util.core.task.DeferredSupplier;
+
+/**
+ * Marker interface so the evaluator can tell apart objects which are {@link DeferredSupplier}
+ * but which expect DSL methods called on them instead of the value they supply.
+ */
+public interface DslCallable {
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d71141ef/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java
new file mode 100644
index 0000000..20d1a4e
--- /dev/null
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslDeferredFunctionCall.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 The Apache Software Foundation.
+ *
+ * Licensed 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.camp.brooklyn.spi.dsl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.javalang.Reflections;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+
+public class DslDeferredFunctionCall extends BrooklynDslDeferredSupplier<Object> {
+
+    private static final long serialVersionUID = 3243262633795112155L;
+
+    // TODO should this be some of the super types?
+    private BrooklynDslDeferredSupplier<?> object;
+    private String fnName;
+    private List<?> args;
+
+    public DslDeferredFunctionCall(BrooklynDslDeferredSupplier<?> o, String fn, List<Object> args) {
+        this.object = o;
+        this.fnName = fn;
+        this.args = args;
+    }
+
+    @Override
+    public Maybe<Object> getImmediately() {
+        Maybe<?> obj = object.getImmediately();
+        if (obj.isPresent()) {
+            if (obj.isNull()) {
+                throw new IllegalArgumentException("Deferred function call, " + object + 
+                        " evaluates to null (when calling " + fnName + "(" + toString(args) + "))");
+            }
+            return Maybe.of(invokeOn(obj.get()));
+        }
+        return Maybe.absent("Could not evaluate immediately " + object);
+    }
+
+    @Override
+    public Task<Object> newTask() {
+        return Tasks.builder()
+                .displayName("Deferred function call " + object + "." + fnName + "(" + toString(args) + ")")
+                .tag(BrooklynTaskTags.TRANSIENT_TASK_TAG)
+                .dynamic(false)
+                .body(new Callable<Object>() {
+                    @Override
+                    public Object call() throws Exception {
+                        Object obj = object.get();
+                        if (obj == null) {
+                            throw new IllegalArgumentException("Deferred function call, " + object + 
+                                    " evaluates to null (when calling " + fnName + "(" + DslDeferredFunctionCall.toString(args) + "))");
+                        }
+                        return invokeOn(obj);
+                    }
+
+                }).build();
+    }
+
+    protected Object invokeOn(Object obj) {
+        return invokeOn(obj, fnName, args);
+    }
+
+    protected static Object invokeOn(Object obj, String fnName, List<?> args) {
+        Maybe<Object> v;
+        try {
+            v = Reflections.invokeMethodFromArgs(obj, fnName, args);
+        } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
+            Exceptions.propagateIfFatal(e);
+            throw Exceptions.propagate(new InvocationTargetException(e, "Error invoking '"+fnName+"("+toString(args)+")' on '"+obj+"'"));
+        }
+        if (v.isPresent()) {
+            // Value is most likely another BrooklynDslDeferredSupplier - let the caller handle it,
+            return v.get();
+        } else {
+            throw new IllegalArgumentException("No such function '"+fnName+"("+toString(args)+")' on "+obj);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(object, fnName, args);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null || getClass() != obj.getClass()) return false;
+        DslDeferredFunctionCall that = DslDeferredFunctionCall.class.cast(obj);
+        return Objects.equal(this.object, that.object) &&
+                Objects.equal(this.fnName, that.fnName) &&
+                Objects.equal(this.args, that.args);
+    }
+
+    @Override
+    public String toString() {
+        return object + "." + fnName + "(" + toString(args) + ")";
+    }
+    
+    private static String toString(List<?> args) {
+        if (args == null) return "";
+        return Joiner.on(", ").join(args);
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d71141ef/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
index 7274b2e..ea8e818 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.DslCallable;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
@@ -62,7 +63,7 @@ import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;
 import com.google.common.util.concurrent.Callables;
 
-public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
+public class DslComponent extends BrooklynDslDeferredSupplier<Entity> implements DslCallable {
 
     private static final long serialVersionUID = -7715984495268724954L;
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d71141ef/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/dsl/DslYamlBlockingTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/dsl/DslYamlBlockingTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/dsl/DslYamlBlockingTest.java
index 280b060..772a28f 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/dsl/DslYamlBlockingTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/dsl/DslYamlBlockingTest.java
@@ -23,6 +23,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
+import org.apache.brooklyn.camp.brooklyn.spi.dsl.DslCallable;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.EntityInternal;
@@ -615,7 +616,7 @@ public class DslYamlBlockingTest extends AbstractYamlTest {
         assertEquals(getConfigEventually(app, DEST), Boolean.TRUE);
     }
 
-    public static class DslTestCallable implements DeferredSupplier<TestDslSupplier>, ImmediateSupplier<TestDslSupplier> {
+    public static class DslTestCallable implements DslCallable, DeferredSupplier<TestDslSupplier>, ImmediateSupplier<TestDslSupplier> {
 
         @Override
         public Maybe<TestDslSupplier> getImmediately() {