org.glassfish.hk2.utilities.BuilderHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.hk2.utilities;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.glassfish.hk2.api.ActiveDescriptor;
import org.glassfish.hk2.api.Descriptor;
import org.glassfish.hk2.api.DescriptorType;
import org.glassfish.hk2.api.DescriptorVisibility;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.Filter;
import org.glassfish.hk2.api.IndexedFilter;
import org.glassfish.hk2.api.Metadata;
import org.glassfish.hk2.api.MultiException;
import org.glassfish.hk2.api.PerLookup;
import org.glassfish.hk2.api.ProxyForSameScope;
import org.glassfish.hk2.api.UseProxy;
import org.glassfish.hk2.api.Visibility;
import org.glassfish.hk2.internal.ActiveDescriptorBuilderImpl;
import org.glassfish.hk2.internal.ConstantActiveDescriptor;
import org.glassfish.hk2.internal.DescriptorBuilderImpl;
import org.glassfish.hk2.internal.IndexedFilterImpl;
import org.glassfish.hk2.internal.SpecificFilterImpl;
import org.glassfish.hk2.internal.StarFilter;
import org.glassfish.hk2.utilities.reflection.ReflectionHelper;
import org.jvnet.hk2.annotations.Contract;
import org.jvnet.hk2.annotations.Service;
/**
* This class is used to generate DescriptorBuilders to be used
* as a simple mechanism to create a Filter or Descriptor.
*/
public class BuilderHelper {
/**
* Returns an indexed filter that will return all descriptors that
* have contract as an advertised contract
*
* @param contract The advertised contract to look for
* @return The indexed filter that can be used to calls to ServiceLocator methods
*/
public static IndexedFilter createContractFilter(String contract) {
return new IndexedFilterImpl(contract, null);
}
/**
* Returns an indexed filter that will return all descriptors that
* have the given name
*
* @param name The name to look for
* @return The indexed filter that can be used to calls to ServiceLocator methods
*/
public static IndexedFilter createNameFilter(String name) {
return new IndexedFilterImpl(null, name);
}
/**
* Returns an indexed filter that will return all descriptors that
* have the given name and given contract
*
* @param contract The advertised contract to look for
* @param name The name to look for
* @return The indexed filter that can be used to calls to ServiceLocator methods
*/
public static IndexedFilter createNameAndContractFilter(String contract, String name) {
return new IndexedFilterImpl(contract, name);
}
/** The key for the name field of the tokenized string */
public final static String NAME_KEY = "name";
/** The key for the qualifier field of the tokenized string */
public final static String QUALIFIER_KEY = "qualifier";
/** The token separator */
public final static String TOKEN_SEPARATOR = ";";
/**
* Creates a filter from a token string as per the following rules.
* - The token delimiter is ;
* - The first token is the contract. If the tokenString starts with ; there is no contract
* - All other tokens are in key = value form (with = being the separator)
* - A valid key that can appear only once is "name"
* - A valid key that can appear any number of times is "qualifier"
*
*
* The following are examples of valid token strings:
* - com.acme.product.RocketShoes
* - com.acme.product.Sneakers;name=Nike
* - com.acme.product.Sneakers;name=Nike;qualifier=com.acme.color.Red;qualifier=com.acme.style.HighTop
* - ;name=Narcissus
*
*
* @param tokenString A non-null string following the rules stated above
* @return A filter that will match the given string
* @throws IllegalArgumentException If the token string is invalid in some way
*/
public static IndexedFilter createTokenizedFilter(String tokenString) throws IllegalArgumentException {
if (tokenString == null) throw new IllegalArgumentException("null passed to createTokenizedFilter");
StringTokenizer st = new StringTokenizer(tokenString, TOKEN_SEPARATOR);
String contract = null;
String name = null;
final Set qualifiers = new LinkedHashSet();
boolean firstToken = true;
if (tokenString.startsWith(TOKEN_SEPARATOR)) {
firstToken = false;
}
while (st.hasMoreTokens()) {
String token = st.nextToken();
if (firstToken) {
firstToken = false;
if (token.length() <= 0) continue;
contract = token;
}
else {
int index = token.indexOf('=');
if (index < 0) {
throw new IllegalArgumentException("No = character found in token " + token);
}
String leftHandSide = token.substring(0, index);
String rightHandSide = token.substring(index + 1);
if (rightHandSide.length() <= 0) {
throw new IllegalArgumentException("No value found in token " + token);
}
if (NAME_KEY.equals(leftHandSide)) {
name = rightHandSide;
}
else if (QUALIFIER_KEY.equals(leftHandSide)) {
qualifiers.add(rightHandSide);
}
else {
throw new IllegalArgumentException("Unknown key: " + leftHandSide);
}
}
}
final String fContract = contract;
final String fName = name;
return new IndexedFilter() {
@Override
public boolean matches(Descriptor d) {
if (qualifiers.isEmpty()) return true;
return d.getQualifiers().containsAll(qualifiers);
}
@Override
public String getAdvertisedContract() {
return fContract;
}
@Override
public String getName() {
return fName;
}
@Override
public String toString() {
String cField = (fContract == null) ? "" : fContract;
String nField = (fName == null) ? "" : ";name=" + fName;
StringBuffer sb = new StringBuffer();
for (String q : qualifiers) {
sb.append(";qualifier=" + q);
}
return "TokenizedFilter(" + cField + nField + sb.toString() + ")";
}
};
}
/**
* This method creates a filter that will match one and only one descriptor. The passed
* in descriptor must have both its serviceID and locatorId filled in, or else this
* method will throw an IllegalArgumentException
*
* @param descriptor The descriptor from which to create a filter
* @return A filter to use that will match this descriptor exactly
*/
public static IndexedFilter createSpecificDescriptorFilter(Descriptor descriptor) {
String contract = ServiceLocatorUtilities.getBestContract(descriptor);
String name = descriptor.getName();
if (descriptor.getServiceId() == null) {
throw new IllegalArgumentException("The descriptor must have a specific service ID");
}
if (descriptor.getLocatorId() == null) {
throw new IllegalArgumentException("The descriptor must have a specific locator ID");
}
return new SpecificFilterImpl(contract, name,
descriptor.getServiceId(),
descriptor.getLocatorId());
}
/**
* Returns a filter of type Descriptor that matches
* all descriptors
*
* @return A filter that matches all descriptors
*/
public static Filter allFilter() {
return StarFilter.getDescriptorFilter();
}
/**
* This method links an implementation class with a {@link DescriptorBuilder}, to
* be used to further build the {@link Descriptor}.
*
* @param implementationClass The fully qualified name of the implementation
* class to be associated with the DescriptorBuilder.
* @param addToContracts if true, this implementation class will be added to the
* list of contracts
*
* @return A {@link DescriptorBuilder} that can be used to further build up the
* {@link Descriptor}
* @throws IllegalArgumentException if implementationClass is null
*/
public static DescriptorBuilder link(String implementationClass, boolean addToContracts) throws IllegalArgumentException {
if (implementationClass == null) throw new IllegalArgumentException();
return new DescriptorBuilderImpl(implementationClass, addToContracts);
}
/**
* This method links an implementation class with a {@link DescriptorBuilder}, to
* be used to further build the {@link Descriptor}. This method will automatically
* put the implementationClass into the list of advertised contracts.
*
* @param implementationClass The fully qualified name of the implementation
* class to be associated with the PredicateBuilder.
*
* @return A {@link DescriptorBuilder} that can be used to further build up the
* {@link Descriptor}
* @throws IllegalArgumentException if implementationClass is null
*/
public static DescriptorBuilder link(String implementationClass) throws IllegalArgumentException {
return link(implementationClass, true);
}
/**
* This method links an implementation class with a {@link DescriptorBuilder}, to
* be used to further build the {@link Descriptor}
*
* @param implementationClass The implementation class to be associated
* with the {@link DescriptorBuilder}.
* @param addToContracts true if this impl class should be automatically added to
* the list of contracts
* @return A {@link DescriptorBuilder} that can be used to further build up the
* {@link Descriptor}
* @throws IllegalArgumentException if implementationClass is null
*/
public static DescriptorBuilder link(Class> implementationClass, boolean addToContracts) throws IllegalArgumentException {
if (implementationClass == null) throw new IllegalArgumentException();
DescriptorBuilder builder = link(implementationClass.getName(), addToContracts);
return builder;
}
/**
* This method links an implementation class with a {@link DescriptorBuilder}, to
* be used to further build the {@link Descriptor}.
*
* @param implementationClass The implementation class to be associated
* with the {@link DescriptorBuilder}.
* @return A {@link DescriptorBuilder} that can be used to further build up the
* {@link Descriptor}
* @throws IllegalArgumentException if implementationClass is null
*/
public static DescriptorBuilder link(Class> implementationClass) throws IllegalArgumentException {
if (implementationClass == null) throw new IllegalArgumentException();
boolean isFactory = (Factory.class.isAssignableFrom(implementationClass));
DescriptorBuilder db = link(implementationClass, !isFactory);
return db;
}
/**
* This method creates an {@link ActiveDescriptorBuilder}, whose job it
* is to create an unreified {@link ActiveDescriptor}. The implementation
* class given will NOT automatically be added to the set of contracts
* of the {@link ActiveDescriptor}.
*
* @param implementationClass The implementation class to be associated
* with the {@link ActiveDescriptorBuilder}.
* @return A {@link ActiveDescriptorBuilder} that can be used to further build up the
* {@link Descriptor}
* @throws IllegalArgumentException if implementationClass is null
*/
public static ActiveDescriptorBuilder activeLink(Class> implementationClass) throws IllegalArgumentException {
if (implementationClass == null) throw new IllegalArgumentException();
return new ActiveDescriptorBuilderImpl(implementationClass);
}
/**
* This creates a descriptor that will always return the given object. The
* set of types in the advertised contracts will contain the class of the
* constant along with:
* - Any superclass of the constant marked with {@link Contract}
* - Any interface of the constant marked with {@link Contract}
*
*
* @param constant The non-null constant that should always be returned from
* the create method of this ActiveDescriptor.
* @return The descriptor returned can be used in calls to
* DynamicConfiguration.addActiveDescriptor
* @throws IllegalArgumentException if constant is null
*/
public static AbstractActiveDescriptor createConstantDescriptor(T constant) {
if (constant == null) throw new IllegalArgumentException();
Set contracts = ReflectionHelper.getAdvertisedTypesFromObject(constant, Contract.class);
return createConstantDescriptor(constant,
ReflectionHelper.getName(constant.getClass()),
contracts.toArray(new Type[contracts.size()]));
}
/**
* This creates a descriptor that will always return the given object.
* The advertised contracts is given in the incoming parameter and the
* name on the descriptor also comes from the incoming parameter.
*
* @param constant The non-null constant that should always be returned from
* the create method of this ActiveDescriptor.
* @param name The possibly null name that should be associated with this constant descriptor
* @param contracts The possibly empty set of contracts that should be associated with this
* descriptor
* @return The descriptor returned can be used in calls to
* DynamicConfiguration.addActiveDescriptor
* @throws IllegalArgumentException if constant is null
*/
public static AbstractActiveDescriptor createConstantDescriptor(T constant, String name, Type... contracts) {
if (constant == null) throw new IllegalArgumentException();
Annotation scope =
ReflectionHelper.getScopeAnnotationFromObject(constant);
Class extends Annotation> scopeClass = (scope == null) ? PerLookup.class :
scope.annotationType();
Set qualifiers =
ReflectionHelper.getQualifiersFromObject(constant);
Map> metadata = new HashMap>();
if (scope != null) {
getMetadataValues(scope, metadata);
}
for (Annotation qualifier : qualifiers) {
getMetadataValues(qualifier, metadata);
}
Set contractsAsSet = new LinkedHashSet();
for (Type cType : contracts) {
contractsAsSet.add(cType);
}
Boolean proxy = null;
UseProxy up = constant.getClass().getAnnotation(UseProxy.class);
if (up != null) {
proxy = up.value();
}
Boolean proxyForSameScope = null;
ProxyForSameScope pfss = constant.getClass().getAnnotation(ProxyForSameScope.class);
if (pfss != null) {
proxyForSameScope = pfss.value();
}
DescriptorVisibility visibility = DescriptorVisibility.NORMAL;
Visibility vi = constant.getClass().getAnnotation(Visibility.class);
if (vi != null) {
visibility = vi.value();
}
String classAnalysisName = null;
Service service = constant.getClass().getAnnotation(Service.class);
if (service != null) {
classAnalysisName = service.analyzer();
}
return new ConstantActiveDescriptor(
constant,
contractsAsSet,
scopeClass,
name,
qualifiers,
visibility,
proxy,
proxyForSameScope,
classAnalysisName,
metadata);
}
/**
* This returns a DescriptorImpl based on the given class. The returned
* descriptor will include the class itself as an advertised contract and
* all implemented interfaces that are marked @Contract
*
* @param clazz The class to analyze
* @return The DescriptorImpl corresponding to this class
*/
public static DescriptorImpl createDescriptorFromClass(Class> clazz) {
if (clazz == null) return new DescriptorImpl();
Set contracts = ReflectionHelper.getContractsFromClass(clazz, Contract.class);
String name = ReflectionHelper.getName(clazz);
String scope = ReflectionHelper.getScopeFromClass(clazz, PerLookup.class).getName();
Set qualifiers = ReflectionHelper.getQualifiersFromClass(clazz);
DescriptorType type = DescriptorType.CLASS;
if (Factory.class.isAssignableFrom(clazz)) {
type = DescriptorType.PROVIDE_METHOD;
}
Boolean proxy = null;
UseProxy up = clazz.getAnnotation(UseProxy.class);
if (up != null) {
proxy = Boolean.valueOf(up.value());
}
Boolean proxyForSameScope = null;
ProxyForSameScope pfss = clazz.getAnnotation(ProxyForSameScope.class);
if (pfss != null) {
proxyForSameScope = Boolean.valueOf(pfss.value());
}
DescriptorVisibility visibility = DescriptorVisibility.NORMAL;
Visibility vi = clazz.getAnnotation(Visibility.class);
if (vi != null) {
visibility = vi.value();
}
// TODO: Can we get metadata from @Service?
return new DescriptorImpl(
contracts,
name,
scope,
clazz.getName(),
new HashMap>(),
qualifiers,
type,
visibility,
null,
0,
proxy,
proxyForSameScope,
null,
null,
null);
}
/**
* Makes a deep copy of the incoming descriptor
*
* @param copyMe The descriptor to copy
* @return A new descriptor with all fields copied
*/
public static DescriptorImpl deepCopyDescriptor(Descriptor copyMe) {
return new DescriptorImpl(copyMe);
}
/**
* This is a helper method that gets the metadata values from the
* {@link Metadata} annotations found in an annotation.
*
* @param annotation The annotation to find {@link Metadata} values
* from. May not be null.
* @param metadata A non-null metadata map. The values found in the
* annotation will be added to this metadata map
* @throws IllegalArgumentException if annotation or metadata is null
* @throws MultiException if there was an error invoking the methods of the annotation
*/
public static void getMetadataValues(Annotation annotation, Map> metadata) {
if (annotation == null || metadata == null) {
throw new IllegalArgumentException();
}
final Class extends Annotation> annotationClass = annotation.annotationType();
Method annotationMethods[] = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Method[] run() {
return annotationClass.getDeclaredMethods();
}
});
for (Method annotationMethod : annotationMethods) {
Metadata metadataAnno = annotationMethod.getAnnotation(Metadata.class);
if (metadataAnno == null) continue;
String key = metadataAnno.value();
Object addMe;
try {
addMe = ReflectionHelper.invoke(annotation, annotationMethod, new Object[0], false);
}
catch (Throwable th) {
throw new MultiException(th);
}
if (addMe == null) continue;
String addMeString;
if (addMe instanceof Class) {
addMeString = ((Class>) addMe).getName();
}
else {
addMeString = addMe.toString();
}
ReflectionHelper.addMetadata(metadata, key, addMeString);
}
}
}