|
20 | 20 |
|
21 | 21 | import static org.apache.brooklyn.camp.brooklyn.spi.dsl.DslUtils.resolved; |
22 | 22 |
|
| 23 | +import java.util.Iterator; |
| 24 | +import java.util.List; |
| 25 | +import java.util.Map; |
23 | 26 | import java.util.NoSuchElementException; |
24 | 27 | import java.util.concurrent.Callable; |
25 | 28 | import java.util.concurrent.ExecutionException; |
26 | 29 |
|
| 30 | +import org.apache.brooklyn.api.effector.Effector; |
27 | 31 | import org.apache.brooklyn.api.entity.Entity; |
28 | 32 | import org.apache.brooklyn.api.mgmt.ExecutionContext; |
29 | 33 | import org.apache.brooklyn.api.mgmt.Task; |
| 34 | +import org.apache.brooklyn.api.mgmt.TaskAdaptable; |
| 35 | +import org.apache.brooklyn.api.mgmt.TaskFactory; |
30 | 36 | import org.apache.brooklyn.api.objs.BrooklynObject; |
31 | 37 | import org.apache.brooklyn.api.sensor.AttributeSensor; |
32 | 38 | import org.apache.brooklyn.api.sensor.Sensor; |
|
43 | 49 | import org.apache.brooklyn.core.mgmt.internal.EntityManagerInternal; |
44 | 50 | import org.apache.brooklyn.core.sensor.DependentConfiguration; |
45 | 51 | import org.apache.brooklyn.core.sensor.Sensors; |
| 52 | +import org.apache.brooklyn.util.collections.MutableMap; |
46 | 53 | import org.apache.brooklyn.util.core.flags.TypeCoercions; |
47 | 54 | import org.apache.brooklyn.util.core.task.BasicExecutionContext; |
48 | 55 | import org.apache.brooklyn.util.core.task.DeferredSupplier; |
| 56 | +import org.apache.brooklyn.util.core.task.HasSideEffects; |
49 | 57 | import org.apache.brooklyn.util.core.task.ImmediateSupplier; |
50 | 58 | import org.apache.brooklyn.util.core.task.TaskBuilder; |
51 | 59 | import org.apache.brooklyn.util.core.task.Tasks; |
52 | 60 | import org.apache.brooklyn.util.exceptions.Exceptions; |
53 | 61 | import org.apache.brooklyn.util.groovy.GroovyJavaMethods; |
54 | 62 | import org.apache.brooklyn.util.guava.Maybe; |
| 63 | +import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes; |
55 | 64 | import org.apache.brooklyn.util.text.Strings; |
56 | 65 |
|
57 | 66 | import com.google.common.base.CaseFormat; |
58 | 67 | import com.google.common.base.Converter; |
| 68 | +import com.google.common.base.Function; |
59 | 69 | import com.google.common.base.Objects; |
60 | 70 | import com.google.common.base.Optional; |
61 | 71 | import com.google.common.base.Preconditions; |
62 | 72 | import com.google.common.base.Predicate; |
63 | 73 | import com.google.common.base.Predicates; |
| 74 | +import com.google.common.collect.ImmutableList; |
| 75 | +import com.google.common.collect.ImmutableMap; |
64 | 76 | import com.google.common.collect.Iterables; |
| 77 | +import com.google.common.collect.Lists; |
65 | 78 | import com.google.common.util.concurrent.Callables; |
66 | 79 |
|
67 | 80 | public class DslComponent extends BrooklynDslDeferredSupplier<Entity> implements DslFunctionSource { |
@@ -509,6 +522,119 @@ public String toString() { |
509 | 522 | } |
510 | 523 | } |
511 | 524 |
|
| 525 | + @DslAccessible |
| 526 | + public BrooklynDslDeferredSupplier<?> effector(final String effectorName) { |
| 527 | + return new ExecuteEffector(this, effectorName, ImmutableMap.<String, Object>of()); |
| 528 | + } |
| 529 | + @DslAccessible |
| 530 | + public BrooklynDslDeferredSupplier<?> effector(final String effectorName, final Map<String, ?> args) { |
| 531 | + return new ExecuteEffector(this, effectorName, args); |
| 532 | + } |
| 533 | + public BrooklynDslDeferredSupplier<?> effector(final String effectorName, Object... args) { |
| 534 | + return new ExecuteEffector(this, effectorName, ImmutableList.copyOf(args)); |
| 535 | + } |
| 536 | + protected static class ExecuteEffector extends BrooklynDslDeferredSupplier<Object> implements HasSideEffects { |
| 537 | + private static final long serialVersionUID = 1740899524088902383L; |
| 538 | + private final DslComponent component; |
| 539 | + private final String effectorName; |
| 540 | + private final Map<String, ?> args; |
| 541 | + private final List<? extends Object> argList; |
| 542 | + private Task<?> cachedTask; |
| 543 | + |
| 544 | + public ExecuteEffector(DslComponent component, String effectorName, Map<String, ?> args) { |
| 545 | + this.component = Preconditions.checkNotNull(component); |
| 546 | + this.effectorName = effectorName; |
| 547 | + this.args = args; |
| 548 | + this.argList = null; |
| 549 | + } |
| 550 | + |
| 551 | + public ExecuteEffector(DslComponent component, String effectorName, List<? extends Object> args) { |
| 552 | + this.component = Preconditions.checkNotNull(component); |
| 553 | + this.effectorName = effectorName; |
| 554 | + this.argList = args; |
| 555 | + this.args = null; |
| 556 | + } |
| 557 | + |
| 558 | + @Override |
| 559 | + public Maybe<Object> getImmediately() { |
| 560 | + return Maybe.absent(); |
| 561 | + } |
| 562 | + |
| 563 | + @SuppressWarnings("unchecked") |
| 564 | + @Override |
| 565 | + public Task<Object> newTask() { |
| 566 | + Entity targetEntity = component.get(); |
| 567 | + Maybe<Effector<?>> targetEffector = targetEntity.getEntityType().getEffectorByName(effectorName); |
| 568 | + if (targetEffector.isAbsentOrNull()) { |
| 569 | + throw new IllegalArgumentException("Effector " + effectorName + " not found on entity: " + targetEntity); |
| 570 | + } |
| 571 | + synchronized (this) { |
| 572 | + if (cachedTask == null) { |
| 573 | + if (argList == null) { |
| 574 | + cachedTask = Entities.invokeEffector(targetEntity, targetEntity, targetEffector.get(), args); |
| 575 | + } else { |
| 576 | + cachedTask = invokeWithDeferredArgs(targetEntity, targetEffector.get(), argList); |
| 577 | + } |
| 578 | + } |
| 579 | + } |
| 580 | + return (Task<Object>) cachedTask; |
| 581 | + } |
| 582 | + |
| 583 | + private Task<Object> invokeWithDeferredArgs(final Entity targetEntity, final Effector<?> targetEffector, final List<? extends Object> args) { |
| 584 | + List<TaskAdaptable<Object>> taskArgs = Lists.newArrayList(); |
| 585 | + for (Object arg : args) { |
| 586 | + if (arg instanceof TaskAdaptable) { |
| 587 | + taskArgs.add((TaskAdaptable<Object>) arg); |
| 588 | + } else if (arg instanceof TaskFactory) { |
| 589 | + taskArgs.add(((TaskFactory<TaskAdaptable<Object>>) arg).newTask()); |
| 590 | + } |
| 591 | + } |
| 592 | + |
| 593 | + return DependentConfiguration.transformMultiple( |
| 594 | + MutableMap.of("displayName", "invoking '"+targetEffector.getName()+"' with "+taskArgs.size()+" task"+(taskArgs.size()!=1?"s":"")), |
| 595 | + new Function<List<Object>, Object>() { |
| 596 | + @Override |
| 597 | + public Object apply(List<Object> input) { |
| 598 | + Iterator<?> tri = input.iterator(); |
| 599 | + Object[] vv = new Object[args.size()]; |
| 600 | + int i=0; |
| 601 | + for (Object arg : args) { |
| 602 | + if (arg instanceof TaskAdaptable || arg instanceof TaskFactory) { |
| 603 | + vv[i] = tri.next(); |
| 604 | + } else if (arg instanceof DeferredSupplier) { |
| 605 | + vv[i] = ((DeferredSupplier<?>) arg).get(); |
| 606 | + } else { |
| 607 | + vv[i] = arg; |
| 608 | + } |
| 609 | + i++; |
| 610 | + } |
| 611 | + return Entities.invokeEffectorWithArgs(targetEntity, targetEntity, targetEffector, vv); |
| 612 | + } |
| 613 | + }, |
| 614 | + taskArgs); |
| 615 | + } |
| 616 | + |
| 617 | + @Override |
| 618 | + public int hashCode() { |
| 619 | + return Objects.hashCode(component, effectorName); |
| 620 | + } |
| 621 | + |
| 622 | + @Override |
| 623 | + public boolean equals(Object obj) { |
| 624 | + if (this == obj) return true; |
| 625 | + if (obj == null || getClass() != obj.getClass()) return false; |
| 626 | + ExecuteEffector that = ExecuteEffector.class.cast(obj); |
| 627 | + return Objects.equal(this.component, that.component) && |
| 628 | + Objects.equal(this.effectorName, that.effectorName); |
| 629 | + } |
| 630 | + |
| 631 | + @Override |
| 632 | + public String toString() { |
| 633 | + return (component.scope==Scope.THIS ? "" : component.toString()+".") + |
| 634 | + "effector("+JavaStringEscapes.wrapJavaString(effectorName)+")"; |
| 635 | + } |
| 636 | + } |
| 637 | + |
512 | 638 | @DslAccessible |
513 | 639 | public BrooklynDslDeferredSupplier<?> config(final Object keyNameOrSupplier) { |
514 | 640 | return new DslConfigSupplier(this, keyNameOrSupplier); |
@@ -763,5 +889,5 @@ public String toString() { |
763 | 889 |
|
764 | 890 | return DslToStringHelpers.component(scopeComponent, remainder); |
765 | 891 | } |
766 | | - |
| 892 | + |
767 | 893 | } |
0 commit comments