mirror of https://github.com/apache/jclouds.git
Issue 191: refactored ohai automatic update approach
This commit is contained in:
parent
ef86f2da1b
commit
e6d4a087cb
|
@ -0,0 +1,124 @@
|
|||
package org.jclouds.chef;
|
||||
|
||||
import static org.jclouds.rest.RestContextFactory.createContextBuilder;
|
||||
import static org.jclouds.util.Utils.propagateAuthorizationOrOriginalException;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jclouds.rest.RestContextBuilder;
|
||||
import org.jclouds.rest.RestContextFactory;
|
||||
import org.jclouds.rest.RestContextFactory.ContextSpec;
|
||||
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
* Helper class to instantiate {@code ChefContext} instances.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ChefContextFactory {
|
||||
|
||||
private final RestContextFactory contextFactory;
|
||||
|
||||
/**
|
||||
* Initializes with the default properties built-in to jclouds. This is
|
||||
* typically stored in the classpath resource {@code rest.properties}
|
||||
*
|
||||
* @see RestContextFactory#getPropertiesFromResource
|
||||
*/
|
||||
public ChefContextFactory() {
|
||||
this(new RestContextFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds definitions in the specified properties.
|
||||
*/
|
||||
public ChefContextFactory(Properties properties) {
|
||||
this(new RestContextFactory(properties));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Uses the supplied RestContextFactory to create {@link ChefContext}s
|
||||
*/
|
||||
public ChefContextFactory(RestContextFactory restContextFactory) {
|
||||
this.contextFactory = restContextFactory;
|
||||
}
|
||||
|
||||
public static <S, A> ChefContext buildContextUnwrappingExceptions(RestContextBuilder<S, A> builder) {
|
||||
try {
|
||||
return (ChefContext) builder.buildContext();
|
||||
} catch (Exception e) {
|
||||
return propagateAuthorizationOrOriginalException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RestContextFactory#createContextBuilder(String, String)
|
||||
*/
|
||||
public ChefContext createContext(String identity, String credential) {
|
||||
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
|
||||
identity, credential));
|
||||
return buildContextUnwrappingExceptions(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RestContextFactory#createContextBuilder(Properties)
|
||||
*/
|
||||
public ChefContext createContext(Properties overrides) {
|
||||
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
|
||||
overrides));
|
||||
return buildContextUnwrappingExceptions(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RestContextFactory#createContextBuilder(Iterable)
|
||||
*/
|
||||
public ChefContext createContext(Iterable<? extends Module> modules, Properties overrides) {
|
||||
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
|
||||
modules, overrides));
|
||||
return buildContextUnwrappingExceptions(builder);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RestContextFactory#createContextBuilder(String,String, Iterable)
|
||||
*/
|
||||
public ChefContext createContext(@Nullable String identity, @Nullable String credential,
|
||||
Iterable<? extends Module> modules) {
|
||||
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
|
||||
identity, credential, modules));
|
||||
return buildContextUnwrappingExceptions(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RestContextFactory#createContextBuilder(String,String, Iterable,
|
||||
* Properties)
|
||||
*/
|
||||
public ChefContext createContext(@Nullable String identity, @Nullable String credential,
|
||||
Iterable<? extends Module> modules, Properties overrides) {
|
||||
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(contextFactory.createContextBuilder("chef",
|
||||
identity, credential, modules, overrides));
|
||||
return buildContextUnwrappingExceptions(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RestContextFactory#createContextBuilder(ContextSpec)
|
||||
*/
|
||||
public <S, A> ChefContext createContext(ContextSpec<S, A> contextSpec) {
|
||||
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(createContextBuilder(contextSpec));
|
||||
return buildContextUnwrappingExceptions(builder);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RestContextFactory#createContextBuilder(ContextSpec, Properties)
|
||||
*/
|
||||
public <S, A> ChefContext createContext(ContextSpec<S, A> contextSpec, Properties overrides) {
|
||||
RestContextBuilder<?, ?> builder = RestContextBuilder.class.cast(createContextBuilder(contextSpec, overrides));
|
||||
return buildContextUnwrappingExceptions(builder);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
package org.jclouds.chef;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.jclouds.chef.domain.Node;
|
||||
import org.jclouds.chef.internal.BaseChefService;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.io.InputSupplier;
|
||||
import com.google.inject.ImplementedBy;
|
||||
|
||||
/**
|
||||
|
@ -18,6 +22,10 @@ public interface ChefService {
|
|||
*/
|
||||
ChefContext getContext();
|
||||
|
||||
byte[] encrypt(InputSupplier<? extends InputStream> supplier) throws IOException;
|
||||
|
||||
byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException;
|
||||
|
||||
void cleanupStaleNodesAndClients(String prefix, int secondsStale);
|
||||
|
||||
void createNodeAndPopulateAutomaticAttributes(String nodeName, Iterable<String> runList);
|
||||
|
|
|
@ -64,7 +64,7 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
|
|||
}
|
||||
|
||||
protected BaseChefRestClientModule(Class<S> syncClientType, Class<A> asyncClientType,
|
||||
Map<Class<?>, Class<?>> delegates) {
|
||||
Map<Class<?>, Class<?>> delegates) {
|
||||
super(syncClientType, asyncClientType, delegates);
|
||||
}
|
||||
|
||||
|
@ -90,10 +90,10 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
|
|||
@Provides
|
||||
@Singleton
|
||||
public PrivateKey provideKey(Crypto crypto, @Named(PROPERTY_CREDENTIAL) String pem) throws InvalidKeySpecException,
|
||||
IOException {
|
||||
IOException {
|
||||
return crypto.rsaKeyFactory().generatePrivate(Pems.privateKeySpec(InputSuppliers.of(pem)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void bindErrorHandlers() {
|
||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ChefErrorHandler.class);
|
||||
|
|
|
@ -41,11 +41,23 @@
|
|||
*/
|
||||
package org.jclouds.chef.config;
|
||||
|
||||
import static org.jclouds.Constants.PROPERTY_IDENTITY;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.chef.ChefAsyncClient;
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.crypto.Crypto;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.rest.ConfiguresRestClient;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* Configures the Chef connection.
|
||||
*
|
||||
|
|
|
@ -105,7 +105,7 @@ public class CookbookVersion {
|
|||
return metadata;
|
||||
}
|
||||
|
||||
public Set<Resource> getProviders() {
|
||||
public Set<Resource> getSuppliers() {
|
||||
return providers;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,14 @@ package org.jclouds.chef.internal;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.chef.ChefContext;
|
||||
|
@ -16,9 +21,14 @@ import org.jclouds.chef.strategy.CreateNodeAndPopulateAutomaticAttributes;
|
|||
import org.jclouds.chef.strategy.DeleteAllNodesInList;
|
||||
import org.jclouds.chef.strategy.GetNodes;
|
||||
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
|
||||
import org.jclouds.io.Payloads;
|
||||
import org.jclouds.io.payloads.RSADecryptingPayload;
|
||||
import org.jclouds.io.payloads.RSAEncryptingPayload;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.InputSupplier;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -37,12 +47,13 @@ public class BaseChefService implements ChefService {
|
|||
private final DeleteAllNodesInList deleteAllNodesInList;
|
||||
private final GetNodes getNodes;
|
||||
private final UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode;
|
||||
private final Provider<PrivateKey> privateKey;
|
||||
|
||||
@Inject
|
||||
protected BaseChefService(ChefContext chefContext, CleanupStaleNodesAndClients cleanupStaleNodesAndClients,
|
||||
CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes,
|
||||
DeleteAllNodesInList deleteAllNodesInList, GetNodes getNodes,
|
||||
UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode) {
|
||||
UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode, Provider<PrivateKey> privateKey) {
|
||||
this.chefContext = checkNotNull(chefContext, "chefContext");
|
||||
this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients");
|
||||
this.createNodeAndPopulateAutomaticAttributes = checkNotNull(createNodeAndPopulateAutomaticAttributes,
|
||||
|
@ -51,6 +62,7 @@ public class BaseChefService implements ChefService {
|
|||
this.getNodes = checkNotNull(getNodes, "getNodes");
|
||||
this.updateAutomaticAttributesOnNode = checkNotNull(updateAutomaticAttributesOnNode,
|
||||
"updateAutomaticAttributesOnNode");
|
||||
this.privateKey = checkNotNull(privateKey, "privateKey");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,4 +105,16 @@ public class BaseChefService implements ChefService {
|
|||
return chefContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
|
||||
return ByteStreams.toByteArray(new RSADecryptingPayload(Payloads.newPayload(supplier.getInput()), privateKey
|
||||
.get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
|
||||
return ByteStreams.toByteArray(new RSAEncryptingPayload(Payloads.newPayload(supplier.getInput()), privateKey
|
||||
.get()));
|
||||
}
|
||||
|
||||
}
|
|
@ -33,6 +33,7 @@ import org.jclouds.chef.reference.ChefConstants;
|
|||
import org.jclouds.chef.strategy.CreateNodeAndPopulateAutomaticAttributes;
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.ohai.Automatic;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
|
@ -54,7 +55,7 @@ public class CreateNodeAndPopulateAutomaticAttributesImpl implements CreateNodeA
|
|||
|
||||
@Inject
|
||||
public CreateNodeAndPopulateAutomaticAttributesImpl(ChefClient chef,
|
||||
@Named("automatic") Supplier<Map<String, JsonBall>> automaticSupplier) {
|
||||
@Automatic Supplier<Map<String, JsonBall>> automaticSupplier) {
|
||||
this.chef = checkNotNull(chef, "chef");
|
||||
this.automaticSupplier = checkNotNull(automaticSupplier, "automaticSupplier");
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.jclouds.chef.reference.ChefConstants;
|
|||
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.ohai.Automatic;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
|
@ -54,7 +55,7 @@ public class UpdateAutomaticAttributesOnNodeImpl implements UpdateAutomaticAttri
|
|||
|
||||
@Inject
|
||||
public UpdateAutomaticAttributesOnNodeImpl(ChefClient chef,
|
||||
@Named("automatic") Supplier<Map<String, JsonBall>> automaticSupplier) {
|
||||
@Automatic Supplier<Map<String, JsonBall>> automaticSupplier) {
|
||||
this.chef = checkNotNull(chef, "chef");
|
||||
this.automaticSupplier = checkNotNull(automaticSupplier, "automaticSupplier");
|
||||
}
|
||||
|
|
|
@ -16,25 +16,24 @@
|
|||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.config;
|
||||
package org.jclouds.ohai;
|
||||
|
||||
import java.util.Properties;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import javax.inject.Named;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
/**
|
||||
* Wires the components needed to parse ohai data from a JVM
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BaseOhaiJVMModule extends BaseOhaiModule {
|
||||
|
||||
@Named("systemProperties")
|
||||
@Provides
|
||||
protected Properties systemProperties() {
|
||||
return System.getProperties();
|
||||
}
|
||||
|
||||
}
|
||||
@Retention(RUNTIME)
|
||||
@Target( { TYPE, METHOD, PARAMETER })
|
||||
@Qualifier
|
||||
public @interface Automatic {
|
||||
}
|
|
@ -16,47 +16,40 @@
|
|||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.plugins;
|
||||
package org.jclouds.ohai;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.ohai.functions.NestSlashKeys;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
*
|
||||
* Gathers Ohai data from the JVM.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class JMX implements Supplier<Map<String, JsonBall>> {
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
private final Provider<RuntimeMXBean> runtimeSupplier;
|
||||
public class AutomaticSupplier implements Supplier<Map<String, JsonBall>> {
|
||||
private final Multimap<String,Supplier<JsonBall>> autoAttrs;
|
||||
private final NestSlashKeys nester;
|
||||
|
||||
@Inject
|
||||
public JMX(Provider<RuntimeMXBean> runtimeSupplier) {
|
||||
this.runtimeSupplier = checkNotNull(runtimeSupplier, "runtimeSupplier");
|
||||
AutomaticSupplier(@Automatic Multimap<String,Supplier<JsonBall>> autoAttrs, NestSlashKeys nester) {
|
||||
this.autoAttrs = checkNotNull(autoAttrs, "autoAttrs");
|
||||
this.nester = checkNotNull(nester, "nester");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, JsonBall> get() {
|
||||
RuntimeMXBean runtime = runtimeSupplier.get();
|
||||
Map<String, JsonBall> automatic = Maps.newLinkedHashMap();
|
||||
long uptimeInSeconds = runtime.getUptime() / 1000;
|
||||
automatic.put("uptime_seconds", new JsonBall(uptimeInSeconds));
|
||||
return automatic;
|
||||
return nester.apply(autoAttrs);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@ import java.util.Properties;
|
|||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.ohai.config.ConfiguresOhai;
|
||||
import org.jclouds.ohai.config.JMXOhaiJVMModule;
|
||||
import org.jclouds.ohai.config.JMXOhaiModule;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.rest.RestContextBuilder;
|
||||
|
||||
|
@ -54,7 +54,7 @@ public class OhaiContextBuilder<S, A> extends RestContextBuilder<S, A> {
|
|||
}
|
||||
|
||||
protected void addOhaiModule() {
|
||||
modules.add(new JMXOhaiJVMModule());
|
||||
modules.add(new JMXOhaiModule());
|
||||
}
|
||||
|
||||
}
|
|
@ -23,6 +23,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import java.util.Date;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.ohai.Automatic;
|
||||
import org.jclouds.ohai.config.multibindings.MapBinder;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -35,11 +41,14 @@ public class OhaiUtils {
|
|||
return new Date(Long.parseLong(checkNotNull(ohaiDate, "ohaiDate").toString().replaceAll("\\.[0-9]*$", "")));
|
||||
}
|
||||
|
||||
public static JsonBall toOhaiTime(long nanos) {
|
||||
String now = nanos + "";
|
||||
StringBuilder nowBuilder = new StringBuilder(now).insert(now.length() - 6, '.');
|
||||
while (nowBuilder.lastIndexOf("0") != -1 && nowBuilder.lastIndexOf("0") == nowBuilder.length() - 1)
|
||||
nowBuilder.deleteCharAt(nowBuilder.length() - 1);
|
||||
return new JsonBall(nowBuilder.toString());
|
||||
public static JsonBall toOhaiTime(long millis) {
|
||||
return new JsonBall(millis + "");
|
||||
}
|
||||
|
||||
public static MapBinder<String, Supplier<JsonBall>> ohaiAutomaticAttributeBinder(Binder binder) {
|
||||
MapBinder<String, Supplier<JsonBall>> mapbinder = MapBinder.newMapBinder(binder, new TypeLiteral<String>() {
|
||||
}, new TypeLiteral<Supplier<JsonBall>>() {
|
||||
}, Automatic.class);
|
||||
return mapbinder;
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.config;
|
||||
|
||||
import static org.jclouds.util.Utils.composeMapSupplier;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.ohai.functions.ByteArrayToMacAddress;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Wires the components needed to parse ohai data
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BaseOhaiModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(new TypeLiteral<Function<byte[], String>>() {
|
||||
}).to(new TypeLiteral<ByteArrayToMacAddress>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Named("nanoTime")
|
||||
@Provides
|
||||
protected Long nanoTime() {
|
||||
return System.nanoTime();
|
||||
}
|
||||
|
||||
@Named("automatic")
|
||||
@Provides
|
||||
@Singleton
|
||||
Supplier<Map<String, JsonBall>> automaticSupplier(
|
||||
@Named("automatic") Iterable<Supplier<Map<String, JsonBall>>> suppliers) {
|
||||
return composeMapSupplier(suppliers);
|
||||
}
|
||||
|
||||
@Named("automatic")
|
||||
@Singleton
|
||||
@Provides
|
||||
protected abstract Iterable<Supplier<Map<String, JsonBall>>> suppliers(Injector injector);
|
||||
|
||||
}
|
|
@ -20,17 +20,14 @@ package org.jclouds.ohai.config;
|
|||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.ohai.plugins.JMX;
|
||||
import org.jclouds.ohai.plugins.WhiteListCompliantJVM;
|
||||
import org.jclouds.ohai.config.multibindings.MapBinder;
|
||||
import org.jclouds.ohai.suppliers.UptimeSecondsSupplier;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
|
@ -39,7 +36,7 @@ import com.google.inject.Provides;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresOhai
|
||||
public class JMXOhaiJVMModule extends BaseOhaiJVMModule {
|
||||
public class JMXOhaiModule extends OhaiModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
@ -47,9 +44,9 @@ public class JMXOhaiJVMModule extends BaseOhaiJVMModule {
|
|||
return ManagementFactory.getRuntimeMXBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Supplier<Map<String, JsonBall>>> suppliers(Injector injector) {
|
||||
return ImmutableList.<Supplier<Map<String, JsonBall>>> of(injector.getInstance(WhiteListCompliantJVM.class),
|
||||
injector.getInstance(JMX.class));
|
||||
public MapBinder<String, Supplier<JsonBall>> bindOhai() {
|
||||
MapBinder<String, Supplier<JsonBall>> mapBinder = super.bindOhai();
|
||||
mapBinder.addBinding("uptime_seconds").to(UptimeSecondsSupplier.class);
|
||||
return mapBinder;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.config;
|
||||
|
||||
import static org.jclouds.ohai.Util.OhaiUtils.ohaiAutomaticAttributeBinder;
|
||||
import static org.jclouds.ohai.Util.OhaiUtils.toOhaiTime;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.ohai.Automatic;
|
||||
import org.jclouds.ohai.AutomaticSupplier;
|
||||
import org.jclouds.ohai.config.multibindings.MapBinder;
|
||||
import org.jclouds.ohai.functions.ByteArrayToMacAddress;
|
||||
import org.jclouds.ohai.functions.MapSetToMultimap;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Wires the components needed to parse ohai data
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresOhai
|
||||
public class OhaiModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(new TypeLiteral<Function<byte[], String>>() {
|
||||
}).to(new TypeLiteral<ByteArrayToMacAddress>() {
|
||||
});
|
||||
bindOhai();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Automatic
|
||||
protected Supplier<Map<String, JsonBall>> provideAutomatic(AutomaticSupplier in) {
|
||||
return in;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Automatic
|
||||
Multimap<String, Supplier<JsonBall>> provideAutomatic(MapSetToMultimap<String, Supplier<JsonBall>> converter,
|
||||
@Automatic Map<String, Set<Supplier<JsonBall>>> input) {
|
||||
return converter.apply(input);
|
||||
|
||||
}
|
||||
|
||||
@Named("systemProperties")
|
||||
@Provides
|
||||
protected Properties systemProperties() {
|
||||
return System.getProperties();
|
||||
}
|
||||
|
||||
public MapBinder<String, Supplier<JsonBall>> bindOhai() {
|
||||
MapBinder<String, Supplier<JsonBall>> mapbinder = ohaiAutomaticAttributeBinder(binder()).permitDuplicates();
|
||||
mapbinder.addBinding("ohai_time").to(OhaiTimeProvider.class);
|
||||
mapbinder.addBinding("jvm/system").to(SystemPropertiesProvider.class);
|
||||
mapbinder.addBinding("platform").to(PlatformProvider.class);
|
||||
mapbinder.addBinding("platform_version").to(PlatformVersionProvider.class);
|
||||
mapbinder.addBinding("current_user").to(CurrentUserProvider.class);
|
||||
return mapbinder;
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class OhaiTimeProvider implements Supplier<JsonBall> {
|
||||
private final Provider<Long> timeProvider;
|
||||
|
||||
@Inject
|
||||
OhaiTimeProvider(Provider<Long> timeProvider) {
|
||||
this.timeProvider = timeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonBall get() {
|
||||
return toOhaiTime(timeProvider.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Provides
|
||||
protected Long millis() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class SystemPropertiesProvider implements Supplier<JsonBall> {
|
||||
|
||||
private final Json json;
|
||||
private final Properties systemProperties;
|
||||
|
||||
@Inject
|
||||
SystemPropertiesProvider(Json json, @Named("systemProperties") Properties systemProperties) {
|
||||
this.json = json;
|
||||
this.systemProperties = systemProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonBall get() {
|
||||
return new JsonBall(json.toJson(systemProperties));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class PlatformProvider extends SystemPropertyProvider {
|
||||
|
||||
@Inject
|
||||
PlatformProvider(@Named("systemProperties") Properties systemProperties) {
|
||||
super("os.name", systemProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonBall get() {
|
||||
JsonBall returnValue = super.get();
|
||||
return returnValue != null ? new JsonBall(returnValue.toString().replaceAll("[ -]", "").toLowerCase()) : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class PlatformVersionProvider extends SystemPropertyProvider {
|
||||
|
||||
@Inject
|
||||
PlatformVersionProvider(@Named("systemProperties") Properties systemProperties) {
|
||||
super("os.version", systemProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class CurrentUserProvider extends SystemPropertyProvider {
|
||||
|
||||
@Inject
|
||||
CurrentUserProvider(@Named("systemProperties") Properties systemProperties) {
|
||||
super("user.name", systemProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SystemPropertyProvider implements Supplier<JsonBall> {
|
||||
private final Properties systemProperties;
|
||||
private final String property;
|
||||
|
||||
@Inject
|
||||
SystemPropertyProvider(String property, @Named("systemProperties") Properties systemProperties) {
|
||||
this.property = property;
|
||||
this.systemProperties = systemProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonBall get() {
|
||||
return systemProperties.containsKey(property) ? new JsonBall(systemProperties.getProperty(property)) : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.jclouds.ohai.config.multibindings;
|
||||
|
||||
import com.google.inject.BindingAnnotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* An internal binding annotation applied to each element in a multibinding.
|
||||
* All elements are assigned a globally-unique id to allow different modules
|
||||
* to contribute multibindings independently.
|
||||
*
|
||||
* @author jessewilson@google.com (Jesse Wilson)
|
||||
*/
|
||||
@Retention(RUNTIME) @BindingAnnotation
|
||||
@interface Element {
|
||||
String setName();
|
||||
int uniqueId();
|
||||
}
|
|
@ -0,0 +1,518 @@
|
|||
package org.jclouds.ohai.config.multibindings;
|
||||
|
||||
import static com.google.inject.util.Types.newParameterizedTypeWithOwner;
|
||||
import static org.jclouds.ohai.config.multibindings.Multibinder.checkConfiguration;
|
||||
import static org.jclouds.ohai.config.multibindings.Multibinder.checkNotNull;
|
||||
import static org.jclouds.ohai.config.multibindings.Multibinder.setOf;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.jclouds.ohai.config.multibindings.Multibinder.RealMultibinder;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.binder.LinkedBindingBuilder;
|
||||
import com.google.inject.spi.Dependency;
|
||||
import com.google.inject.spi.ProviderWithDependencies;
|
||||
import com.google.inject.util.Types;
|
||||
|
||||
/**
|
||||
* An API to bind multiple map entries separately, only to later inject them as
|
||||
* a complete map. MapBinder is intended for use in your application's module:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* public class SnacksModule extends AbstractModule {
|
||||
* protected void configure() {
|
||||
* MapBinder<String, Snack> mapbinder
|
||||
* = MapBinder.newMapBinder(binder(), String.class, Snack.class);
|
||||
* mapbinder.addBinding("twix").toInstance(new Twix());
|
||||
* mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
|
||||
* mapbinder.addBinding("skittles").to(Skittles.class);
|
||||
* }
|
||||
* }</code>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* With this binding, a {@link Map}{@code <String, Snack>} can now be injected:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* class SnackMachine {
|
||||
* {@literal @}Inject
|
||||
* public SnackMachine(Map<String, Snack> snacks) { ... }
|
||||
* }</code>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* In addition to binding {@code Map<K, V>}, a mapbinder will also bind {@code
|
||||
* Map<K, Provider<V>>} for lazy value provision:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* class SnackMachine {
|
||||
* {@literal @}Inject
|
||||
* public SnackMachine(Map<String, Provider<Snack>> snackSuppliers) { ... }
|
||||
* }</code>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Contributing mapbindings from different modules is supported. For example, it
|
||||
* is okay to have both {@code CandyModule} and {@code ChipsModule} both create
|
||||
* their own {@code MapBinder<String, Snack>}, and to each contribute bindings
|
||||
* to the snacks map. When that map is injected, it will contain entries from
|
||||
* both modules.
|
||||
*
|
||||
* <p>
|
||||
* The map's iteration order is consistent with the binding order. This is
|
||||
* convenient when multiple elements are contributed by the same module because
|
||||
* that module can order its bindings appropriately. Avoid relying on the
|
||||
* iteration order of elements contributed by different modules, since there is
|
||||
* no equivalent mechanism to order modules.
|
||||
*
|
||||
* <p>
|
||||
* Values are resolved at map injection time. If a value is bound to a provider,
|
||||
* that provider's get method will be called each time the map is injected
|
||||
* (unless the binding is also scoped, or a map of providers is injected).
|
||||
*
|
||||
* <p>
|
||||
* Annotations are used to create different maps of the same key/value type.
|
||||
* Each distinct annotation gets its own independent map.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Keys must be distinct.</strong> If the same key is bound more than
|
||||
* once, map injection will fail. However, use {@link #permitDuplicates()} in
|
||||
* order to allow duplicate keys; extra bindings to {@code Map<K, Set<V>>} and
|
||||
* {@code Map<K, Set<Provider<V>>} will be added.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Keys must be non-null.</strong> {@code addBinding(null)} will throw
|
||||
* an unchecked exception.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Values must be non-null to use map injection.</strong> If any value
|
||||
* is null, map injection will fail (although injecting a map of providers will
|
||||
* not).
|
||||
*
|
||||
* @author dpb@google.com (David P. Baker)
|
||||
*/
|
||||
public abstract class MapBinder<K, V> {
|
||||
private MapBinder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
|
||||
* valueType} in a {@link Map} that is itself bound with no binding
|
||||
* annotation.
|
||||
*/
|
||||
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
|
||||
binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
|
||||
return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType)), Key.get(mapOfProviderOf(keyType,
|
||||
valueType)), Key.get(mapOf(keyType, setOf(valueType))), Key.get(mapOfSetOfProviderOf(keyType, valueType)),
|
||||
Multibinder.newSetBinder(binder, entryOfProviderOf(keyType, valueType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
|
||||
* valueType} in a {@link Map} that is itself bound with no binding
|
||||
* annotation.
|
||||
*/
|
||||
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType) {
|
||||
return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
|
||||
* valueType} in a {@link Map} that is itself bound with {@code annotation}.
|
||||
*/
|
||||
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType,
|
||||
Annotation annotation) {
|
||||
binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
|
||||
return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType), annotation), Key.get(mapOfProviderOf(
|
||||
keyType, valueType), annotation), Key.get(mapOf(keyType, setOf(valueType)), annotation), Key.get(
|
||||
mapOfSetOfProviderOf(keyType, valueType), annotation), Multibinder.newSetBinder(binder, entryOfProviderOf(
|
||||
keyType, valueType), annotation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
|
||||
* valueType} in a {@link Map} that is itself bound with {@code annotation}.
|
||||
*/
|
||||
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType,
|
||||
Annotation annotation) {
|
||||
return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
|
||||
* valueType} in a {@link Map} that is itself bound with {@code
|
||||
* annotationType}.
|
||||
*/
|
||||
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
binder = binder.skipSources(MapBinder.class, RealMapBinder.class);
|
||||
return newMapBinder(binder, valueType, Key.get(mapOf(keyType, valueType), annotationType), Key.get(
|
||||
mapOfProviderOf(keyType, valueType), annotationType), Key.get(mapOf(keyType, setOf(valueType)),
|
||||
annotationType), Key.get(mapOfSetOfProviderOf(keyType, valueType), annotationType), Multibinder
|
||||
.newSetBinder(binder, entryOfProviderOf(keyType, valueType), annotationType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new mapbinder that collects entries of {@code keyType}/{@code
|
||||
* valueType} in a {@link Map} that is itself bound with {@code
|
||||
* annotationType}.
|
||||
*/
|
||||
public static <K, V> MapBinder<K, V> newMapBinder(Binder binder, Class<K> keyType, Class<V> valueType,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotationType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// a map of <K, V> is safely a Map<K, V>
|
||||
private static <K, V> TypeLiteral<Map<K, V>> mapOf(TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
|
||||
return (TypeLiteral<Map<K, V>>) TypeLiteral.get(Types.mapOf(keyType.getType(), valueType.getType()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// a provider map <K, V> is safely a Map<K, Provider<V>>
|
||||
private static <K, V> TypeLiteral<Map<K, Provider<V>>> mapOfProviderOf(TypeLiteral<K> keyType,
|
||||
TypeLiteral<V> valueType) {
|
||||
return (TypeLiteral<Map<K, Provider<V>>>) TypeLiteral.get(Types.mapOf(keyType.getType(), Types
|
||||
.providerOf(valueType.getType())));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
|
||||
private static <K, V> TypeLiteral<Map<K, Set<Provider<V>>>> mapOfSetOfProviderOf(TypeLiteral<K> keyType,
|
||||
TypeLiteral<V> valueType) {
|
||||
return (TypeLiteral<Map<K, Set<Provider<V>>>>) TypeLiteral.get(Types.mapOf(keyType.getType(), Types.setOf(Types
|
||||
.providerOf(valueType.getType()))));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
|
||||
private static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfProviderOf(TypeLiteral<K> keyType,
|
||||
TypeLiteral<V> valueType) {
|
||||
return (TypeLiteral<Entry<K, Provider<V>>>) TypeLiteral.get(newParameterizedTypeWithOwner(Map.class, Entry.class,
|
||||
keyType.getType(), Types.providerOf(valueType.getType())));
|
||||
}
|
||||
|
||||
private static <K, V> MapBinder<K, V> newMapBinder(Binder binder, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey,
|
||||
Key<Map<K, Provider<V>>> providerMapKey, Key<Map<K, Set<V>>> multimapKey,
|
||||
Key<Map<K, Set<Provider<V>>>> providerMultimapKey, Multibinder<Entry<K, Provider<V>>> entrySetBinder) {
|
||||
RealMapBinder<K, V> mapBinder = new RealMapBinder<K, V>(binder, valueType, mapKey, providerMapKey, multimapKey,
|
||||
providerMultimapKey, entrySetBinder);
|
||||
binder.install(mapBinder);
|
||||
return mapBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@code MapBinder} to handle duplicate entries.
|
||||
* <p>
|
||||
* When multiple equal keys are bound, the value that gets included in the
|
||||
* map is arbitrary.
|
||||
* <p>
|
||||
* In addition to the {@code Map<K, V>} and {@code Map<K, Provider<V>>} maps
|
||||
* that are normally bound, a {@code Map<K, Set<V>>} and {@code Map<K,
|
||||
* Set<Provider<V>>>} are <em>also</em> bound, which contain all values bound
|
||||
* to each key.
|
||||
* <p>
|
||||
* When multiple modules contribute elements to the map, this configuration
|
||||
* option impacts all of them.
|
||||
*
|
||||
* @return this map binder
|
||||
*/
|
||||
public abstract MapBinder<K, V> permitDuplicates();
|
||||
|
||||
/**
|
||||
* Returns a binding builder used to add a new entry in the map. Each key
|
||||
* must be distinct (and non-null). Bound providers will be evaluated each
|
||||
* time the map is injected.
|
||||
*
|
||||
* <p>
|
||||
* It is an error to call this method without also calling one of the {@code
|
||||
* to} methods on the returned binding builder.
|
||||
*
|
||||
* <p>
|
||||
* Scoping elements independently is supported. Use the {@code in} method to
|
||||
* specify a binding scope.
|
||||
*/
|
||||
public abstract LinkedBindingBuilder<V> addBinding(K key);
|
||||
|
||||
/**
|
||||
* The actual mapbinder plays several roles:
|
||||
*
|
||||
* <p>
|
||||
* As a MapBinder, it acts as a factory for LinkedBindingBuilders for each of
|
||||
* the map's values. It delegates to a {@link Multibinder} of entries (keys
|
||||
* to value providers).
|
||||
*
|
||||
* <p>
|
||||
* As a Module, it installs the binding to the map itself, as well as to a
|
||||
* corresponding map whose values are providers. It uses the entry set
|
||||
* multibinder to construct the map and the provider map.
|
||||
*
|
||||
* <p>
|
||||
* As a module, this implements equals() and hashcode() in order to trick
|
||||
* Guice into executing its configure() method only once. That makes it so
|
||||
* that multiple mapbinders can be created for the same target map, but only
|
||||
* one is bound. Since the list of bindings is retrieved from the injector
|
||||
* itself (and not the mapbinder), each mapbinder has access to all
|
||||
* contributions from all equivalent mapbinders.
|
||||
*
|
||||
* <p>
|
||||
* Rather than binding a single Map.Entry<K, V>, the map binder binds
|
||||
* keys and values independently. This allows the values to be properly
|
||||
* scoped.
|
||||
*
|
||||
* <p>
|
||||
* We use a subclass to hide 'implements Module' from the public API.
|
||||
*/
|
||||
private static final class RealMapBinder<K, V> extends MapBinder<K, V> implements Module {
|
||||
private final TypeLiteral<V> valueType;
|
||||
private final Key<Map<K, V>> mapKey;
|
||||
private final Key<Map<K, Provider<V>>> providerMapKey;
|
||||
private final Key<Map<K, Set<V>>> multimapKey;
|
||||
private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
|
||||
private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder;
|
||||
|
||||
/*
|
||||
* the target injector's binder. non-null until initialization, null
|
||||
* afterwards
|
||||
*/
|
||||
private Binder binder;
|
||||
|
||||
private RealMapBinder(Binder binder, TypeLiteral<V> valueType, Key<Map<K, V>> mapKey,
|
||||
Key<Map<K, Provider<V>>> providerMapKey, Key<Map<K, Set<V>>> multimapKey,
|
||||
Key<Map<K, Set<Provider<V>>>> providerMultimapKey, Multibinder<Map.Entry<K, Provider<V>>> entrySetBinder) {
|
||||
this.valueType = valueType;
|
||||
this.mapKey = mapKey;
|
||||
this.providerMapKey = providerMapKey;
|
||||
this.multimapKey = multimapKey;
|
||||
this.providerMultimapKey = providerMultimapKey;
|
||||
this.entrySetBinder = (RealMultibinder<Entry<K, Provider<V>>>) entrySetBinder;
|
||||
this.binder = binder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapBinder<K, V> permitDuplicates() {
|
||||
entrySetBinder.permitDuplicates();
|
||||
binder.install(new MultimapBinder<K, V>(multimapKey, providerMultimapKey, entrySetBinder.getSetKey()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates two bindings. One for the {@code Map.Entry<K,
|
||||
* Provider<V>>} and another for {@code V}.
|
||||
*/
|
||||
@Override
|
||||
public LinkedBindingBuilder<V> addBinding(K key) {
|
||||
checkNotNull(key, "key");
|
||||
checkConfiguration(!isInitialized(), "MapBinder was already initialized");
|
||||
|
||||
Key<V> valueKey = Key.get(valueType, new RealElement(entrySetBinder.getSetName()));
|
||||
entrySetBinder.addBinding().toInstance(new MapEntry<K, Provider<V>>(key, binder.getProvider(valueKey)));
|
||||
return binder.bind(valueKey);
|
||||
}
|
||||
|
||||
public void configure(Binder binder) {
|
||||
checkConfiguration(!isInitialized(), "MapBinder was already initialized");
|
||||
|
||||
final ImmutableSet<Dependency<?>> dependencies = ImmutableSet.<Dependency<?>> of(Dependency.get(entrySetBinder
|
||||
.getSetKey()));
|
||||
|
||||
// Binds a Map<K, Provider<V>> from a collection of Map<Entry<K,
|
||||
// Provider<V>>.
|
||||
final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider = binder.getProvider(entrySetBinder.getSetKey());
|
||||
binder.bind(providerMapKey).toProvider(new ProviderWithDependencies<Map<K, Provider<V>>>() {
|
||||
private Map<K, Provider<V>> providerMap;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Inject
|
||||
void initialize(Injector injector) {
|
||||
RealMapBinder.this.binder = null;
|
||||
boolean permitDuplicates = entrySetBinder.permitsDuplicates(injector);
|
||||
|
||||
Map<K, Provider<V>> providerMapMutable = new LinkedHashMap<K, Provider<V>>();
|
||||
for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
|
||||
Provider<V> previous = providerMapMutable.put(entry.getKey(), entry.getValue());
|
||||
checkConfiguration(previous == null || permitDuplicates,
|
||||
"Map injection failed due to duplicated key \"%s\"", entry.getKey());
|
||||
}
|
||||
|
||||
providerMap = ImmutableMap.copyOf(providerMapMutable);
|
||||
}
|
||||
|
||||
public Map<K, Provider<V>> get() {
|
||||
return providerMap;
|
||||
}
|
||||
|
||||
public Set<Dependency<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
});
|
||||
|
||||
final Provider<Map<K, Provider<V>>> mapProvider = binder.getProvider(providerMapKey);
|
||||
binder.bind(mapKey).toProvider(new ProviderWithDependencies<Map<K, V>>() {
|
||||
public Map<K, V> get() {
|
||||
Map<K, V> map = new LinkedHashMap<K, V>();
|
||||
for (Entry<K, Provider<V>> entry : mapProvider.get().entrySet()) {
|
||||
V value = entry.getValue().get();
|
||||
K key = entry.getKey();
|
||||
checkConfiguration(value != null, "Map injection failed due to null value for key \"%s\"", key);
|
||||
map.put(key, value);
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
public Set<Dependency<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isInitialized() {
|
||||
return binder == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof RealMapBinder<?, ?> && ((RealMapBinder<?, ?>) o).mapKey.equals(mapKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mapKey.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds {@code Map<K, Set<V>>} and {{@code Map<K, Set<Provider<V>>>}.
|
||||
*/
|
||||
private static final class MultimapBinder<K, V> implements Module {
|
||||
|
||||
private final Key<Map<K, Set<V>>> multimapKey;
|
||||
private final Key<Map<K, Set<Provider<V>>>> providerMultimapKey;
|
||||
private final Key<Set<Entry<K, Provider<V>>>> entrySetKey;
|
||||
|
||||
public MultimapBinder(Key<Map<K, Set<V>>> multimapKey, Key<Map<K, Set<Provider<V>>>> providerMultimapKey,
|
||||
Key<Set<Entry<K, Provider<V>>>> entrySetKey) {
|
||||
this.multimapKey = multimapKey;
|
||||
this.providerMultimapKey = providerMultimapKey;
|
||||
this.entrySetKey = entrySetKey;
|
||||
}
|
||||
|
||||
public void configure(Binder binder) {
|
||||
final ImmutableSet<Dependency<?>> dependencies = ImmutableSet.<Dependency<?>> of(Dependency
|
||||
.get(entrySetKey));
|
||||
|
||||
final Provider<Set<Entry<K, Provider<V>>>> entrySetProvider = binder.getProvider(entrySetKey);
|
||||
// Binds a Map<K, Set<Provider<V>>> from a collection of
|
||||
// Map<Entry<K, Provider<V>> if
|
||||
// permitDuplicates was called.
|
||||
binder.bind(providerMultimapKey).toProvider(new ProviderWithDependencies<Map<K, Set<Provider<V>>>>() {
|
||||
private Map<K, Set<Provider<V>>> providerMultimap;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Inject
|
||||
void initialize(Injector injector) {
|
||||
Map<K, ImmutableSet.Builder<Provider<V>>> providerMultimapMutable = new LinkedHashMap<K, ImmutableSet.Builder<Provider<V>>>();
|
||||
for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
|
||||
if (!providerMultimapMutable.containsKey(entry.getKey())) {
|
||||
providerMultimapMutable.put(entry.getKey(), ImmutableSet.<Provider<V>> builder());
|
||||
}
|
||||
providerMultimapMutable.get(entry.getKey()).add(entry.getValue());
|
||||
}
|
||||
|
||||
ImmutableMap.Builder<K, Set<Provider<V>>> providerMultimapBuilder = ImmutableMap.builder();
|
||||
for (Entry<K, ImmutableSet.Builder<Provider<V>>> entry : providerMultimapMutable.entrySet()) {
|
||||
providerMultimapBuilder.put(entry.getKey(), entry.getValue().build());
|
||||
}
|
||||
providerMultimap = providerMultimapBuilder.build();
|
||||
}
|
||||
|
||||
public Map<K, Set<Provider<V>>> get() {
|
||||
return providerMultimap;
|
||||
}
|
||||
|
||||
public Set<Dependency<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
});
|
||||
|
||||
final Provider<Map<K, Set<Provider<V>>>> multimapProvider = binder.getProvider(providerMultimapKey);
|
||||
binder.bind(multimapKey).toProvider(new ProviderWithDependencies<Map<K, Set<V>>>() {
|
||||
|
||||
public Map<K, Set<V>> get() {
|
||||
ImmutableMap.Builder<K, Set<V>> multimapBuilder = ImmutableMap.builder();
|
||||
for (Entry<K, Set<Provider<V>>> entry : multimapProvider.get().entrySet()) {
|
||||
K key = entry.getKey();
|
||||
ImmutableSet.Builder<V> valuesBuilder = ImmutableSet.builder();
|
||||
for (Provider<V> valueProvider : entry.getValue()) {
|
||||
V value = valueProvider.get();
|
||||
checkConfiguration(value != null, "Multimap injection failed due to null value for key \"%s\"",
|
||||
key);
|
||||
valuesBuilder.add(value);
|
||||
}
|
||||
multimapBuilder.put(key, valuesBuilder.build());
|
||||
}
|
||||
return multimapBuilder.build();
|
||||
}
|
||||
|
||||
public Set<Dependency<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MapEntry<K, V> implements Map.Entry<K, V> {
|
||||
private final K key;
|
||||
private final V value;
|
||||
|
||||
private MapEntry(K key, V value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public V setValue(V value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Map.Entry<?, ?> && key.equals(((Map.Entry<?, ?>) obj).getKey())
|
||||
&& value.equals(((Map.Entry<?, ?>) obj).getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 127 * ("key".hashCode() ^ key.hashCode()) + 127 * ("value".hashCode() ^ value.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MapEntry(" + key + ", " + value + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
/**
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.ohai.config.multibindings;
|
||||
|
||||
import static com.google.inject.name.Names.named;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Binding;
|
||||
import com.google.inject.ConfigurationException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.binder.LinkedBindingBuilder;
|
||||
import com.google.inject.internal.Errors;
|
||||
import com.google.inject.spi.Dependency;
|
||||
import com.google.inject.spi.HasDependencies;
|
||||
import com.google.inject.spi.Message;
|
||||
import com.google.inject.spi.Toolable;
|
||||
import com.google.inject.util.Types;
|
||||
|
||||
/**
|
||||
*
|
||||
* An API to bind multiple values separately, only to later inject them as a
|
||||
* complete collection. Multibinder is intended for use in your application's
|
||||
* module:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* public class SnacksModule extends AbstractModule {
|
||||
* protected void configure() {
|
||||
* Multibinder<Snack> multibinder
|
||||
* = Multibinder.newSetBinder(binder(), Snack.class);
|
||||
* multibinder.addBinding().toInstance(new Twix());
|
||||
* multibinder.addBinding().toProvider(SnickersProvider.class);
|
||||
* multibinder.addBinding().to(Skittles.class);
|
||||
* }
|
||||
* }</code>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* With this binding, a {@link Set}{@code <Snack>} can now be injected:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* class SnackMachine {
|
||||
* {@literal @}Inject
|
||||
* public SnackMachine(Set<Snack> snacks) { ... }
|
||||
* }</code>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Contributing multibindings from different modules is supported. For example,
|
||||
* it is okay to have both {@code CandyModule} and {@code ChipsModule} to both
|
||||
* create their own {@code Multibinder<Snack>}, and to each contribute bindings
|
||||
* to the set of snacks. When that set is injected, it will contain elements
|
||||
* from both modules.
|
||||
*
|
||||
* <p>
|
||||
* The set's iteration order is consistent with the binding order. This is
|
||||
* convenient when multiple elements are contributed by the same module because
|
||||
* that module can order its bindings appropriately. Avoid relying on the
|
||||
* iteration order of elements contributed by different modules, since there is
|
||||
* no equivalent mechanism to order modules.
|
||||
*
|
||||
* <p>
|
||||
* Elements are resolved at set injection time. If an element is bound to a
|
||||
* provider, that provider's get method will be called each time the set is
|
||||
* injected (unless the binding is also scoped).
|
||||
*
|
||||
* <p>
|
||||
* Annotations are be used to create different sets of the same element type.
|
||||
* Each distinct annotation gets its own independent collection of elements.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Elements must be distinct.</strong> If multiple bound elements have
|
||||
* the same value, set injection will fail.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Elements must be non-null.</strong> If any set element is null, set
|
||||
* injection will fail.
|
||||
*
|
||||
* @author jessewilson@google.com (Jesse Wilson)
|
||||
*/
|
||||
public abstract class Multibinder<T> {
|
||||
private Multibinder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new multibinder that collects instances of {@code type} in a
|
||||
* {@link Set} that is itself bound with no binding annotation.
|
||||
*/
|
||||
public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type) {
|
||||
binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
|
||||
RealMultibinder<T> result = new RealMultibinder<T>(binder, type, "", Key.get(Multibinder.<T> setOf(type)));
|
||||
binder.install(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new multibinder that collects instances of {@code type} in a
|
||||
* {@link Set} that is itself bound with no binding annotation.
|
||||
*/
|
||||
public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type) {
|
||||
return newSetBinder(binder, TypeLiteral.get(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new multibinder that collects instances of {@code type} in a
|
||||
* {@link Set} that is itself bound with {@code annotation}.
|
||||
*/
|
||||
public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type, Annotation annotation) {
|
||||
binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
|
||||
RealMultibinder<T> result = new RealMultibinder<T>(binder, type, annotation.toString(), Key.get(Multibinder
|
||||
.<T> setOf(type), annotation));
|
||||
binder.install(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new multibinder that collects instances of {@code type} in a
|
||||
* {@link Set} that is itself bound with {@code annotation}.
|
||||
*/
|
||||
public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type, Annotation annotation) {
|
||||
return newSetBinder(binder, TypeLiteral.get(type), annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new multibinder that collects instances of {@code type} in a
|
||||
* {@link Set} that is itself bound with {@code annotationType}.
|
||||
*/
|
||||
public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
binder = binder.skipSources(RealMultibinder.class, Multibinder.class);
|
||||
RealMultibinder<T> result = new RealMultibinder<T>(binder, type, "@" + annotationType.getName(), Key.get(
|
||||
Multibinder.<T> setOf(type), annotationType));
|
||||
binder.install(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new multibinder that collects instances of {@code type} in a
|
||||
* {@link Set} that is itself bound with {@code annotationType}.
|
||||
*/
|
||||
public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
return newSetBinder(binder, TypeLiteral.get(type), annotationType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// wrapping a T in a Set safely returns a Set<T>
|
||||
static <T> TypeLiteral<Set<T>> setOf(TypeLiteral<T> elementType) {
|
||||
Type type = Types.setOf(elementType.getType());
|
||||
return (TypeLiteral<Set<T>>) TypeLiteral.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the bound set to silently discard duplicate elements. When
|
||||
* multiple equal values are bound, the one that gets included is arbitrary.
|
||||
* When multiple modules contribute elements to the set, this configuration
|
||||
* option impacts all of them.
|
||||
*
|
||||
* @return this multibinder
|
||||
*/
|
||||
public abstract Multibinder<T> permitDuplicates();
|
||||
|
||||
/**
|
||||
* Returns a binding builder used to add a new element in the set. Each bound
|
||||
* element must have a distinct value. Bound providers will be evaluated each
|
||||
* time the set is injected.
|
||||
*
|
||||
* <p>
|
||||
* It is an error to call this method without also calling one of the {@code
|
||||
* to} methods on the returned binding builder.
|
||||
*
|
||||
* <p>
|
||||
* Scoping elements independently is supported. Use the {@code in} method to
|
||||
* specify a binding scope.
|
||||
*/
|
||||
public abstract LinkedBindingBuilder<T> addBinding();
|
||||
|
||||
/**
|
||||
* The actual multibinder plays several roles:
|
||||
*
|
||||
* <p>
|
||||
* As a Multibinder, it acts as a factory for LinkedBindingBuilders for each
|
||||
* of the set's elements. Each binding is given an annotation that identifies
|
||||
* it as a part of this set.
|
||||
*
|
||||
* <p>
|
||||
* As a Module, it installs the binding to the set itself. As a module, this
|
||||
* implements equals() and hashcode() in order to trick Guice into executing
|
||||
* its configure() method only once. That makes it so that multiple
|
||||
* multibinders can be created for the same target collection, but only one
|
||||
* is bound. Since the list of bindings is retrieved from the injector itself
|
||||
* (and not the multibinder), each multibinder has access to all
|
||||
* contributions from all multibinders.
|
||||
*
|
||||
* <p>
|
||||
* As a Provider, this constructs the set instances.
|
||||
*
|
||||
* <p>
|
||||
* We use a subclass to hide 'implements Module, Provider' from the public
|
||||
* API.
|
||||
*/
|
||||
static final class RealMultibinder<T> extends Multibinder<T> implements Module, Provider<Set<T>>, HasDependencies {
|
||||
|
||||
private final TypeLiteral<T> elementType;
|
||||
private final String setName;
|
||||
private final Key<Set<T>> setKey;
|
||||
private final Key<Boolean> permitDuplicatesKey;
|
||||
|
||||
/*
|
||||
* the target injector's binder. non-null until initialization, null
|
||||
* afterwards
|
||||
*/
|
||||
private Binder binder;
|
||||
|
||||
/*
|
||||
* a provider for each element in the set. null until initialization,
|
||||
* non-null afterwards
|
||||
*/
|
||||
private List<Provider<T>> providers;
|
||||
private Set<Dependency<?>> dependencies;
|
||||
|
||||
/**
|
||||
* whether duplicates are allowed. Possibly configured by a different
|
||||
* instance
|
||||
*/
|
||||
private boolean permitDuplicates;
|
||||
|
||||
private RealMultibinder(Binder binder, TypeLiteral<T> elementType, String setName, Key<Set<T>> setKey) {
|
||||
this.binder = checkNotNull(binder, "binder");
|
||||
this.elementType = checkNotNull(elementType, "elementType");
|
||||
this.setName = checkNotNull(setName, "setName");
|
||||
this.setKey = checkNotNull(setKey, "setKey");
|
||||
this.permitDuplicatesKey = Key.get(Boolean.class, named(toString() + " permits duplicates"));
|
||||
}
|
||||
|
||||
public void configure(Binder binder) {
|
||||
checkConfiguration(!isInitialized(), "Multibinder was already initialized");
|
||||
binder.bind(setKey).toProvider(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multibinder<T> permitDuplicates() {
|
||||
binder.install(new PermitDuplicatesModule(permitDuplicatesKey));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedBindingBuilder<T> addBinding() {
|
||||
checkConfiguration(!isInitialized(), "Multibinder was already initialized");
|
||||
|
||||
return binder.bind(Key.get(elementType, new RealElement(setName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by Guice at Injector-creation time to prepare providers for
|
||||
* each element in this set. At this time the set's size is known, but its
|
||||
* contents are only evaluated when get() is invoked.
|
||||
*/
|
||||
@Toolable
|
||||
@Inject
|
||||
void initialize(Injector injector) {
|
||||
providers = Lists.newArrayList();
|
||||
List<Dependency<?>> dependencies = Lists.newArrayList();
|
||||
for (Binding<?> entry : injector.findBindingsByType(elementType)) {
|
||||
|
||||
if (keyMatches(entry.getKey())) {
|
||||
@SuppressWarnings("unchecked")
|
||||
// protected by findBindingsByType()
|
||||
Binding<T> binding = (Binding<T>) entry;
|
||||
providers.add(binding.getProvider());
|
||||
dependencies.add(Dependency.get(binding.getKey()));
|
||||
}
|
||||
}
|
||||
|
||||
this.dependencies = ImmutableSet.copyOf(dependencies);
|
||||
this.permitDuplicates = permitsDuplicates(injector);
|
||||
this.binder = null;
|
||||
}
|
||||
|
||||
boolean permitsDuplicates(Injector injector) {
|
||||
return injector.getBindings().containsKey(permitDuplicatesKey);
|
||||
}
|
||||
|
||||
private boolean keyMatches(Key<?> key) {
|
||||
return key.getTypeLiteral().equals(elementType) && key.getAnnotation() instanceof Element
|
||||
&& ((Element) key.getAnnotation()).setName().equals(setName);
|
||||
}
|
||||
|
||||
private boolean isInitialized() {
|
||||
return binder == null;
|
||||
}
|
||||
|
||||
public Set<T> get() {
|
||||
checkConfiguration(isInitialized(), "Multibinder is not initialized");
|
||||
|
||||
Set<T> result = new LinkedHashSet<T>();
|
||||
for (Provider<T> provider : providers) {
|
||||
final T newValue = provider.get();
|
||||
checkConfiguration(newValue != null, "Set injection failed due to null element");
|
||||
checkConfiguration(result.add(newValue) || permitDuplicates,
|
||||
"Set injection failed due to duplicated element \"%s\"", newValue);
|
||||
}
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
|
||||
String getSetName() {
|
||||
return setName;
|
||||
}
|
||||
|
||||
Key<Set<T>> getSetKey() {
|
||||
return setKey;
|
||||
}
|
||||
|
||||
public Set<Dependency<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof RealMultibinder<?> && ((RealMultibinder<?>) o).setKey.equals(setKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return setKey.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append(setName).append(setName.length() > 0 ? " " : "").append("Multibinder<")
|
||||
.append(elementType).append(">").toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We install the permit duplicates configuration as its own binding, all by
|
||||
* itself. This way, if only one of a multibinder's users remember to call
|
||||
* permitDuplicates(), they're still permitted.
|
||||
*/
|
||||
private static class PermitDuplicatesModule extends AbstractModule {
|
||||
private final Key<Boolean> key;
|
||||
|
||||
PermitDuplicatesModule(Key<Boolean> key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(key).toInstance(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof PermitDuplicatesModule && ((PermitDuplicatesModule) o).key.equals(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode() ^ key.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
static void checkConfiguration(boolean condition, String format, Object... args) {
|
||||
if (condition) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ConfigurationException(ImmutableSet.of(new Message(Errors.format(format, args))));
|
||||
}
|
||||
|
||||
static <T> T checkNotNull(T reference, String name) {
|
||||
if (reference != null) {
|
||||
return reference;
|
||||
}
|
||||
|
||||
NullPointerException npe = new NullPointerException(name);
|
||||
throw new ConfigurationException(ImmutableSet.of(new Message(ImmutableList.of(), npe.toString(), npe)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
|
||||
package org.jclouds.ohai.config.multibindings;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
||||
/**
|
||||
* @author jessewilson@google.com (Jesse Wilson)
|
||||
*/
|
||||
class RealElement implements Element {
|
||||
private static final AtomicInteger nextUniqueId = new AtomicInteger(1);
|
||||
|
||||
private final int uniqueId;
|
||||
private final String setName;
|
||||
|
||||
RealElement(String setName) {
|
||||
uniqueId = nextUniqueId.getAndIncrement();
|
||||
this.setName = setName;
|
||||
}
|
||||
|
||||
public String setName() {
|
||||
return setName;
|
||||
}
|
||||
|
||||
public int uniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Element.class;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "@" + Element.class.getName() + "(setName=" + setName
|
||||
+ ",uniqueId=" + uniqueId + ")";
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
return o instanceof Element
|
||||
&& ((Element) o).setName().equals(setName())
|
||||
&& ((Element) o).uniqueId() == uniqueId();
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return 127 * ("setName".hashCode() ^ setName.hashCode())
|
||||
+ 127 * ("uniqueId".hashCode() ^ uniqueId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Taken from r1154 of Guice, as they decided to stop supporting multiple bindings and instead silently throw them away.
|
||||
*/
|
||||
package org.jclouds.ohai.config.multibindings;
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.functions;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class MapSetToMultimap<K, V> implements Function<Map<K, Set<V>>, Multimap<K, V>> {
|
||||
|
||||
@Override
|
||||
public Multimap<K, V> apply(Map<K, Set<V>> from) {
|
||||
Multimap<K, V> returnV = LinkedHashMultimap.create();
|
||||
for (Entry<K, Set<V>> entry : from.entrySet()) {
|
||||
for (V value : entry.getValue())
|
||||
returnV.put(entry.getKey(), value);
|
||||
}
|
||||
return returnV;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.json.Json;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class NestSlashKeys implements Function<Multimap<String, Supplier<JsonBall>>, Map<String, JsonBall>> {
|
||||
|
||||
private final Json json;
|
||||
|
||||
@Inject
|
||||
NestSlashKeys(Json json) {
|
||||
this.json = checkNotNull(json, "json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, JsonBall> apply(Multimap<String, Supplier<JsonBall>> from) {
|
||||
|
||||
Map<String, JsonBall> autoAttrs = mergeSameKeys(from);
|
||||
|
||||
Map<String, JsonBall> modifiableFlatMap = Maps.newLinkedHashMap(Maps.filterKeys(autoAttrs,
|
||||
new Predicate<String>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return input.indexOf('/') == -1;
|
||||
}
|
||||
|
||||
}));
|
||||
Map<String, JsonBall> withSlashesMap = Maps.difference(autoAttrs, modifiableFlatMap).entriesOnlyOnLeft();
|
||||
for (Entry<String, JsonBall> entry : withSlashesMap.entrySet()) {
|
||||
List<String> keyParts = Lists.newArrayList(Splitter.on('/').split(entry.getKey()));
|
||||
JsonBall toInsert = entry.getValue();
|
||||
try {
|
||||
putUnderContext(keyParts, toInsert, modifiableFlatMap);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("error inserting value in entry: " + entry.getKey(), e);
|
||||
}
|
||||
}
|
||||
return modifiableFlatMap;
|
||||
}
|
||||
|
||||
private Map<String, JsonBall> mergeSameKeys(Multimap<String, Supplier<JsonBall>> from) {
|
||||
Map<String, JsonBall> merged = Maps.newLinkedHashMap();
|
||||
for (Entry<String, Supplier<JsonBall>> entry : from.entries()) {
|
||||
if (merged.containsKey(entry.getKey())) {
|
||||
mergeAsPeer(entry.getKey(), entry.getValue().get(), merged);
|
||||
} else {
|
||||
merged.put(entry.getKey(), entry.getValue().get());
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void mergeAsPeer(String key, JsonBall value, Map<String, JsonBall> insertionContext) {
|
||||
Map<String, JsonBall> valueContext = json.fromJson(insertionContext.get(key).toString(), mapLiteral);
|
||||
Map<String, JsonBall> toPut = json.<Map<String, JsonBall>> fromJson(value.toString(), mapLiteral);
|
||||
Set<String> uniques = Sets.difference(toPut.keySet(), valueContext.keySet());
|
||||
for (String k : uniques)
|
||||
valueContext.put(k, toPut.get(k));
|
||||
Set<String> conflicts = Sets.difference(toPut.keySet(), uniques);
|
||||
for (String k : conflicts) {
|
||||
JsonBall v = toPut.get(k);
|
||||
if (v.toString().matches("^\\{.*\\}$")) {
|
||||
mergeAsPeer(k, v, valueContext);
|
||||
} else {
|
||||
// replace
|
||||
valueContext.put(k, v);
|
||||
}
|
||||
}
|
||||
insertionContext.put(key, new JsonBall(json.toJson(valueContext, mapLiteral)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param keyParts
|
||||
* @param toInsert
|
||||
* @param destination
|
||||
* @throws IllegalArgumentException
|
||||
* <p/>
|
||||
* if destination.get(keyParts(0)) is not a map *
|
||||
* <p/>
|
||||
* keyParts is zero length
|
||||
*/
|
||||
void putUnderContext(List<String> keyParts, JsonBall toInsert, Map<String, JsonBall> destination) {
|
||||
checkNotNull(keyParts, "keyParts");
|
||||
checkArgument(keyParts.size() >= 1, "keyParts must contain at least one element");
|
||||
|
||||
checkNotNull(toInsert, "toInsert");
|
||||
checkNotNull(destination, "destination");
|
||||
|
||||
String rootKey = keyParts.remove(0);
|
||||
String rootValue = destination.containsKey(rootKey) ? destination.get(rootKey).toString() : "{}";
|
||||
|
||||
checkArgument(rootValue.matches("^\\{.*\\}$"), "value must be a hash: %s", rootValue);
|
||||
Map<String, JsonBall> insertionContext = json.fromJson(rootValue, mapLiteral);
|
||||
if (keyParts.size() == 1) {
|
||||
if (!insertionContext.containsKey(keyParts.get(0))) {
|
||||
insertionContext.put(keyParts.get(0), toInsert);
|
||||
} else {
|
||||
String key = keyParts.get(0);
|
||||
mergeAsPeer(key, toInsert, insertionContext);
|
||||
}
|
||||
} else {
|
||||
putUnderContext(keyParts, toInsert, insertionContext);
|
||||
}
|
||||
destination.put(rootKey, new JsonBall(json.toJson(insertionContext, mapLiteral)));
|
||||
}
|
||||
|
||||
final Type mapLiteral = new TypeLiteral<Map<String, JsonBall>>() {
|
||||
}.getType();
|
||||
final Type listLiteral = new TypeLiteral<List<JsonBall>>() {
|
||||
}.getType();
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.plugins;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.inject.internal.Maps.newLinkedHashMap;
|
||||
import static org.jclouds.ohai.Util.OhaiUtils.toOhaiTime;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
*
|
||||
* Gathers Ohai data from the JVM. Note that this is intended to be Google App
|
||||
* Engine compatible, so please do not access the network, JMX, or other classes
|
||||
* not on the whitelist.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class WhiteListCompliantJVM implements Supplier<Map<String, JsonBall>> {
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Json json;
|
||||
private final Provider<Long> nanoTimeProvider;
|
||||
private final Provider<Properties> systemPropertiesProvider;
|
||||
|
||||
@Inject
|
||||
public WhiteListCompliantJVM(Json json, @Named("nanoTime") Provider<Long> nanoTimeProvider,
|
||||
@Named("systemProperties") Provider<Properties> systemPropertiesProvider) {
|
||||
this.json = checkNotNull(json, "json");
|
||||
this.nanoTimeProvider = checkNotNull(nanoTimeProvider, "nanoTimeProvider");
|
||||
this.systemPropertiesProvider = checkNotNull(systemPropertiesProvider, "systemPropertiesProvider");
|
||||
}
|
||||
|
||||
public Map<String, JsonBall> get() {
|
||||
Map<String, JsonBall> returnVal = newLinkedHashMap();
|
||||
Properties systemProperties = systemPropertiesProvider.get();
|
||||
|
||||
returnVal.put("ohai_time", toOhaiTime(nanoTimeProvider.get()));
|
||||
|
||||
returnVal.put("java", new JsonBall(json.toJson(systemProperties)));
|
||||
|
||||
String platform = systemProperties.getProperty("os.name");
|
||||
platform = platform.replaceAll("[ -]", "").toLowerCase();
|
||||
|
||||
returnVal.put("platform", new JsonBall(platform));
|
||||
|
||||
if (systemProperties.getProperty("os.version") != null)
|
||||
returnVal.put("platform_version", new JsonBall(systemProperties.getProperty("os.version")));
|
||||
|
||||
if (systemProperties.getProperty("user.name") != null)
|
||||
returnVal.put("current_user", new JsonBall(systemProperties.getProperty("user.name")));
|
||||
return returnVal;
|
||||
}
|
||||
}
|
|
@ -16,27 +16,35 @@
|
|||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.config;
|
||||
package org.jclouds.ohai.suppliers;
|
||||
|
||||
import java.util.Map;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.ohai.plugins.WhiteListCompliantJVM;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Wires the components needed to parse ohai data without violating the GAE JVM
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresOhai
|
||||
public class WhiteListCompliantOhaiJVMModule extends BaseOhaiJVMModule {
|
||||
@Singleton
|
||||
public class UptimeSecondsSupplier implements Supplier<JsonBall> {
|
||||
|
||||
@Inject
|
||||
UptimeSecondsSupplier(RuntimeMXBean runtime) {
|
||||
this.runtime = runtime;
|
||||
}
|
||||
|
||||
private final RuntimeMXBean runtime;
|
||||
|
||||
@Override
|
||||
protected Iterable<Supplier<Map<String, JsonBall>>> suppliers(Injector injector) {
|
||||
return ImmutableList.<Supplier<Map<String, JsonBall>>> of(injector.getInstance(WhiteListCompliantJVM.class));
|
||||
public JsonBall get() {
|
||||
long uptimeInSeconds = runtime.getUptime() / 1000;
|
||||
return new JsonBall(uptimeInSeconds);
|
||||
}
|
||||
|
||||
}
|
|
@ -174,7 +174,7 @@ public abstract class BaseChefClientLiveTest {
|
|||
System.err.printf("%s/%s:%n", cookbook, version);
|
||||
CookbookVersion cookbookO = getAdminConnection().getCookbook(cookbook, version);
|
||||
for (Resource resource : ImmutableList.<Resource> builder().addAll(cookbookO.getDefinitions()).addAll(
|
||||
cookbookO.getFiles()).addAll(cookbookO.getLibraries()).addAll(cookbookO.getProviders()).addAll(
|
||||
cookbookO.getFiles()).addAll(cookbookO.getLibraries()).addAll(cookbookO.getSuppliers()).addAll(
|
||||
cookbookO.getRecipes()).addAll(cookbookO.getResources()).addAll(cookbookO.getRootFiles()).addAll(
|
||||
cookbookO.getTemplates()).build()) {
|
||||
try {
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.jclouds.json.Json;
|
|||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||
import org.jclouds.rest.HttpClient;
|
||||
import org.jclouds.rest.RestContextFactory;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -80,8 +79,8 @@ public class ChefClientLiveTest extends BaseChefClientLiveTest {
|
|||
private ChefContext createConnection(String identity, String key) throws IOException {
|
||||
Properties props = new Properties();
|
||||
props.setProperty("chef.endpoint", endpoint);
|
||||
return (ChefContext) new RestContextFactory().<ChefClient, ChefAsyncClient> createContext("chef", identity, key,
|
||||
ImmutableSet.<Module> of(new Log4JLoggingModule()), props);
|
||||
return new ChefContextFactory().createContext(identity, key, ImmutableSet.<Module> of(new Log4JLoggingModule()),
|
||||
props);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,17 +31,16 @@ import java.util.Set;
|
|||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.domain.Node;
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.ohai.config.BaseOhaiModule;
|
||||
import org.jclouds.ohai.AutomaticSupplier;
|
||||
import org.jclouds.ohai.config.ConfiguresOhai;
|
||||
import org.jclouds.ohai.config.OhaiModule;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
|
@ -57,13 +56,11 @@ public class CreateNodeAndPopulateAutomaticAttributesImplLiveTest extends BaseCh
|
|||
private ChefClient chef;
|
||||
|
||||
@ConfiguresOhai
|
||||
static class TestOhaiModule extends BaseOhaiModule {
|
||||
static class TestOhaiModule extends OhaiModule {
|
||||
|
||||
@Override
|
||||
protected Iterable<Supplier<Map<String, JsonBall>>> suppliers(Injector injector) {
|
||||
Supplier<Map<String, JsonBall>> supplier = Suppliers.<Map<String, JsonBall>> ofInstance(ImmutableMap
|
||||
.<String, JsonBall> of("foo", new JsonBall("bar")));
|
||||
return ImmutableList.<Supplier<Map<String, JsonBall>>> of(supplier);
|
||||
protected Supplier<Map<String, JsonBall>> provideAutomatic(AutomaticSupplier in) {
|
||||
return Suppliers.<Map<String, JsonBall>> ofInstance(ImmutableMap.of("foo", new JsonBall("bar")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,17 +31,16 @@ import java.util.Set;
|
|||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.domain.Node;
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.ohai.config.BaseOhaiModule;
|
||||
import org.jclouds.ohai.AutomaticSupplier;
|
||||
import org.jclouds.ohai.config.ConfiguresOhai;
|
||||
import org.jclouds.ohai.config.OhaiModule;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
|
@ -55,13 +54,10 @@ public class UpdateAutomaticAttributesOnNodeImplLiveTest extends BaseChefStrateg
|
|||
private ChefClient chef;
|
||||
|
||||
@ConfiguresOhai
|
||||
static class TestOhaiModule extends BaseOhaiModule {
|
||||
|
||||
static class TestOhaiModule extends OhaiModule {
|
||||
@Override
|
||||
protected Iterable<Supplier<Map<String, JsonBall>>> suppliers(Injector injector) {
|
||||
Supplier<Map<String, JsonBall>> supplier = Suppliers.<Map<String, JsonBall>> ofInstance(ImmutableMap
|
||||
.<String, JsonBall> of("foo", new JsonBall("bar")));
|
||||
return ImmutableList.<Supplier<Map<String, JsonBall>>> of(supplier);
|
||||
protected Supplier<Map<String, JsonBall>> provideAutomatic(AutomaticSupplier in) {
|
||||
return Suppliers.<Map<String, JsonBall>> ofInstance(ImmutableMap.of("foo", new JsonBall("bar")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,22 +21,27 @@
|
|||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.plugins;
|
||||
package org.jclouds.ohai.config;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.chef.config.ChefParserModule;
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.ohai.config.JMXOhaiJVMModule;
|
||||
import org.jclouds.ohai.Automatic;
|
||||
import org.jclouds.ohai.config.JMXOhaiModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
|
@ -57,18 +62,23 @@ public class JMXTest {
|
|||
|
||||
replay(runtime);
|
||||
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule(), new JMXOhaiJVMModule() {
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule(), new JMXOhaiModule() {
|
||||
@Override
|
||||
protected RuntimeMXBean provideRuntimeMXBean() {
|
||||
return runtime;
|
||||
}
|
||||
});
|
||||
Json json = injector.getInstance(Json.class);
|
||||
JMX jmx = injector.getInstance(JMX.class);
|
||||
Ohai ohai = injector.getInstance(Ohai.class);
|
||||
assertEquals(json.toJson(ohai.ohai.get().get("uptime_seconds")), "69876");
|
||||
}
|
||||
|
||||
assertEquals(json.toJson(jmx.get()), "{\"uptime_seconds\":69876}");
|
||||
|
||||
verify(runtime);
|
||||
static class Ohai {
|
||||
private Supplier<Map<String, JsonBall>> ohai;
|
||||
|
||||
@Inject
|
||||
public Ohai(@Automatic Supplier<Map<String, JsonBall>> ohai) {
|
||||
this.ohai = ohai;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.ohai.config;
|
||||
|
||||
import static org.jclouds.ohai.Util.OhaiUtils.ohaiAutomaticAttributeBinder;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.net.SocketException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.chef.config.ChefParserModule;
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.ohai.Automatic;
|
||||
import org.jclouds.ohai.config.multibindings.MapBinder;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.util.Providers;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code OhaiModule}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ohai.OhaiModuleTest")
|
||||
public class OhaiModuleTest {
|
||||
|
||||
@Test
|
||||
public void test() throws SocketException {
|
||||
|
||||
final Properties sysProperties = new Properties();
|
||||
|
||||
sysProperties.setProperty("os.name", "Mac OS X");
|
||||
sysProperties.setProperty("os.version", "10.3.0");
|
||||
sysProperties.setProperty("user.name", "user");
|
||||
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule(), new OhaiModule() {
|
||||
@Override
|
||||
protected Long millis() {
|
||||
return 127999291932529l;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties systemProperties() {
|
||||
return sysProperties;
|
||||
}
|
||||
|
||||
});
|
||||
Ohai ohai = injector.getInstance(Ohai.class);
|
||||
Json json = injector.getInstance(Json.class);
|
||||
|
||||
assertEquals(
|
||||
json.toJson(ohai.ohai.get(), new TypeLiteral<Map<String, JsonBall>>() {
|
||||
}.getType()),
|
||||
"{\"ohai_time\":127999291932529,\"platform\":\"macosx\",\"platform_version\":\"10.3.0\",\"current_user\":\"user\",\"jvm\":{\"system\":{\"user.name\":\"user\",\"os.version\":\"10.3.0\",\"os.name\":\"Mac OS X\"}}}");
|
||||
}
|
||||
|
||||
public void test2modules() throws SocketException {
|
||||
|
||||
final Properties sysProperties = new Properties();
|
||||
|
||||
sysProperties.setProperty("os.name", "Mac OS X");
|
||||
sysProperties.setProperty("os.version", "10.3.0");
|
||||
sysProperties.setProperty("user.name", "user");
|
||||
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule(), new OhaiModule() {
|
||||
@Override
|
||||
protected Long millis() {
|
||||
return 1279992919l;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties systemProperties() {
|
||||
return sysProperties;
|
||||
}
|
||||
|
||||
}, new AbstractModule() {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
MapBinder<String, Supplier<JsonBall>> mapbinder = ohaiAutomaticAttributeBinder(binder());
|
||||
mapbinder.addBinding("test").toProvider(
|
||||
Providers.of(Suppliers.ofInstance(new JsonBall("{\"prop1\":\"test1\"}"))));
|
||||
}
|
||||
|
||||
}, new AbstractModule() {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
MapBinder<String, Supplier<JsonBall>> mapbinder = ohaiAutomaticAttributeBinder(binder());
|
||||
mapbinder.addBinding("test").toProvider(
|
||||
Providers.of(Suppliers.ofInstance(new JsonBall("{\"prop2\":\"test2\"}"))));
|
||||
}
|
||||
|
||||
});
|
||||
Ohai ohai = injector.getInstance(Ohai.class);
|
||||
Json json = injector.getInstance(Json.class);
|
||||
|
||||
assertEquals(
|
||||
json.toJson(ohai.ohai.get(), new TypeLiteral<Map<String, JsonBall>>() {
|
||||
}.getType()),
|
||||
"{\"ohai_time\":1279992919,\"platform\":\"macosx\",\"platform_version\":\"10.3.0\",\"current_user\":\"user\",\"test\":{\"prop1\":\"test1\",\"prop2\":\"test2\"},\"jvm\":{\"system\":{\"user.name\":\"user\",\"os.version\":\"10.3.0\",\"os.name\":\"Mac OS X\"}}}");
|
||||
}
|
||||
|
||||
static class Ohai {
|
||||
private Supplier<Map<String, JsonBall>> ohai;
|
||||
|
||||
@Inject
|
||||
public Ohai(@Automatic Supplier<Map<String, JsonBall>> ohai) {
|
||||
this.ohai = ohai;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.ohai.functions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jclouds.chef.config.ChefParserModule;
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code NestSlashKeys}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", sequential = true, testName = "ohai.NestSlashKeysTest")
|
||||
public class NestSlashKeysTest {
|
||||
|
||||
private NestSlashKeys converter;
|
||||
private Json json;
|
||||
|
||||
@BeforeTest
|
||||
protected void setUpInjector() throws IOException {
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule());
|
||||
converter = injector.getInstance(NestSlashKeys.class);
|
||||
json = injector.getInstance(Json.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBase() {
|
||||
assertEquals(json.toJson(converter.apply(ImmutableMultimap.<String, Supplier<JsonBall>> of("java", Suppliers
|
||||
.ofInstance(new JsonBall("java"))))), "{\"java\":\"java\"}");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testIllegal() {
|
||||
json.toJson(converter.apply(ImmutableMultimap.<String, Supplier<JsonBall>> of("java", Suppliers
|
||||
.ofInstance(new JsonBall("java")), "java/system", Suppliers.ofInstance(new JsonBall("system")))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOne() {
|
||||
assertEquals(json.toJson(converter.apply(ImmutableMultimap.<String, Supplier<JsonBall>> of("java", Suppliers
|
||||
.ofInstance(new JsonBall("{\"time\":\"time\"}")), "java/system", Suppliers
|
||||
.ofInstance(new JsonBall("system"))))), "{\"java\":{\"time\":\"time\",\"system\":\"system\"}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneDuplicate() {
|
||||
assertEquals(json.toJson(converter.apply(ImmutableMultimap.<String, Supplier<JsonBall>> of("java", Suppliers
|
||||
.ofInstance(new JsonBall("{\"time\":\"time\"}")), "java", Suppliers.ofInstance(new JsonBall(
|
||||
"{\"system\":\"system\"}"))))), "{\"java\":{\"time\":\"time\",\"system\":\"system\"}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge() {
|
||||
assertEquals(json.toJson(converter.apply(ImmutableMultimap.<String, Supplier<JsonBall>> of("java", Suppliers
|
||||
.ofInstance(new JsonBall("{\"time\":{\"1\":\"hello\"}}")), "java/time", Suppliers.ofInstance(new JsonBall(
|
||||
"{\"2\":\"goodbye\"}"))))), "{\"java\":{\"time\":{\"1\":\"hello\",\"2\":\"goodbye\"}}}");
|
||||
}
|
||||
@Test
|
||||
public void testMergeNestedTwice() {
|
||||
assertEquals(json.toJson(converter.apply(ImmutableMultimap.<String, Supplier<JsonBall>> of("java", Suppliers
|
||||
.ofInstance(new JsonBall("{\"time\":{\"1\":\"hello\"}}")), "java", Suppliers.ofInstance(new JsonBall(
|
||||
"{\"time\":{\"2\":\"goodbye\"}}"))))), "{\"java\":{\"time\":{\"1\":\"hello\",\"2\":\"goodbye\"}}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceList() {
|
||||
assertEquals(json.toJson(converter.apply(ImmutableMultimap.<String, Supplier<JsonBall>> of("java", Suppliers
|
||||
.ofInstance(new JsonBall("{\"time\":{\"1\":[\"hello\"]}}")), "java/time", Suppliers.ofInstance(new JsonBall(
|
||||
"{\"1\":[\"goodbye\"]}"))))), "{\"java\":{\"time\":{\"1\":[\"goodbye\"]}}}");
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.ohai.plugins;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.net.SocketException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.chef.config.ChefParserModule;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.ohai.config.WhiteListCompliantOhaiJVMModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code WhiteListCompliantJVM}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ohai.WhiteListCompliantJVMTest")
|
||||
public class WhiteListCompliantJVMTest {
|
||||
|
||||
@Test
|
||||
public void test() throws SocketException {
|
||||
|
||||
final Properties sysProperties = new Properties();
|
||||
|
||||
sysProperties.setProperty("os.name", "Mac OS X");
|
||||
sysProperties.setProperty("os.version", "10.3.0");
|
||||
sysProperties.setProperty("user.name", "user");
|
||||
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule(),
|
||||
new WhiteListCompliantOhaiJVMModule() {
|
||||
@Override
|
||||
protected Long nanoTime() {
|
||||
return 1279992919325290l;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties systemProperties() {
|
||||
return sysProperties;
|
||||
}
|
||||
|
||||
});
|
||||
Json json = injector.getInstance(Json.class);
|
||||
WhiteListCompliantJVM WhiteListCompliantJVM = injector.getInstance(WhiteListCompliantJVM.class);
|
||||
|
||||
assertEquals(
|
||||
json.toJson(WhiteListCompliantJVM.get()),
|
||||
"{\"ohai_time\":1279992919.32529,\"java\":{\"user.name\":\"user\",\"os.version\":\"10.3.0\",\"os.name\":\"Mac OS X\"},\"platform\":\"macosx\",\"platform_version\":\"10.3.0\",\"current_user\":\"user\"}");
|
||||
|
||||
}
|
||||
}
|
|
@ -38,16 +38,16 @@ import org.testng.annotations.Test;
|
|||
*/
|
||||
@Test(groups = "unit", sequential = true, testName = "ohai.OhaiUtilsTest")
|
||||
public class OhaiUtilsTest {
|
||||
public static long nanotime = 1280251180727244000l;
|
||||
public static String nanotimeString = "1280251180727.244";
|
||||
public static long millis = 1280251180727l;
|
||||
public static String millisString = "1280251180727";
|
||||
public static Date now = new Date(1280251180727l);
|
||||
|
||||
public void testToOhaiTime() {
|
||||
assertEquals(OhaiUtils.toOhaiTime(nanotime).toString(), nanotimeString);
|
||||
assertEquals(OhaiUtils.toOhaiTime(millis).toString(), millisString);
|
||||
}
|
||||
|
||||
public void testFromOhaiTime() {
|
||||
assertEquals(OhaiUtils.fromOhaiTime(new JsonBall(nanotimeString)), now);
|
||||
assertEquals(OhaiUtils.fromOhaiTime(new JsonBall(millisString)), now);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,13 @@
|
|||
<artifactId>jclouds-chef</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-servlet_2.5_spec</artifactId>
|
||||
|
|
|
@ -28,18 +28,19 @@ import static org.jclouds.chef.reference.ChefConstants.CHEF_SERVICE_CLIENT;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import org.jclouds.chef.ChefAsyncClient;
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.ChefContext;
|
||||
import org.jclouds.chef.ChefContextFactory;
|
||||
import org.jclouds.chef.ChefService;
|
||||
import org.jclouds.chef.reference.ChefConstants;
|
||||
import org.jclouds.chef.servlet.functions.InitParamsToProperties;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.logging.jdk.JDKLogger;
|
||||
import org.jclouds.rest.RestContextFactory;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
/**
|
||||
* Registers a new node in Chef and binds its name to
|
||||
|
@ -58,12 +59,12 @@ public class ChefRegistrationListener implements ServletContextListener {
|
|||
public void contextInitialized(ServletContextEvent servletContextEvent) {
|
||||
try {
|
||||
logger.debug("starting initialization");
|
||||
Properties overrides = InitParamsToProperties.INSTANCE.apply(servletContextEvent);
|
||||
Properties overrides = InitParamsToProperties.INSTANCE.apply(servletContextEvent.getServletContext());
|
||||
String role = getInitParam(servletContextEvent, CHEF_ROLE);
|
||||
|
||||
logger.trace("creating client connection");
|
||||
|
||||
ChefService client = createService(overrides);
|
||||
ChefService client = createService(overrides, servletContextEvent);
|
||||
logger.debug("created client connection");
|
||||
|
||||
String nodeName;
|
||||
|
@ -103,9 +104,15 @@ public class ChefRegistrationListener implements ServletContextListener {
|
|||
return nodeName;
|
||||
}
|
||||
|
||||
private ChefService createService(Properties props) {
|
||||
return ((ChefContext) new RestContextFactory().<ChefClient, ChefAsyncClient> createContext("chef", props))
|
||||
.getChefService();
|
||||
private ChefService createService(Properties props, final ServletContextEvent servletContextEvent) {
|
||||
return new ChefContextFactory().createContext(ImmutableSet.of(new AbstractModule() {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(ServletContext.class).toInstance(servletContextEvent.getServletContext());
|
||||
}
|
||||
|
||||
}), props).getChefService();
|
||||
}
|
||||
|
||||
private static String getInitParam(ServletContextEvent servletContextEvent, String name) {
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Enumeration;
|
|||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
|
@ -31,16 +31,16 @@ import com.google.common.base.Function;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class InitParamsToProperties implements Function<ServletContextEvent, Properties> {
|
||||
public class InitParamsToProperties implements Function<ServletContext, Properties> {
|
||||
|
||||
public static final InitParamsToProperties INSTANCE = new InitParamsToProperties();
|
||||
|
||||
public Properties apply(ServletContextEvent servletContextEvent) {
|
||||
public Properties apply(ServletContext servletContext) {
|
||||
Properties overrides = new Properties();
|
||||
Enumeration<?> e = servletContextEvent.getServletContext().getInitParameterNames();
|
||||
Enumeration<?> e = servletContext.getInitParameterNames();
|
||||
while (e.hasMoreElements()) {
|
||||
String propertyName = e.nextElement().toString();
|
||||
overrides.setProperty(propertyName, servletContextEvent.getServletContext().getInitParameter(propertyName));
|
||||
overrides.setProperty(propertyName, servletContext.getInitParameter(propertyName));
|
||||
}
|
||||
return overrides;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.servlet.config;
|
||||
|
||||
|
||||
import static org.jclouds.ohai.Util.OhaiUtils.ohaiAutomaticAttributeBinder;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
import org.jclouds.ohai.config.multibindings.MapBinder;
|
||||
import org.jclouds.ohai.servlet.suppliers.ServletContextInfoSupplier;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
/**
|
||||
* Wires the components needed to parse ohai data
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ServletOhaiModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
MapBinder<String, Supplier<JsonBall>> mapbinder = ohaiAutomaticAttributeBinder(binder());
|
||||
mapbinder.addBinding("webapp").to(ServletContextInfoSupplier.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.servlet.suppliers;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.jclouds.chef.servlet.functions.InitParamsToProperties;
|
||||
import org.jclouds.json.Json;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ServletContextInfoSupplier extends ServletContextSupplier {
|
||||
private final InitParamsToProperties converter;
|
||||
private final Json json;
|
||||
|
||||
@Inject
|
||||
public ServletContextInfoSupplier(ServletContext servletContext, InitParamsToProperties converter, Json json) {
|
||||
super(servletContext);
|
||||
this.converter = converter;
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String provideJson(ServletContext servletContext) {
|
||||
return String.format("{\"server_info\":\"%s\",\"init_params\":%s}", servletContext.getServerInfo(), json
|
||||
.toJson(converter.apply(servletContext)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ohai.servlet.suppliers;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.jclouds.domain.JsonBall;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public abstract class ServletContextSupplier implements Supplier<JsonBall> {
|
||||
private final ServletContext servletContext;
|
||||
|
||||
@Inject
|
||||
public ServletContextSupplier(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonBall get() {
|
||||
String path = servletContext.getContextPath();
|
||||
if (path == null || path.equals(""))
|
||||
path = "/";
|
||||
return new JsonBall(String.format("{\"%s\":%s}", path, provideJson(servletContext)));
|
||||
}
|
||||
|
||||
protected abstract String provideJson(ServletContext servletContext);
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.chef.servlet.suppliers;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.jclouds.chef.servlet.functions.InitParamsToProperties;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.ohai.servlet.config.ServletOhaiModule;
|
||||
import org.jclouds.ohai.servlet.suppliers.ServletContextInfoSupplier;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
|
||||
@Test(groups = "unit", testName = "chef.ServletContextInfoSupplierTest")
|
||||
public class ServletContextInfoSupplierTest {
|
||||
|
||||
@Test
|
||||
public void testApply() {
|
||||
|
||||
final ServletContext servletContext = createMock(ServletContext.class);
|
||||
final InitParamsToProperties converter = createMock(InitParamsToProperties.class);
|
||||
Properties props = new Properties();
|
||||
props.setProperty("foo", "bar");
|
||||
|
||||
expect(servletContext.getContextPath()).andReturn("path");
|
||||
expect(servletContext.getServerInfo()).andReturn("serverinfo");
|
||||
expect(converter.apply(servletContext)).andReturn(props);
|
||||
|
||||
replay(servletContext);
|
||||
replay(converter);
|
||||
|
||||
Injector injector = Guice.createInjector(new GsonModule(), new ServletOhaiModule() {
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
protected ServletContext provideServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
protected InitParamsToProperties provideInitParamsToProperties() {
|
||||
return converter;
|
||||
}
|
||||
});
|
||||
|
||||
Json json = injector.getInstance(Json.class);
|
||||
ServletContextInfoSupplier ohai = injector.getInstance(ServletContextInfoSupplier.class);
|
||||
assertEquals(json.toJson(ohai.get()),
|
||||
"{\"path\":{\"server_info\":\"serverinfo\",\"init_params\":{\"foo\":\"bar\"}}}");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyNullPath() {
|
||||
|
||||
final ServletContext servletContext = createMock(ServletContext.class);
|
||||
final InitParamsToProperties converter = createMock(InitParamsToProperties.class);
|
||||
Properties props = new Properties();
|
||||
props.setProperty("foo", "bar");
|
||||
|
||||
expect(servletContext.getContextPath()).andReturn(null);
|
||||
expect(servletContext.getServerInfo()).andReturn("serverinfo");
|
||||
expect(converter.apply(servletContext)).andReturn(props);
|
||||
|
||||
replay(servletContext);
|
||||
replay(converter);
|
||||
|
||||
Injector injector = Guice.createInjector(new GsonModule(), new ServletOhaiModule() {
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
protected ServletContext provideServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
protected InitParamsToProperties provideInitParamsToProperties() {
|
||||
return converter;
|
||||
}
|
||||
});
|
||||
|
||||
Json json = injector.getInstance(Json.class);
|
||||
ServletContextInfoSupplier ohai = injector.getInstance(ServletContextInfoSupplier.class);
|
||||
assertEquals(json.toJson(ohai.get()),
|
||||
"{\"/\":{\"server_info\":\"serverinfo\",\"init_params\":{\"foo\":\"bar\"}}}");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyEmptyPath() {
|
||||
|
||||
final ServletContext servletContext = createMock(ServletContext.class);
|
||||
final InitParamsToProperties converter = createMock(InitParamsToProperties.class);
|
||||
Properties props = new Properties();
|
||||
props.setProperty("foo", "bar");
|
||||
|
||||
expect(servletContext.getContextPath()).andReturn("");
|
||||
expect(servletContext.getServerInfo()).andReturn("serverinfo");
|
||||
expect(converter.apply(servletContext)).andReturn(props);
|
||||
|
||||
replay(servletContext);
|
||||
replay(converter);
|
||||
|
||||
Injector injector = Guice.createInjector(new GsonModule(), new ServletOhaiModule() {
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
protected ServletContext provideServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
protected InitParamsToProperties provideInitParamsToProperties() {
|
||||
return converter;
|
||||
}
|
||||
});
|
||||
|
||||
Json json = injector.getInstance(Json.class);
|
||||
ServletContextInfoSupplier ohai = injector.getInstance(ServletContextInfoSupplier.class);
|
||||
assertEquals(json.toJson(ohai.get()),
|
||||
"{\"/\":{\"server_info\":\"serverinfo\",\"init_params\":{\"foo\":\"bar\"}}}");
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue