http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/main/java/brooklyn/util/file/ArchiveTasks.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/file/ArchiveTasks.java b/core/src/main/java/brooklyn/util/file/ArchiveTasks.java deleted file mode 100644 index b183f62..0000000 --- a/core/src/main/java/brooklyn/util/file/ArchiveTasks.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.util.file; - -import java.util.Map; - -import org.apache.brooklyn.api.management.TaskAdaptable; -import org.apache.brooklyn.api.management.TaskFactory; - -import org.apache.brooklyn.location.basic.SshMachineLocation; -import brooklyn.util.ResourceUtils; -import brooklyn.util.net.Urls; -import brooklyn.util.task.Tasks; - -public class ArchiveTasks { - - /** as {@link #deploy(ResourceUtils, Map, String, SshMachineLocation, String, String, String)} with the most common parameters */ - public static TaskFactory<?> deploy(final ResourceUtils optionalResolver, final String archiveUrl, final SshMachineLocation machine, final String destDir) { - return deploy(optionalResolver, null, archiveUrl, machine, destDir, false, null, null); - } - - /** returns a task which installs and unpacks the given archive, as per {@link ArchiveUtils#deploy(ResourceUtils, Map, String, SshMachineLocation, String, String, String)}; - * if allowNonarchivesOrKeepArchiveAfterDeploy is false, this task will fail if the item is not an archive; - * in cases where the download type is not clear in the URL but is known by the caller, supply a optionalDestFile including the appropriate file extension */ - public static TaskFactory<?> deploy(final ResourceUtils resolver, final Map<String, ?> props, final String archiveUrl, final SshMachineLocation machine, final String destDir, final boolean allowNonarchivesOrKeepArchiveAfterDeploy, final String optionalTmpDir, final String optionalDestFile) { - return new TaskFactory<TaskAdaptable<?>>() { - @Override - public TaskAdaptable<?> newTask() { - return Tasks.<Void>builder().name("deploying "+Urls.getBasename(archiveUrl)).description("installing "+archiveUrl+" and unpacking to "+destDir).body(new Runnable() { - @Override - public void run() { - boolean unpacked = ArchiveUtils.deploy(resolver, props, archiveUrl, machine, destDir, allowNonarchivesOrKeepArchiveAfterDeploy, optionalTmpDir, optionalDestFile); - if (!unpacked && !allowNonarchivesOrKeepArchiveAfterDeploy) { - throw new IllegalStateException("Unable to unpack archive from "+archiveUrl+"; not able to infer archive type"); - } - } - }).build(); - } - }; - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/main/java/brooklyn/util/file/ArchiveUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/file/ArchiveUtils.java b/core/src/main/java/brooklyn/util/file/ArchiveUtils.java deleted file mode 100644 index d072b70..0000000 --- a/core/src/main/java/brooklyn/util/file/ArchiveUtils.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * 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.util.file; - -import static java.lang.String.format; - -import java.io.File; -import java.io.IOException; -import java.util.EnumSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.brooklyn.location.basic.SshMachineLocation; -import brooklyn.util.ResourceUtils; -import brooklyn.util.collections.MutableList; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.javalang.StackTraceSimplifier; -import brooklyn.util.net.Urls; -import brooklyn.util.os.Os; -import brooklyn.util.ssh.BashCommands; -import brooklyn.util.task.DynamicTasks; -import brooklyn.util.task.Tasks; -import brooklyn.util.task.ssh.SshTasks; -import brooklyn.util.text.Strings; - -import com.google.common.base.Charsets; -import com.google.common.base.Preconditions; -import com.google.common.io.Files; - -public class ArchiveUtils { - - private static final Logger log = LoggerFactory.getLogger(ArchiveUtils.class); - - // TODO Make this a ConfigKey on the machine location - /** Number of attempts when copying a file to a remote server. */ - public static final int NUM_RETRIES_FOR_COPYING = 5; - - /** - * The types of archive that are supported by Brooklyn. - */ - public static enum ArchiveType { - TAR, - TGZ, - TBZ, - ZIP, - JAR, - WAR, - EAR, - UNKNOWN; - - /** - * Zip format archives used by Java. - */ - public static Set<ArchiveType> ZIP_ARCHIVES = EnumSet.of(ArchiveType.ZIP, ArchiveType.JAR, ArchiveType.WAR, ArchiveType.EAR); - - public static ArchiveUtils.ArchiveType of(String filename) { - if (filename == null) return null; - String ext = Files.getFileExtension(filename); - try { - return valueOf(ext.toUpperCase()); - } catch (IllegalArgumentException iae) { - if (filename.toLowerCase().endsWith(".tar.gz")) { - return TGZ; - } else if (filename.toLowerCase().endsWith(".tar.bz") || - filename.toLowerCase().endsWith(".tar.bz2") || - filename.toLowerCase().endsWith(".tar.xz")) { - return TBZ; - } else { - return UNKNOWN; - } - } - } - - @Override - public String toString() { - if (UNKNOWN.equals(this)) { - return ""; - } else { - return name().toLowerCase(); - } - } - } - - /** - * Returns the list of commands used to install support for an archive with the given name. - */ - public static List<String> installCommands(String fileName) { - List<String> commands = new LinkedList<String>(); - switch (ArchiveType.of(fileName)) { - case TAR: - case TGZ: - case TBZ: - commands.add(BashCommands.INSTALL_TAR); - break; - case ZIP: - commands.add(BashCommands.INSTALL_UNZIP); - break; - case JAR: - case WAR: - case EAR: - case UNKNOWN: - break; - } - return commands; - } - - /** - * Returns the list of commands used to extract the contents of the archive with the given name. - * <p> - * Optionally, Java archives of type - * - * @see #extractCommands(String, String) - */ - public static List<String> extractCommands(String fileName, String sourceDir, String targetDir, boolean extractJar) { - return extractCommands(fileName, sourceDir, targetDir, extractJar, true); - } - - /** as {@link #extractCommands(String, String, String, boolean)}, but also with option to keep the original */ - public static List<String> extractCommands(String fileName, String sourceDir, String targetDir, boolean extractJar, boolean keepOriginal) { - List<String> commands = new LinkedList<String>(); - commands.add("cd " + targetDir); - String sourcePath = Os.mergePathsUnix(sourceDir, fileName); - switch (ArchiveType.of(fileName)) { - case TAR: - commands.add("tar xvf " + sourcePath); - break; - case TGZ: - commands.add("tar xvfz " + sourcePath); - break; - case TBZ: - commands.add("tar xvfj " + sourcePath); - break; - case ZIP: - commands.add("unzip " + sourcePath); - break; - case JAR: - case WAR: - case EAR: - if (extractJar) { - commands.add("jar -xvf " + sourcePath); - break; - } - case UNKNOWN: - if (!sourcePath.equals(Urls.mergePaths(targetDir, fileName))) { - commands.add("cp " + sourcePath + " " + targetDir); - } else { - keepOriginal = true; - // else we'd just end up deleting it! - // this branch will often lead to errors in any case, see the allowNonarchivesOrKeepArchiveAfterDeploy parameter - // in ArchiveTasks which calls through to here and then fails in the case corresponding to this code branch - } - break; - } - if (!keepOriginal && !commands.isEmpty()) - commands.add("rm "+sourcePath); - return commands; - } - - /** - * Returns the list of commands used to extract the contents of the archive with the given name. - * <p> - * The archive will be extracted in its current directory unless it is a Java archive of type {@code .jar}, - * {@code .war} or {@code .ear}, which will be left as is. - * - * @see #extractCommands(String, String, String, boolean) - */ - public static List<String> extractCommands(String fileName, String sourceDir) { - return extractCommands(fileName, sourceDir, ".", false); - } - - /** - * Deploys an archive file to a remote machine and extracts the contents. - */ - public static void deploy(String archiveUrl, SshMachineLocation machine, String destDir) { - deploy(MutableMap.<String, Object>of(), archiveUrl, machine, destDir); - } - - /** - * Deploys an archive file to a remote machine and extracts the contents. - * <p> - * Copies the archive file from the given URL to the destination directory and extracts - * the contents. If the URL is a local directory, the contents are packaged as a Zip archive first. - * - * @see #deploy(String, SshMachineLocation, String, String) - * @see #deploy(Map, String, SshMachineLocation, String, String, String) - */ - public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir) { - if (Urls.isDirectory(archiveUrl)) { - File zipFile = ArchiveBuilder.zip().entry(".", Urls.toFile(archiveUrl)).create(); - archiveUrl = zipFile.getAbsolutePath(); - } - - // Determine filename - String destFile = archiveUrl.contains("?") ? archiveUrl.substring(0, archiveUrl.indexOf('?')) : archiveUrl; - destFile = destFile.substring(destFile.lastIndexOf('/') + 1); - - deploy(props, archiveUrl, machine, destDir, destFile); - } - - /** - * Deploys an archive file to a remote machine and extracts the contents. - * <p> - * Copies the archive file from the given URL to a file in the destination directory and extracts - * the contents. - * - * @see #deploy(String, SshMachineLocation, String) - * @see #deploy(Map, String, SshMachineLocation, String, String, String) - */ - public static void deploy(String archiveUrl, SshMachineLocation machine, String destDir, String destFile) { - deploy(MutableMap.<String, Object>of(), archiveUrl, machine, destDir, destDir, destFile); - } - public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir, String destFile) { - deploy(props, archiveUrl, machine, destDir, destDir, destFile); - } - public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String tmpDir, String destDir, String destFile) { - deploy(null, props, archiveUrl, machine, destDir, true, tmpDir, destFile); - } - - /** - * Deploys an archive file to a remote machine and extracts the contents. - * <p> - * Copies the archive file from the given URL to a file in a temporary directory and extracts - * the contents in the destination directory. For Java archives of type {@code .jar}, - * {@code .war} or {@code .ear} the file is simply copied. - * - * @return true if the archive is downloaded AND unpacked; false if it is downloaded but not unpacked; - * throws if there was an error downloading or, for known archive types, unpacking. - * - * @see #deploy(String, SshMachineLocation, String) - * @see #deploy(Map, String, SshMachineLocation, String, String, String) - * @see #install(SshMachineLocation, String, String, int) - */ - public static boolean deploy(ResourceUtils resolver, Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir, boolean keepArchiveAfterUnpacking, String optionalTmpDir, String optionalDestFile) { - String destFile = optionalDestFile; - if (destFile==null) destFile = Urls.getBasename(Preconditions.checkNotNull(archiveUrl, "archiveUrl")); - if (Strings.isBlank(destFile)) - throw new IllegalStateException("Not given filename and cannot infer archive type from '"+archiveUrl+"'"); - - String tmpDir = optionalTmpDir; - if (tmpDir==null) tmpDir=Preconditions.checkNotNull(destDir, "destDir"); - if (props==null) props = MutableMap.of(); - String destPath = Os.mergePaths(tmpDir, destFile); - - // Use the location mutex to prevent package manager locking issues - machine.acquireMutex("installing", "installing archive"); - try { - int result = install(resolver, props, machine, archiveUrl, destPath, NUM_RETRIES_FOR_COPYING); - if (result != 0) { - throw new IllegalStateException(format("Unable to install archive %s to %s", archiveUrl, machine)); - } - - // extract, now using task if available - MutableList<String> commands = MutableList.copyOf(installCommands(destFile)) - .appendAll(extractCommands(destFile, tmpDir, destDir, false, keepArchiveAfterUnpacking)); - if (DynamicTasks.getTaskQueuingContext()!=null) { - result = DynamicTasks.queue(SshTasks.newSshExecTaskFactory(machine, commands.toArray(new String[0])).summary("extracting archive").requiringExitCodeZero()).get(); - } else { - result = machine.execCommands(props, "extracting content", commands); - } - if (result != 0) { - throw new IllegalStateException(format("Failed to expand archive %s on %s", archiveUrl, machine)); - } - return ArchiveType.of(destFile)!=ArchiveType.UNKNOWN; - } finally { - machine.releaseMutex("installing"); - } - } - - /** - * Installs a URL onto a remote machine. - * - * @see #install(Map, SshMachineLocation, String, String, int) - */ - public static int install(SshMachineLocation machine, String urlToInstall, String target) { - return install(MutableMap.<String, Object>of(), machine, urlToInstall, target, NUM_RETRIES_FOR_COPYING); - } - - /** - * Installs a URL onto a remote machine. - * - * @see #install(SshMachineLocation, String, String) - * @see SshMachineLocation#installTo(Map, String, String) - */ - public static int install(Map<String, ?> props, SshMachineLocation machine, String urlToInstall, String target, int numAttempts) { - return install(null, props, machine, urlToInstall, target, numAttempts); - } - - public static int install(ResourceUtils resolver, Map<String, ?> props, SshMachineLocation machine, String urlToInstall, String target, int numAttempts) { - if (resolver==null) resolver = ResourceUtils.create(machine); - Exception lastError = null; - int retriesRemaining = numAttempts; - int attemptNum = 0; - do { - attemptNum++; - try { - Tasks.setBlockingDetails("Installing "+urlToInstall+" at "+machine); - // TODO would be nice to have this in a task (and the things within it!) - return machine.installTo(resolver, props, urlToInstall, target); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - lastError = e; - String stack = StackTraceSimplifier.toString(e); - if (stack.contains("net.schmizz.sshj.sftp.RemoteFile.write")) { - log.warn("Failed to transfer "+urlToInstall+" to "+machine+", retryable error, attempt "+attemptNum+"/"+numAttempts+": "+e); - continue; - } - log.warn("Failed to transfer "+urlToInstall+" to "+machine+", not a retryable error so failing: "+e); - throw Exceptions.propagate(e); - } finally { - Tasks.resetBlockingDetails(); - } - } while (retriesRemaining --> 0); - throw Exceptions.propagate(lastError); - } - - /** - * Copies the entire contents of a file to a String. - * - * @see com.google.common.io.Files#toString(File, java.nio.charset.Charset) - */ - public static String readFullyString(File sourceFile) { - try { - return Files.toString(sourceFile, Charsets.UTF_8); - } catch (IOException ioe) { - throw Exceptions.propagate(ioe); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/main/java/brooklyn/util/flags/ClassCoercionException.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/flags/ClassCoercionException.java b/core/src/main/java/brooklyn/util/flags/ClassCoercionException.java deleted file mode 100644 index 17385ac..0000000 --- a/core/src/main/java/brooklyn/util/flags/ClassCoercionException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.util.flags; - -/** - * Thrown to indicate that {@link TypeCoercions} could not cast an object from one - * class to another. - */ -public class ClassCoercionException extends ClassCastException { - public ClassCoercionException() { - super(); - } - - /** - * Constructs a <code>ClassCoercionException</code> with the specified - * detail message. - * - * @param s the detail message. - */ - public ClassCoercionException(String s) { - super(s); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/main/java/brooklyn/util/flags/FlagUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/flags/FlagUtils.java b/core/src/main/java/brooklyn/util/flags/FlagUtils.java deleted file mode 100644 index 0e596ac..0000000 --- a/core/src/main/java/brooklyn/util/flags/FlagUtils.java +++ /dev/null @@ -1,587 +0,0 @@ -/* - * 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.util.flags; - -import static brooklyn.util.GroovyJavaMethods.elvis; -import static brooklyn.util.GroovyJavaMethods.truth; -import static com.google.common.base.Preconditions.checkNotNull; -import groovy.lang.Closure; -import groovy.lang.GroovyObject; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; - -import org.apache.brooklyn.api.entity.trait.Configurable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.config.ConfigKey; -import brooklyn.config.ConfigKey.HasConfigKey; -import brooklyn.util.GroovyJavaMethods; -import brooklyn.util.config.ConfigBag; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.guava.Maybe; - -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.base.Throwables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - - -/** class to help transfer values passed as named arguments to other well-known variables/fields/objects; - * see the test case for example usage */ -public class FlagUtils { - - public static final Logger log = LoggerFactory.getLogger(FlagUtils.class); - - private FlagUtils() {} - - /** see {@link #setFieldsFromFlags(Object o, ConfigBag)} */ - public static Map<?, ?> setPublicFieldsFromFlags(Map<?, ?> flags, Object o) { - return setFieldsFromFlagsInternal(o, Arrays.asList(o.getClass().getFields()), flags, null, true); - } - - /** see {@link #setFieldsFromFlags(Object, ConfigBag)} */ - public static Map<?, ?> setFieldsFromFlags(Map<?, ?> flags, Object o) { - return setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), flags, null, true); - } - - /** sets all fields (including private and static, local and inherited) annotated {@link SetFromFlag} on the given object, - * from the given flags map, returning just those flag-value pairs passed in which do not correspond to SetFromFlags fields - * annotated ConfigKey and HasConfigKey fields are _configured_ (and we assume the object in that case is {@link Configurable}); - * keys should be ConfigKey, HasConfigKey, or String; - * default values are also applied unless that is specified false on one of the variants of this method which takes such an argument - */ - public static void setFieldsFromFlags(Object o, ConfigBag configBag) { - setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), configBag.getAllConfig(), configBag, true); - } - - /** as {@link #setFieldsFromFlags(Object, ConfigBag)}, but allowing control over whether default values should be set */ - public static void setFieldsFromFlags(Object o, ConfigBag configBag, boolean setDefaultVals) { - setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), configBag.getAllConfig(), configBag, setDefaultVals); - } - - /** as {@link #setFieldsFromFlags(Object, ConfigBag)}, but specifying a subset of flags to use */ - public static void setFieldsFromFlagsWithBag(Object o, Map<?,?> flags, ConfigBag configBag, boolean setDefaultVals) { - setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), flags, configBag, setDefaultVals); - } - - /** - * Sets the field with the given flag (if it exists) to the given value. - * Will attempt to coerce the value to the required type. - * Will respect "nullable" on the SetFromFlag annotation. - * - * @throws IllegalArgumentException If fieldVal is null and the SetFromFlag annotation set nullable=false - */ - public static boolean setFieldFromFlag(Object o, String flagName, Object fieldVal) { - return setFieldFromFlagInternal(checkNotNull(flagName, "flagName"), fieldVal, o, getAllFields(o.getClass())); - } - - /** get all fields (including private and static) on the given object and all supertypes, - * that are annotated with SetFromFlags. - */ - public static Map<String, ?> getFieldsWithFlags(Object o) { - return getFieldsWithFlagsInternal(o, getAllFields(o.getClass())); - } - - /** - * Finds the {@link Field} on the given object annotated with the given name flag. - */ - public static Field findFieldForFlag(String flagName, Object o) { - return findFieldForFlagInternal(flagName, o, getAllFields(o.getClass())); - } - - /** get all fields (including private and static) and their values on the given object and all supertypes, - * where the field is annotated with SetFromFlags. - */ - public static Map<String, Object> getFieldsWithFlagsExcludingModifiers(Object o, int excludingModifiers) { - List<Field> filteredFields = Lists.newArrayList(); - for (Field contender : getAllFields(o.getClass())) { - if ((contender.getModifiers() & excludingModifiers) == 0) { - filteredFields.add(contender); - } - } - return getFieldsWithFlagsInternal(o, filteredFields); - } - - /** get all fields with the given modifiers, and their values on the given object and all supertypes, - * where the field is annotated with SetFromFlags. - */ - public static Map<String, Object> getFieldsWithFlagsWithModifiers(Object o, int requiredModifiers) { - List<Field> filteredFields = Lists.newArrayList(); - for (Field contender : getAllFields(o.getClass())) { - if ((contender.getModifiers() & requiredModifiers) == requiredModifiers) { - filteredFields.add(contender); - } - } - return getFieldsWithFlagsInternal(o, filteredFields); - } - - /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, - * using the indicated flags/config-bag - * @deprecated since 0.7.0 use {@link #setAllConfigKeys(Map, Configurable, boolean)} */ - public static Map<String, ?> setAllConfigKeys(Map<String, ?> flagsOrConfig, Configurable instance) { - return setAllConfigKeys(flagsOrConfig, instance, false); - } - /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, - * using the indicated flags/config-bag */ - public static Map<String, ?> setAllConfigKeys(Map<String, ?> flagsOrConfig, Configurable instance, boolean includeFlags) { - ConfigBag bag = new ConfigBag().putAll(flagsOrConfig); - setAllConfigKeys(instance, bag, includeFlags); - return bag.getUnusedConfigMutable(); - } - - /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, - * using the indicated flags/config-bag - * @deprecated since 0.7.0 use {@link #setAllConfigKeys(Configurable, ConfigBag, boolean)} */ - public static void setAllConfigKeys(Configurable o, ConfigBag bag) { - setAllConfigKeys(o, bag, false); - } - /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, - * using the indicated flags/config-bag */ - public static void setAllConfigKeys(Configurable o, ConfigBag bag, boolean includeFlags) { - for (Field f: getAllFields(o.getClass())) { - ConfigKey<?> key = getFieldAsConfigKey(o, f); - if (key!=null) { - FlagConfigKeyAndValueRecord record = getFlagConfigKeyRecord(f, key, bag); - if ((includeFlags && record.isValuePresent()) || record.getConfigKeyMaybeValue().isPresent()) { - setField(o, f, record.getValueOrNullPreferringConfigKey(), null); - } - } - } - } - - public static class FlagConfigKeyAndValueRecord { - private String flagName = null; - private ConfigKey<?> configKey = null; - private Maybe<Object> flagValue = Maybe.absent(); - private Maybe<Object> configKeyValue = Maybe.absent(); - - public String getFlagName() { - return flagName; - } - public ConfigKey<?> getConfigKey() { - return configKey; - } - public Maybe<Object> getFlagMaybeValue() { - return flagValue; - } - public Maybe<Object> getConfigKeyMaybeValue() { - return configKeyValue; - } - public Object getValueOrNullPreferringConfigKey() { - return getConfigKeyMaybeValue().or(getFlagMaybeValue()).orNull(); - } - public Object getValueOrNullPreferringFlag() { - return getFlagMaybeValue().or(getConfigKeyMaybeValue()).orNull(); - } - /** true if value is present for either flag or config key */ - public boolean isValuePresent() { - return flagValue.isPresent() || configKeyValue.isPresent(); - } - - @Override - public String toString() { - return Objects.toStringHelper(this).omitNullValues() - .add("flag", flagName) - .add("configKey", configKey) - .add("flagValue", flagValue.orNull()) - .add("configKeyValue", configKeyValue.orNull()) - .toString(); - } - } - - /** gets all the flags/keys in the given config bag which are applicable to the given type's config keys and flags */ - public static <T> List<FlagConfigKeyAndValueRecord> findAllFlagsAndConfigKeys(T optionalInstance, Class<? extends T> type, ConfigBag input) { - List<FlagConfigKeyAndValueRecord> output = new ArrayList<FlagUtils.FlagConfigKeyAndValueRecord>(); - for (Field f: getAllFields(type)) { - ConfigKey<?> key = getFieldAsConfigKey(optionalInstance, f); - FlagConfigKeyAndValueRecord record = getFlagConfigKeyRecord(f, key, input); - if (record.isValuePresent()) - output.add(record); - } - return output; - } - - /** returns the flag/config-key record for the given input */ - private static FlagConfigKeyAndValueRecord getFlagConfigKeyRecord(Field f, ConfigKey<?> key, ConfigBag input) { - FlagConfigKeyAndValueRecord result = new FlagConfigKeyAndValueRecord(); - result.configKey = key; - if (key!=null && input.containsKey(key)) - result.configKeyValue = Maybe.<Object>of(input.getStringKey(key.getName())); - SetFromFlag flag = f.getAnnotation(SetFromFlag.class); - if (flag!=null) { - result.flagName = flag.value(); - if (input.containsKey(flag.value())) - result.flagValue = Maybe.of(input.getStringKey(flag.value())); - } - return result; - } - - /** returns all fields on the given class, superclasses, and interfaces thereof, in that order of preference, - * (excluding fields on Object) */ - public static List<Field> getAllFields(Class<?> base, Closure<Boolean> filter) { - return getAllFields(base, GroovyJavaMethods.<Field>predicateFromClosure(filter)); - } - public static List<Field> getAllFields(Class<?> base) { - return getAllFields(base, Predicates.<Field>alwaysTrue()); - } - public static List<Field> getAllFields(Class<?> base, Predicate<Field> filter) { - return getLocalFields(getAllAssignableTypes(base), filter); - } - /** returns all fields explicitly declared on the given classes */ - public static List<Field> getLocalFields(List<Class<?>> classes) { - return getLocalFields(classes, Predicates.<Field>alwaysTrue()); - } - public static List<Field> getLocalFields(List<Class<?>> classes, Closure<Boolean> filter) { - return getLocalFields(classes, GroovyJavaMethods.<Field>predicateFromClosure(filter)); - } - public static List<Field> getLocalFields(List<Class<?>> classes, Predicate<Field> filter) { - List<Field> fields = Lists.newArrayList(); - for (Class<?> c : classes) { - for (Field f : c.getDeclaredFields()) { - if (filter.apply(f)) fields.add(f); - } - } - return fields; - } - - /** returns base, superclasses, then interfaces */ - public static List<Class<?>> getAllAssignableTypes(Class<?> base) { - return getAllAssignableTypes(base, new Predicate<Class<?>>() { - @Override public boolean apply(Class<?> it) { - return (it != Object.class) && (it != GroovyObject.class); - } - }); - } - public static List<Class<?>> getAllAssignableTypes(Class<?> base, Closure<Boolean> filter) { - return getAllAssignableTypes(base, GroovyJavaMethods.<Class<?>>predicateFromClosure(filter)); - } - public static List<Class<?>> getAllAssignableTypes(Class<?> base, Predicate<Class<?>> filter) { - List<Class<?>> classes = Lists.newArrayList(); - for (Class<?> c = base; c != null; c = c.getSuperclass()) { - if (filter.apply(c)) classes.add(c); - } - for (int i=0; i<classes.size(); i++) { - for (Class<?> interf : classes.get(i).getInterfaces()) { - if (filter.apply(interf) && !(classes.contains(interf))) classes.add(interf); - } - } - return classes; - } - - private static Map<String, Object> getFieldsWithFlagsInternal(Object o, Collection<Field> fields) { - Map<String, Object> result = Maps.newLinkedHashMap(); - for (Field f: fields) { - SetFromFlag cf = f.getAnnotation(SetFromFlag.class); - if (cf != null) { - String flagName = elvis(cf.value(), f.getName()); - if (truth(flagName)) { - result.put(flagName, getField(o, f)); - } else { - log.warn("Ignoring field {} of object {} as no flag name available", f, o); - } - } - } - return result; - } - - private static Field findFieldForFlagInternal(String flagName, Object o, Collection<Field> fields) { - for (Field f: fields) { - SetFromFlag cf = f.getAnnotation(SetFromFlag.class); - if (cf != null) { - String contenderName = elvis(cf.value(), f.getName()); - if (flagName.equals(contenderName)) { - return f; - } - } - } - throw new NoSuchElementException("Field with flag "+flagName+" not found on "+o+" of type "+(o != null ? o.getClass() : null)); - } - - private static boolean setFieldFromFlagInternal(String flagName, Object fieldVal, Object o, Collection<Field> fields) { - for (Field f: fields) { - SetFromFlag cf = f.getAnnotation(SetFromFlag.class); - if (cf != null && flagName.equals(elvis(cf.value(), f.getName()))) { - setField(o, f, fieldVal, cf); - return true; - } - } - return false; - } - - private static Map<String, ?> setFieldsFromFlagsInternal(Object o, Collection<Field> fields, Map<?,?> flagsOrConfig, ConfigBag bag, boolean setDefaultVals) { - if (bag==null) bag = new ConfigBag().putAll(flagsOrConfig); - for (Field f: fields) { - SetFromFlag cf = f.getAnnotation(SetFromFlag.class); - if (cf!=null) setFieldFromConfig(o, f, bag, cf, setDefaultVals); - } - return bag.getUnusedConfigMutable(); - } - - private static void setFieldFromConfig(Object o, Field f, ConfigBag bag, SetFromFlag optionalAnnotation, boolean setDefaultVals) { - String flagName = optionalAnnotation==null ? null : (String)elvis(optionalAnnotation.value(), f.getName()); - // prefer flag name, if present - if (truth(flagName) && bag.containsKey(flagName)) { - setField(o, f, bag.getStringKey(flagName), optionalAnnotation); - return; - } - // first check whether it is a key - ConfigKey<?> key = getFieldAsConfigKey(o, f); - if (key!=null && bag.containsKey(key)) { - Object uncoercedValue = bag.getStringKey(key.getName()); - setField(o, f, uncoercedValue, optionalAnnotation); - return; - } - if (setDefaultVals && optionalAnnotation!=null && truth(optionalAnnotation.defaultVal())) { - Object oldValue; - try { - f.setAccessible(true); - oldValue = f.get(o); - if (oldValue==null || oldValue.equals(getDefaultValueForType(f.getType()))) { - setField(o, f, optionalAnnotation.defaultVal(), optionalAnnotation); - } - } catch (Exception e) { - Exceptions.propagate(e); - } - return; - } - } - - /** returns the given field as a config key, if it is an accessible config key, otherwise null */ - private static ConfigKey<?> getFieldAsConfigKey(Object optionalInstance, Field f) { - if (optionalInstance==null) { - if ((f.getModifiers() & Modifier.STATIC)==0) - // non-static field on null instance, can't be set - return null; - } - if (ConfigKey.class.isAssignableFrom(f.getType())) { - return (ConfigKey<?>) getField(optionalInstance, f); - } else if (HasConfigKey.class.isAssignableFrom(f.getType())) { - return ((HasConfigKey<?>)getField(optionalInstance, f)).getConfigKey(); - } - return null; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static void setConfig(Object objectOfField, ConfigKey<?> key, Object value, SetFromFlag optionalAnnotation) { - if (objectOfField instanceof Configurable) { - ((Configurable)objectOfField).setConfig((ConfigKey)key, value); - return; - } else { - if (optionalAnnotation==null) { - log.warn("Cannot set key "+key.getName()+" on "+objectOfField+": containing class is not Configurable"); - } else if (!key.getName().equals(optionalAnnotation.value())) { - log.warn("Cannot set key "+key.getName()+" on "+objectOfField+" from flag "+optionalAnnotation.value()+": containing class is not Configurable"); - } else { - // if key and flag are the same, then it will probably happen automatically - if (log.isDebugEnabled()) - log.debug("Cannot set key "+key.getName()+" on "+objectOfField+" from flag "+optionalAnnotation.value()+": containing class is not Configurable"); - } - return; - } - } - - /** sets the field to the value, after checking whether the given value can be set - * respecting the constraints of the annotation - */ - public static void setField(Object objectOfField, Field f, Object value, SetFromFlag optionalAnnotation) { - try { - ConfigKey<?> key = getFieldAsConfigKey(objectOfField, f); - if (key!=null) { - setConfig(objectOfField, key, value, optionalAnnotation); - return; - } - - if (!f.isAccessible()) f.setAccessible(true); - if (optionalAnnotation!=null && optionalAnnotation.immutable()) { - Object oldValue = f.get(objectOfField); - if (!Objects.equal(oldValue, getDefaultValueForType(f.getType())) && oldValue != value) { - throw new IllegalStateException("Forbidden modification to immutable field "+ - f+" in "+objectOfField+": attempting to change to "+value+" when was already "+oldValue); - } - } - if (optionalAnnotation!=null && !optionalAnnotation.nullable() && value==null) { - throw new IllegalArgumentException("Forbidden null assignment to non-nullable field "+ - f+" in "+objectOfField); - } - if (optionalAnnotation!=null && (f.getModifiers() & Modifier.STATIC)==Modifier.STATIC) - log.warn("Setting static field "+f+" in "+objectOfField+" from flag "+optionalAnnotation.value()+": discouraged"); - - Object newValue; - try { - newValue = TypeCoercions.coerce(value, f.getType()); - } catch (Exception e) { - throw new IllegalArgumentException("Cannot set "+f+" in "+objectOfField+" from type "+value.getClass()+" ("+value+"): "+e, e); - } - f.set(objectOfField, newValue); - if (log.isTraceEnabled()) log.trace("FlagUtils for "+objectOfField+", setting field="+f.getName()+"; val="+value+"; newVal="+newValue+"; key="+key); - - } catch (IllegalAccessException e) { - throw Throwables.propagate(e); - } - } - - /** gets the value of the field. - */ - public static Object getField(Object objectOfField, Field f) { - try { - if (!f.isAccessible()) f.setAccessible(true); - return f.get(objectOfField); - } catch (IllegalAccessException e) { - throw Throwables.propagate(e); - } - } - - /** returns the default/inital value that is assigned to fields of the givien type; - * if the type is not primitive this value is null; - * for primitive types it is obvious but not AFAIK programmatically visible - * (e.g. 0 for int, false for boolean) - */ - public static Object getDefaultValueForType(Class<?> t) { - if (!t.isPrimitive()) return null; - if (t==Integer.TYPE) return (int)0; - if (t==Long.TYPE) return (long)0; - if (t==Double.TYPE) return (double)0; - if (t==Float.TYPE) return (float)0; - if (t==Byte.TYPE) return (byte)0; - if (t==Short.TYPE) return (short)0; - if (t==Character.TYPE) return (char)0; - if (t==Boolean.TYPE) return false; - //should never happen - throw new IllegalStateException("Class "+t+" is an unknown primitive."); - } - - /** returns a map of all fields which are annotated 'SetFromFlag', along with the annotation */ - public static Map<Field,SetFromFlag> getAnnotatedFields(Class<?> type) { - Map<Field, SetFromFlag> result = Maps.newLinkedHashMap(); - for (Field f: getAllFields(type)) { - SetFromFlag cf = f.getAnnotation(SetFromFlag.class); - if (truth(cf)) result.put(f, cf); - } - return result; - } - - /** returns a map of all {@link ConfigKey} fields which are annotated 'SetFromFlag', along with the annotation */ - public static Map<ConfigKey<?>,SetFromFlag> getAnnotatedConfigKeys(Class<?> type) { - Map<ConfigKey<?>, SetFromFlag> result = Maps.newLinkedHashMap(); - List<Field> fields = getAllFields(type, new Predicate<Field>() { - @Override public boolean apply(Field f) { - return (f != null) && ConfigKey.class.isAssignableFrom(f.getType()) && ((f.getModifiers() & Modifier.STATIC)!=0); - }}); - for (Field f: fields) { - SetFromFlag cf = f.getAnnotation(SetFromFlag.class); - if (cf != null) { - ConfigKey<?> key = getFieldAsConfigKey(null, f); - if (key != null) { - result.put(key, cf); - } - } - } - return result; - } - - /** returns a map of all fields which are annotated 'SetFromFlag' with their current values; - * useful if you want to clone settings from one object - */ - public static Map<String,Object> getFieldsWithValues(Object o) { - try { - Map<String, Object> result = Maps.newLinkedHashMap(); - for (Map.Entry<Field, SetFromFlag> entry : getAnnotatedFields(o.getClass()).entrySet()) { - Field f = entry.getKey(); - SetFromFlag cf = entry.getValue(); - String flagName = elvis(cf.value(), f.getName()); - if (truth(flagName)) { - if (!f.isAccessible()) f.setAccessible(true); - result.put(flagName, f.get(o)); - } - } - return result; - } catch (IllegalAccessException e) { - throw Throwables.propagate(e); - } - } - - /** - * @throws an IllegalStateException if there are fields required (nullable=false) which are unset - * @throws wrapped IllegalAccessException - */ - public static void checkRequiredFields(Object o) { - try { - Set<String> unsetFields = Sets.newLinkedHashSet(); - for (Map.Entry<Field, SetFromFlag> entry : getAnnotatedFields(o.getClass()).entrySet()) { - Field f = entry.getKey(); - SetFromFlag cf = entry.getValue(); - if (!cf.nullable()) { - String flagName = elvis(cf.value(), f.getName()); - if (!f.isAccessible()) f.setAccessible(true); - Object v = f.get(o); - if (v==null) unsetFields.add(flagName); - } - } - if (truth(unsetFields)) { - throw new IllegalStateException("Missing required "+(unsetFields.size()>1 ? "fields" : "field")+": "+unsetFields); - } - } catch (IllegalAccessException e) { - throw Throwables.propagate(e); - } - } - -// /** sets all fields in target annotated with @SetFromFlag using the configuration in the given config bag */ -// public static void setFieldsFromConfigFlags(Object target, ConfigBag configBag) { -// setFieldsFromConfigFlags(target, configBag.getAllConfig(), configBag); -// } -// -// -// /** sets all fields in target annotated with @SetFromFlag using the configuration in the given configToUse, -// * marking used in the given configBag */ -// public static void setFieldsFromConfigFlags(Object target, Map<?,?> configToUse, ConfigBag configBag) { -// for (Map.Entry<?,?> entry: configToUse.entrySet()) { -// setFieldFromConfigFlag(target, entry.getKey(), entry.getValue(), configBag); -// } -// } -// -// public static void setFieldFromConfigFlag(Object target, Object key, Object value, ConfigBag optionalConfigBag) { -// String name = null; -// if (key instanceof String) name = (String)key; -// else if (key instanceof ConfigKey<?>) name = ((ConfigKey<?>)key).getName(); -// else if (key instanceof HasConfigKey<?>) name = ((HasConfigKey<?>)key).getConfigKey().getName(); -// else { -// if (key!=null) { -// log.warn("Invalid config type "+key.getClass().getCanonicalName()+" ("+key+") when configuring "+target+"; ignoring"); -// } -// return; -// } -// if (setFieldFromFlag(name, value, target)) { -// if (optionalConfigBag!=null) -// optionalConfigBag.markUsed(name); -// } -// } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/main/java/brooklyn/util/flags/MethodCoercions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/flags/MethodCoercions.java b/core/src/main/java/brooklyn/util/flags/MethodCoercions.java deleted file mode 100644 index c9f00fe..0000000 --- a/core/src/main/java/brooklyn/util/flags/MethodCoercions.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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.util.flags; - -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.guava.Maybe; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.reflect.TypeToken; - -import javax.annotation.Nullable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.List; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * A way of binding a loosely-specified method call into a strongly-typed Java method call. - */ -public class MethodCoercions { - - /** - * Returns a predicate that matches a method with the given name, and a single parameter that - * {@link brooklyn.util.flags.TypeCoercions#tryCoerce(Object, com.google.common.reflect.TypeToken)} can process - * from the given argument. - * - * @param methodName name of the method - * @param argument argument that is intended to be given - * @return a predicate that will match a compatible method - */ - public static Predicate<Method> matchSingleParameterMethod(final String methodName, final Object argument) { - checkNotNull(methodName, "methodName"); - checkNotNull(argument, "argument"); - - return new Predicate<Method>() { - @Override - public boolean apply(@Nullable Method input) { - if (input == null) return false; - if (!input.getName().equals(methodName)) return false; - Type[] parameterTypes = input.getGenericParameterTypes(); - return parameterTypes.length == 1 - && TypeCoercions.tryCoerce(argument, TypeToken.of(parameterTypes[0])).isPresentAndNonNull(); - - } - }; - } - - /** - * Tries to find a single-parameter method with a parameter compatible with (can be coerced to) the argument, and - * invokes it. - * - * @param instance the object to invoke the method on - * @param methodName the name of the method to invoke - * @param argument the argument to the method's parameter. - * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched. - */ - public static Maybe<?> tryFindAndInvokeSingleParameterMethod(final Object instance, final String methodName, final Object argument) { - Class<?> clazz = instance.getClass(); - Iterable<Method> methods = Arrays.asList(clazz.getMethods()); - Optional<Method> matchingMethod = Iterables.tryFind(methods, matchSingleParameterMethod(methodName, argument)); - if (matchingMethod.isPresent()) { - Method method = matchingMethod.get(); - try { - Type paramType = method.getGenericParameterTypes()[0]; - Object coercedArgument = TypeCoercions.coerce(argument, TypeToken.of(paramType)); - return Maybe.of(method.invoke(instance, coercedArgument)); - } catch (IllegalAccessException | InvocationTargetException e) { - throw Exceptions.propagate(e); - } - } else { - return Maybe.absent(); - } - } - - /** - * Returns a predicate that matches a method with the given name, and parameters that - * {@link brooklyn.util.flags.TypeCoercions#tryCoerce(Object, com.google.common.reflect.TypeToken)} can process - * from the given list of arguments. - * - * @param methodName name of the method - * @param arguments arguments that is intended to be given - * @return a predicate that will match a compatible method - */ - public static Predicate<Method> matchMultiParameterMethod(final String methodName, final List<?> arguments) { - checkNotNull(methodName, "methodName"); - checkNotNull(arguments, "arguments"); - - return new Predicate<Method>() { - @Override - public boolean apply(@Nullable Method input) { - if (input == null) return false; - if (!input.getName().equals(methodName)) return false; - int numOptionParams = arguments.size(); - Type[] parameterTypes = input.getGenericParameterTypes(); - if (parameterTypes.length != numOptionParams) return false; - - for (int paramCount = 0; paramCount < numOptionParams; paramCount++) { - if (!TypeCoercions.tryCoerce(((List) arguments).get(paramCount), - TypeToken.of(parameterTypes[paramCount])).isPresentAndNonNull()) return false; - } - return true; - } - }; - } - - /** - * Tries to find a multiple-parameter method with each parameter compatible with (can be coerced to) the - * corresponding argument, and invokes it. - * - * @param instance the object to invoke the method on - * @param methodName the name of the method to invoke - * @param argument a list of the arguments to the method's parameters. - * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched. - */ - public static Maybe<?> tryFindAndInvokeMultiParameterMethod(final Object instance, final String methodName, final List<?> arguments) { - Class<?> clazz = instance.getClass(); - Iterable<Method> methods = Arrays.asList(clazz.getMethods()); - Optional<Method> matchingMethod = Iterables.tryFind(methods, matchMultiParameterMethod(methodName, arguments)); - if (matchingMethod.isPresent()) { - Method method = matchingMethod.get(); - try { - int numOptionParams = ((List)arguments).size(); - Object[] coercedArguments = new Object[numOptionParams]; - for (int paramCount = 0; paramCount < numOptionParams; paramCount++) { - Object argument = arguments.get(paramCount); - Type paramType = method.getGenericParameterTypes()[paramCount]; - coercedArguments[paramCount] = TypeCoercions.coerce(argument, TypeToken.of(paramType)); - } - return Maybe.of(method.invoke(instance, coercedArguments)); - } catch (IllegalAccessException | InvocationTargetException e) { - throw Exceptions.propagate(e); - } - } else { - return Maybe.absent(); - } - } - - /** - * Tries to find a method with each parameter compatible with (can be coerced to) the corresponding argument, and invokes it. - * - * @param instance the object to invoke the method on - * @param methodName the name of the method to invoke - * @param argument a list of the arguments to the method's parameters, or a single argument for a single-parameter method. - * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched. - */ - public static Maybe<?> tryFindAndInvokeBestMatchingMethod(final Object instance, final String methodName, final Object argument) { - if (argument instanceof List) { - List<?> arguments = (List<?>) argument; - - // ambiguous case: we can't tell if the user is using the multi-parameter syntax, or the single-parameter - // syntax for a method which takes a List parameter. So we try one, then fall back to the other. - - Maybe<?> maybe = tryFindAndInvokeMultiParameterMethod(instance, methodName, arguments); - if (maybe.isAbsent()) - maybe = tryFindAndInvokeSingleParameterMethod(instance, methodName, argument); - - return maybe; - } else { - return tryFindAndInvokeSingleParameterMethod(instance, methodName, argument); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a4c0e5fd/core/src/main/java/brooklyn/util/flags/SetFromFlag.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/flags/SetFromFlag.java b/core/src/main/java/brooklyn/util/flags/SetFromFlag.java deleted file mode 100644 index c7d588e..0000000 --- a/core/src/main/java/brooklyn/util/flags/SetFromFlag.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.util.flags; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Annotation to indicate that a variable may be set through the use of a named argument, - * looking for the name specified here or inferred from the annotated field/argument/object. - * <p> - * This is used to automate the processing where named arguments are passed in constructors - * and other methods, and the values of those named arguments should be transferred to - * other known fields/arguments/objects at runtime. - * <p> - * Fields on a class are typically set from values in a map with a call to - * {@link FlagUtils#setFieldsFromFlags(java.util.Map, Object)}. - * That method (and related, in the same class) will attend to the arguments here. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface SetFromFlag { - - /** the flag (key) which should be used to find the value; if empty defaults to field/argument/object name */ - String value() default ""; - - /** whether the object should not be changed once set; defaults to false - * <p> - * this is partially tested for in many routines, but not all; - * when nullable=false the testing (when done) is guaranteed. - * however if nullable is allowed we do not distinguish between null and unset - * so explicitly setting null then setting to a value is not detected as an illegal mutating. - */ - boolean immutable() default false; - - /** whether the object is required & should not be set to null; defaults to true. - * (there is no 'required' parameter, but setting nullable false then invoking - * e.g. {@link FlagUtils#checkRequiredFields(Object)} has the effect of requiring a value) - * <p> - * code should call that method explicitly to enforce nullable false; - * errors are not done during a call to setFieldsFromFlags - * because fields may be initialised in multiple passes.) - * <p> - * this is partially tested for in many routines, but not all - */ - boolean nullable() default true; - - /** The default value, if it is not explicitly set. - * <p> - * The value will be coerced from String where required, for types supported by {@link TypeCoercions}. - * <p> - * The field will be initialised with its default value on the first call to setFieldsFromFlags - * (or related). (The field will not be initialised if that method is not called.) - */ - String defaultVal() default ""; -}
