private static Object[] prepareArgsForEffectorFromMap(Effector<?> eff, Map m) { m = Maps.newLinkedHashMap(m); // make editable copy List newArgs = Lists.newArrayList(); int newArgsNeeded = eff.getParameters().size(); boolean mapUsed = false; for (int index = 0; index < eff.getParameters().size(); index++) { ParameterType<?> it = eff.getParameters().get(index); Object v; if (truth(it.getName()) && m.containsKey(it.getName())) { // argument is in the map v = m.remove(it.getName()); } else if (it instanceof BasicParameterType && ((BasicParameterType) it).hasDefaultValue()) { // finally, default values are used to make up for missing parameters v = ((BasicParameterType) it).getDefaultValue(); } else { throw new IllegalArgumentException( "Invalid arguments (missing argument " + it + ") for effector " + eff + ": " + m); } newArgs.add(TypeCoercions.coerce(v, it.getParameterClass())); newArgsNeeded--; } if (newArgsNeeded > 0) throw new IllegalArgumentException( "Invalid arguments (missing " + newArgsNeeded + ") for effector " + eff + ": " + m); return newArgs.toArray(new Object[newArgs.size()]); }
@Test public void testGetEffector() throws Exception { TestEntity entity2 = app.createAndManageChild(EntitySpecs.spec(TestEntity.class)); Effector<?> effector = entity2.getEntityType().getEffector("myEffector"); Effector<?> effector2 = entity2.getEntityType().getEffector("identityEffector", Object.class); assertEquals(effector.getName(), "myEffector"); assertEquals(effector2.getName(), "identityEffector"); }
public static Effector<?> findEffectorMatching( Set<Effector<?>> effectors, String effectorName, Map<String, ?> parameters) { // TODO Support overloading: check parameters as well for (Effector<?> effector : effectors) { if (effector.getName().equals(effectorName)) { return effector; } } return null; }
/** * method used for calls such as entity.effector(arg1, arg2) get routed here from * AbstractEntity.invokeMethod */ private static Object[] prepareArgsForEffectorFromArray(Effector<?> eff, Object args[]) { int newArgsNeeded = eff.getParameters().size(); if (args.length == 1 && args[0] instanceof Map) if (newArgsNeeded != 1 || !eff.getParameters().get(0).getParameterClass().isAssignableFrom(args[0].getClass())) // treat a map in an array as a map passed directly (unless the method takes a single-arg // map) // this is to support effector(param1: val1) return prepareArgsForEffectorFromMap(eff, (Map) args[0]); return prepareArgsForEffectorAsMapFromArray(eff, args).values().toArray(new Object[0]); }
public static Effector<?> findEffectorMatching(Entity entity, Method method) { effector: for (Effector<?> effector : entity.getEntityType().getEffectors()) { if (!effector.getName().equals(entity)) continue; if (effector.getParameters().size() != method.getParameterTypes().length) continue; for (int i = 0; i < effector.getParameters().size(); i++) { if (effector.getParameters().get(i).getParameterClass() != method.getParameterTypes()[i]) continue effector; } return effector; } return null; }
/** Invokes the effector so that its progress is tracked. */ public static <T> T invokeEffector(Entity entity, Effector<T> eff, Object[] args) { String id = entity.getId(); String name = eff.getName(); try { if (log.isDebugEnabled()) log.debug("Invoking effector {} on {}", new Object[] {name, entity}); if (log.isTraceEnabled()) log.trace("Invoking effector {} on {} with args {}", new Object[] {name, entity, args}); EntityManagementSupport mgmtSupport = ((EntityInternal) entity).getManagementSupport(); if (!mgmtSupport.isDeployed()) { mgmtSupport.attemptLegacyAutodeployment(name); } ManagementContextInternal mgmtContext = (ManagementContextInternal) ((EntityInternal) entity).getManagementContext(); mgmtSupport.getEntityChangeListener().onEffectorStarting(eff); try { return mgmtContext.invokeEffectorMethodSync(entity, eff, args); } finally { mgmtSupport.getEntityChangeListener().onEffectorCompleted(eff); } } catch (CancellationException ce) { log.info("Execution of effector {} on entity {} was cancelled", name, id); throw ce; } catch (ExecutionException ee) { log.info("Execution of effector {} on entity {} failed with {}", new Object[] {name, id, ee}); // Exceptions thrown in Futures are wrapped // FIXME Shouldn't pretend exception came from this thread?! Should we remove this unwrapping? if (ee.getCause() != null) throw Exceptions.propagate(ee.getCause()); else throw Exceptions.propagate(ee); } }
public static Map prepareArgsForEffectorAsMapFromArray(Effector<?> eff, Object args[]) { int newArgsNeeded = eff.getParameters().size(); List l = Lists.newArrayList(); l.addAll(Arrays.asList(args)); Map newArgs = new LinkedHashMap(); for (int index = 0; index < eff.getParameters().size(); index++) { ParameterType<?> it = eff.getParameters().get(index); if (l.size() >= newArgsNeeded) // all supplied (unnamed) arguments must be used; ignore map newArgs.put(it.getName(), l.remove(0)); // TODO do we ignore arguments in the same order that groovy does? else if (!l.isEmpty() && it.getParameterClass().isInstance(l.get(0))) { // if there are parameters supplied, and type is correct, they get applied before default // values // (this is akin to groovy) newArgs.put(it.getName(), l.remove(0)); } else if (it instanceof BasicParameterType && ((BasicParameterType) it).hasDefaultValue()) { // finally, default values are used to make up for missing parameters newArgs.put(it.getName(), ((BasicParameterType) it).getDefaultValue()); } else { throw new IllegalArgumentException( "Invalid arguments (count mismatch) for effector " + eff + ": " + args); } newArgsNeeded--; } if (newArgsNeeded > 0) throw new IllegalArgumentException( "Invalid arguments (missing " + newArgsNeeded + ") for effector " + eff + ": " + args); if (!l.isEmpty()) throw new IllegalArgumentException( "Invalid arguments (" + l.size() + " extra) for effector " + eff + ": " + args); return newArgs; }
public static <T> Task<T> invokeEffectorAsync( AbstractEntity entity, Effector<T> eff, Map<String, ?> parameters) { String id = entity.getId(); String name = eff.getName(); if (log.isDebugEnabled()) log.debug("Invoking-async effector {} on {}", new Object[] {name, entity}); if (log.isTraceEnabled()) log.trace( "Invoking-async effector {} on {} with args {}", new Object[] {name, entity, parameters}); EntityManagementSupport mgmtSupport = ((EntityInternal) entity).getManagementSupport(); if (!mgmtSupport.isDeployed()) { mgmtSupport.attemptLegacyAutodeployment(name); } ManagementContextInternal mgmtContext = (ManagementContextInternal) ((EntityInternal) entity).getManagementContext(); mgmtSupport.getEntityChangeListener().onEffectorStarting(eff); try { return mgmtContext.invokeEffector(entity, eff, parameters); } finally { mgmtSupport.getEntityChangeListener().onEffectorCompleted(eff); } }
/** * Takes arguments, and returns an array of arguments suitable for use by the Effector according * to the ParameterTypes it exposes. * * <p>The args can be: 1. an array of ordered arguments 2. a collection (which will be * automatically converted to an array) 3. a single argument (which will then be wrapped in an * array) 4. a map containing the (named) arguments 5. an array or collection single entry of a * map (treated same as 5 above) 6. a semi-populated array or collection that also containing a * map as first arg - uses ordered args in array, but uses named values from map in preference. 7. * semi-populated array or collection, where default values will otherwise be used. */ public static Object[] oldPrepareArgsForEffector(Effector<?> eff, Object args) { // attempt to coerce unexpected types Object[] argsArray; if (args == null) { argsArray = new Object[0]; } else if (args.getClass().isArray()) { argsArray = (Object[]) args; } else { if (args instanceof Collection) { argsArray = ((Collection) args).toArray(new Object[((Collection) args).size()]); } else { argsArray = new Object[] {args}; } } // if args starts with a map, assume it contains the named arguments // (but only use it when we have insufficient supplied arguments) List l = Lists.newArrayList(); l.addAll(Arrays.asList(argsArray)); Map m = (argsArray.length > 0 && argsArray[0] instanceof Map ? Maps.newLinkedHashMap((Map) l.remove(0)) : null); List newArgs = Lists.newArrayList(); int newArgsNeeded = eff.getParameters().size(); boolean mapUsed = false; for (int index = 0; index < eff.getParameters().size(); index++) { ParameterType<?> it = eff.getParameters().get(index); if (l.size() >= newArgsNeeded) // all supplied (unnamed) arguments must be used; ignore map newArgs.add(l.remove(0)); else if (truth(m) && truth(it.getName()) && m.containsKey(it.getName())) // some arguments were not supplied, and this one is in the map newArgs.add(m.remove(it.getName())); else if (index == 0 && Map.class.isAssignableFrom(it.getParameterClass())) { // if first arg is a map it takes the supplied map newArgs.add(m); mapUsed = true; } else if (!l.isEmpty() && it.getParameterClass().isInstance(l.get(0))) // if there are parameters supplied, and type is correct, they get applied before default // values // (this is akin to groovy) newArgs.add(l.remove(0)); else if (it instanceof BasicParameterType && ((BasicParameterType) it).hasDefaultValue()) // finally, default values are used to make up for missing parameters newArgs.add(((BasicParameterType) it).getDefaultValue()); else throw new IllegalArgumentException( "Invalid arguments (count mismatch) for effector " + eff + ": " + args); newArgsNeeded--; } if (newArgsNeeded > 0) throw new IllegalArgumentException( "Invalid arguments (missing " + newArgsNeeded + ") for effector " + eff + ": " + args); if (!l.isEmpty()) throw new IllegalArgumentException( "Invalid arguments (" + l.size() + " extra) for effector " + eff + ": " + args); if (truth(m) && !mapUsed) throw new IllegalArgumentException( "Invalid arguments (" + m.size() + " extra named) for effector " + eff + ": " + args); return newArgs.toArray(new Object[newArgs.size()]); }
@Override public boolean apply(@Nullable Effector<?> input) { return name.equals(input.getName()); }