JCLOUDS-897: Remove the Rocoto dependency

This commit is contained in:
Ignasi Barrera 2015-05-01 02:50:12 +02:00
parent 68a429f366
commit 7053a7870d
10 changed files with 239 additions and 142 deletions

2
.gitignore vendored
View File

@ -17,3 +17,5 @@ TAGS
atlassian-ide-plugin.xml atlassian-ide-plugin.xml
.DS_Store .DS_Store
.java-version .java-version
.factorypath
.apt_generated

View File

@ -20,27 +20,31 @@ import static org.jclouds.reflect.Reflection2.method;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Properties;
import org.jclouds.functions.ExpandProperties;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DateAdapter; import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.openstack.swift.SwiftApiMetadata; import org.jclouds.openstack.swift.SwiftApiMetadata;
import org.jclouds.reflect.Invocation; import org.jclouds.reflect.Invocation;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.nnsoft.guice.rocoto.Rocoto;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.name.Names;
public class BasePayloadTest { public class BasePayloadTest {
protected Injector i = Guice.createInjector(Rocoto.expandVariables(new ConfigurationModule() { protected Injector i = Guice.createInjector(new AbstractModule() {
protected void bindConfigurations() { @Override
bindProperties(new SwiftApiMetadata().getDefaultProperties()); protected void configure() {
Properties expanded = new ExpandProperties().apply(new SwiftApiMetadata().getDefaultProperties());
Names.bindProperties(binder(), expanded);
bind(DateAdapter.class).to(Iso8601DateAdapter.class); bind(DateAdapter.class).to(Iso8601DateAdapter.class);
} }
}), new GsonModule()); }, new GsonModule());
protected GeneratedHttpRequest requestForArgs(List<Object> args) { protected GeneratedHttpRequest requestForArgs(List<Object> args) {
try { try {

View File

@ -38,10 +38,7 @@
</scm> </scm>
<properties> <properties>
<jclouds.osgi.import> <jclouds.osgi.import>*</jclouds.osgi.import>
org.nnsoft.guice.rocoto*;version="[6.1,7)",
*
</jclouds.osgi.import>
<jclouds.osgi.export>org.jclouds*;version=${project.version};-noimport:=true</jclouds.osgi.export> <jclouds.osgi.export>org.jclouds*;version=${project.version};-noimport:=true</jclouds.osgi.export>
<jclouds.osgi.activator>org.jclouds.osgi.Activator</jclouds.osgi.activator> <jclouds.osgi.activator>org.jclouds.osgi.Activator</jclouds.osgi.activator>
</properties> </properties>
@ -60,11 +57,6 @@
<groupId>com.google.inject</groupId> <groupId>com.google.inject</groupId>
<artifactId>guice</artifactId> <artifactId>guice</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.99soft.guice</groupId>
<artifactId>rocoto</artifactId>
<version>6.2</version>
</dependency>
<dependency> <dependency>
<groupId>javax.inject</groupId> <groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId> <artifactId>javax.inject</artifactId>

View File

@ -58,10 +58,10 @@ import org.jclouds.concurrent.config.ConfiguresExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.config.BindApiContextWithWildcardExtendsExplicitAndRawType; import org.jclouds.config.BindApiContextWithWildcardExtendsExplicitAndRawType;
import org.jclouds.config.BindNameToContext; import org.jclouds.config.BindNameToContext;
import org.jclouds.config.BindPropertiesToExpandedValues;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.events.config.ConfiguresEventBus; import org.jclouds.events.config.ConfiguresEventBus;
import org.jclouds.events.config.EventBusModule; import org.jclouds.events.config.EventBusModule;
import org.jclouds.functions.ExpandProperties;
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService; import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
@ -314,7 +314,7 @@ public class ContextBuilder {
Properties resolved = resolveProperties(unexpanded, providerId, keysToResolve, optionalKeys); Properties resolved = resolveProperties(unexpanded, providerId, keysToResolve, optionalKeys);
Properties expanded = expandProperties(resolved); Properties expanded = new ExpandProperties().apply(resolved);
Supplier<Credentials> credentialsSupplier = buildCredentialsSupplier(expanded); Supplier<Credentials> credentialsSupplier = buildCredentialsSupplier(expanded);
@ -351,10 +351,10 @@ public class ContextBuilder {
private Properties currentStateToUnexpandedProperties() { private Properties currentStateToUnexpandedProperties() {
Properties defaults = new Properties(); Properties defaults = new Properties();
defaults.putAll(apiMetadata.getDefaultProperties()); putAllAsString(apiMetadata.getDefaultProperties(), defaults);
defaults.setProperty(PROPERTY_PROVIDER, providerId); defaults.setProperty(PROPERTY_PROVIDER, providerId);
if (providerMetadata.isPresent()) { if (providerMetadata.isPresent()) {
defaults.putAll(providerMetadata.get().getDefaultProperties()); putAllAsString(providerMetadata.get().getDefaultProperties(), defaults);
defaults.setProperty(PROPERTY_ISO3166_CODES, Joiner.on(',').join(providerMetadata.get().getIso3166Codes())); defaults.setProperty(PROPERTY_ISO3166_CODES, Joiner.on(',').join(providerMetadata.get().getIso3166Codes()));
} }
if (endpoint.isPresent()) if (endpoint.isPresent())
@ -367,21 +367,22 @@ public class ContextBuilder {
if (credential != null) if (credential != null)
defaults.setProperty(PROPERTY_CREDENTIAL, credential); defaults.setProperty(PROPERTY_CREDENTIAL, credential);
if (overrides.isPresent()) if (overrides.isPresent())
defaults.putAll(checkNotNull(overrides.get(), "overrides")); putAllAsString(overrides.get(), defaults);
defaults.putAll(propertiesPrefixedWithJcloudsApiOrProviderId(getSystemProperties(), apiMetadata.getId(), providerId)); putAllAsString(propertiesPrefixedWithJcloudsApiOrProviderId(getSystemProperties(), apiMetadata.getId(), providerId), defaults);
return defaults; return defaults;
} }
private static void putAllAsString(Map<?, ?> source, Properties target) {
for (Map.Entry<?, ?> entry : source.entrySet()) {
target.setProperty(entry.getKey().toString(), entry.getValue().toString());
}
}
@VisibleForTesting @VisibleForTesting
protected Properties getSystemProperties() { protected Properties getSystemProperties() {
return System.getProperties(); return System.getProperties();
} }
private Properties expandProperties(final Properties resolved) {
return Guice.createInjector(GUICE_STAGE, new BindPropertiesToExpandedValues(resolved)).getInstance(Properties.class);
}
public static Injector buildInjector(String name, ProviderMetadata providerMetadata, Supplier<Credentials> creds, List<Module> inputModules) { public static Injector buildInjector(String name, ProviderMetadata providerMetadata, Supplier<Credentials> creds, List<Module> inputModules) {
List<Module> modules = newArrayList(); List<Module> modules = newArrayList();
modules.addAll(inputModules); modules.addAll(inputModules);

View File

@ -1,62 +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 org.jclouds.config;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Properties;
import javax.inject.Singleton;
import org.jclouds.internal.FilterStringsBoundToInjectorByName;
import org.nnsoft.guice.rocoto.Rocoto;
import org.nnsoft.guice.rocoto.configuration.ConfigurationModule;
import com.google.common.base.Predicates;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* expands properties.
*/
public class BindPropertiesToExpandedValues extends AbstractModule {
private final Properties resolved;
public BindPropertiesToExpandedValues(Properties resolved) {
this.resolved = checkNotNull(resolved, "resolved");
}
@Override
protected void configure() {
install(Rocoto.expandVariables(new ConfigurationModule() {
@Override
protected void bindConfigurations() {
bindProperties(resolved);
}
@Provides
@Singleton
protected Properties expanded(FilterStringsBoundToInjectorByName filterStringsBoundByName) {
Properties props = new Properties();
props.putAll(filterStringsBoundByName.apply(Predicates.<String> alwaysTrue()));
return props;
}
}));
}
}

View File

@ -0,0 +1,110 @@
/*
* 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 org.jclouds.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
/**
* Resolves the values of the properties so they can be inferred from other
* properties.
*/
public class ExpandProperties implements Function<Properties, Properties> {
// Matches variables in a string such as ${foo.bar}
private static final Pattern VAR = Pattern.compile("\\$\\{[^\\}]+}");
@Override
public Properties apply(final Properties properties) {
checkNotNull(properties, "properties cannot be null");
// Only expand the properties that are Strings
Map<String, String> stringProperties = Maps.toMap(properties.stringPropertyNames(),
new Function<String, String>() {
@Override
public String apply(String input) {
return properties.getProperty(input);
}
});
boolean pendingReplacements = true;
Map<String, String> propertiesToResolve = new HashMap<String, String>(stringProperties);
while (pendingReplacements) {
Map<String, String> leafs = leafs(propertiesToResolve);
if (leafs.isEmpty()) {
break;
}
pendingReplacements = resolveProperties(propertiesToResolve, leafs);
}
// Replace the values with the resolved ones
Properties resolved = new Properties();
resolved.putAll(properties);
for (Map.Entry<String, String> entry : propertiesToResolve.entrySet()) {
resolved.setProperty(entry.getKey(), entry.getValue());
}
return resolved;
}
private Map<String, String> leafs(Map<String, String> input) {
return Maps.filterValues(input, new Predicate<String>() {
@Override
public boolean apply(String input) {
Matcher m = VAR.matcher(input);
return !m.find();
}
});
}
private boolean resolveProperties(Map<String, String> properties, Map<String, String> variables) {
boolean anyReplacementDone = false;
for (String key : properties.keySet()) {
StringBuffer sb = new StringBuffer();
Matcher m = VAR.matcher(properties.get(key));
while (m.find()) {
String match = m.group();
// Remove the ${} from the matched variable
String var = match.substring(2, match.length() - 1);
// Avoid recursive properties. Only get he value if the variable
// is different than the current key
Optional<String> value = var.equals(key) ? Optional.<String> absent() : Optional.fromNullable(variables
.get(var));
// Replace by the value or leave the original value
m.appendReplacement(sb, value.or("\\" + match));
if (value.isPresent()) {
anyReplacementDone = true;
}
}
m.appendTail(sb);
properties.put(key, sb.toString());
}
return anyReplacementDone;
}
}

View File

@ -130,6 +130,27 @@ public class ContextBuilderTest {
assertEquals(version, "1.1"); assertEquals(version, "1.1");
} }
@Test
public void testAllPropertiesAreStrings() {
Properties overrides = new Properties();
overrides.setProperty("foo", "bar");
overrides.put("one", 1);
overrides.put("two", 2.0f);
overrides.put("true", true);
overrides.put("object", new Object() {
@Override
public String toString() {
return "object";
}
});
Context withObjectsInProps = testContextBuilder().overrides(overrides).build();
Properties resolved = withObjectsInProps.getProviderMetadata().getDefaultProperties();
assertEquals(resolved.getProperty("foo"), "bar");
assertEquals(resolved.getProperty("one"), "1");
assertEquals(resolved.getProperty("true"), "true");
assertEquals(resolved.getProperty("object"), "object");
}
@Test @Test
public void testAddHttpModuleIfNotPresent() { public void testAddHttpModuleIfNotPresent() {
List<Module> modules = Lists.newArrayList(); List<Module> modules = Lists.newArrayList();

View File

@ -27,7 +27,7 @@ import com.google.auto.service.AutoService;
* Implementation of {@link ApiMetadata} for testing. * Implementation of {@link ApiMetadata} for testing.
*/ */
@AutoService(ApiMetadata.class) @AutoService(ApiMetadata.class)
public class JcloudsTestBlobStoreApiMetadata extends BaseHttpApiMetadata { public class JcloudsTestBlobStoreApiMetadata extends BaseHttpApiMetadata<IntegrationTestClient> {
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();

View File

@ -1,45 +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 org.jclouds.config;
import static org.testng.Assert.assertEquals;
import java.util.Properties;
import org.testng.annotations.Test;
import com.google.inject.Guice;
/**
* Tests behavior of BindPropertiesToExpandedValues
*/
@Test(groups = "unit", testName = "BindPropertiesToExpandedValuesTest")
public class BindPropertiesToExpandedValuesTest {
@Test
public void testExpand() {
Properties input = new Properties();
input.setProperty("id", "1234");
input.setProperty("path", "path:${id}");
Properties output = Guice.createInjector(new BindPropertiesToExpandedValues(input)).getInstance(Properties.class);
Properties expected = new Properties();
expected.setProperty("id", "1234");
expected.setProperty("path", "path:1234");
assertEquals(output, expected);
}
}

View File

@ -0,0 +1,74 @@
/*
* 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 org.jclouds.functions;
import static org.testng.Assert.assertEquals;
import java.util.Properties;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "ExpandPropertiesTest")
public class ExpandPropertiesTest {
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "properties cannot be null")
public void testPropertiesMandatory() {
new ExpandProperties().apply(null);
}
@Test
public void testResolveProperties() {
Properties props = new Properties();
props.put("number", 1);
props.put("two", "2");
props.put("greeting", "hello");
props.put("simple", "simple: ${greeting}");
props.put("nested", "nested: ${simple}");
props.put("mixed", "mixed: ${nested} and ${simple}");
props.put("unexisting", "${foobar} substitution");
props.put("recursive", "variable5 ${recursive} recursive ${unexisting}");
props.put("characters{{$$", "characters");
props.put("ugly", "substitute: ${characters{{$$}");
Properties resolved = new ExpandProperties().apply(props);
assertEquals(resolved.size(), props.size());
assertEquals(resolved.get("number"), 1);
assertEquals(resolved.get("two"), "2");
assertEquals(resolved.get("greeting"), "hello");
assertEquals(resolved.get("simple"), "simple: hello");
assertEquals(resolved.get("nested"), "nested: simple: hello");
assertEquals(resolved.get("mixed"), "mixed: nested: simple: hello and simple: hello");
assertEquals(resolved.get("unexisting"), "${foobar} substitution");
assertEquals(resolved.get("recursive"), "variable5 ${recursive} recursive ${unexisting}");
assertEquals(resolved.get("ugly"), "substitute: characters");
}
@Test
public void testNoLeafs() {
Properties props = new Properties();
props.put("one", "${two}");
props.put("two", "${one}");
Properties resolved = new ExpandProperties().apply(props);
assertEquals(resolved.size(), props.size());
assertEquals(resolved.get("one"), "${two}");
assertEquals(resolved.get("two"), "${one}");
}
}