http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java deleted file mode 100644 index 9151381..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2006, 2008, 2009, 2010, 2011 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc; - -/** - * Object passed into a service contributor method that allows the method provide contributed values to the service's - * configuration. - * <p/> - * A service can <em>collect</em> contributions in three different ways: - * <ul> - * <li>As an un-ordered collection of values</li> - * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li> - * <li>As a map of keys and values - * </ul> - * <p/> - * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions - * must be compatible with the type, or be {@linkplain org.apache.tapestry5.ioc.services.TypeCoercer coercable} to the type. - * - * @see org.apache.tapestry5.ioc.annotations.Contribute - * @see org.apache.tapestry5.ioc.annotations.UsesConfiguration - */ -public interface OrderedConfiguration<T> -{ - /** - * Adds an ordered object to a service's contribution. Each object has an id (which must be unique). Optionally, - * pre-requisites (a list of ids that must precede this object) and post-requisites (ids that must follow) can be - * provided. - * <p/> - * <p>If no constraints are supplied, then an implicit constraint is supplied: after the previously - * contributed id <em>within the same contribution method</em>. - * - * @param id a unique id for the object; the id will be fully qualified with the contributing module's id - * @param constraints used to order the object relative to other contributed objects - * @param object to add to the service's configuration - */ - void add(String id, T object, String... constraints); - - /** - * Overrides a normally contributed object. Each override must match a single normally contributed object. - * - * @param id identifies object to override - * @param object overriding object (may be null) - * @param constraints constraints for the overridden object, replacing constraints for the original object (even if - * omitted, in which case the override object will have no ordering constraints) - * @since 5.1.0.0 - */ - void override(String id, T object, String... constraints); - - /** - * Adds an ordered object by instantiating (with dependencies) the indicated class. When the configuration type is - * an interface and the class to be contributed is a local file, - * then a reloadable proxy for the class will be created and contributed. - * - * @param id of contribution (used for ordering) - * @param clazz class to instantiate - * @param constraints used to order the object relative to other contributed objects - * @since 5.1.0.0 - */ - void addInstance(String id, Class<? extends T> clazz, String... constraints); - - /** - * Instantiates an object and adds it as an override. When the configuration type is an interface and the class to - * be contributed is a local file, then a reloadable proxy for the class will be created and contributed. - * - * @param id of object to override - * @param clazz to instantiate - * @param constraints constraints for the overridden object, replacing constraints for the original object (even if - * omitted, in which case the override object will have no ordering constraints) - * @since 5.1.0.0 - */ - void overrideInstance(String id, Class<? extends T> clazz, String... constraints); -}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java deleted file mode 100644 index 2acfd0d..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2008 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.ioc.AnnotationProvider; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AccessibleObject; - -/** - * Provides access to annotations of an accessable object such as a {@link java.lang.reflect.Method} or {@link - * java.lang.reflect.Field}. - */ -public class AccessableObjectAnnotationProvider implements AnnotationProvider -{ - private final AccessibleObject object; - - public AccessableObjectAnnotationProvider(AccessibleObject object) - { - this.object = object; - } - - @Override - public <T extends Annotation> T getAnnotation(Class<T> annotationClass) - { - return object.getAnnotation(annotationClass); - } - - @Override - public String toString() - { - return String.format("AnnotationProvider[%s]", object); - } -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java deleted file mode 100644 index 49b0b15..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2008 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.ioc.AnnotationProvider; - -import java.lang.annotation.Annotation; -import java.util.List; - -/** - * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}. - */ -public class AnnotationProviderChain implements AnnotationProvider -{ - private final AnnotationProvider[] providers; - - public AnnotationProviderChain(AnnotationProvider[] providers) - { - this.providers = providers; - } - - /** - * Creates an AnnotationProvider from the list of providers. Returns either an {@link AnnotationProviderChain} or - * the sole element in the list. - */ - public static AnnotationProvider create(List<AnnotationProvider> providers) - { - int size = providers.size(); - - if (size == 1) return providers.get(0); - - return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()])); - } - - @Override - public <T extends Annotation> T getAnnotation(Class<T> annotationClass) - { - for (AnnotationProvider p : providers) - { - T result = p.getAnnotation(annotationClass); - - if (result != null) return result; - } - - return null; - } -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java deleted file mode 100644 index af4bd7d..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2006, 2007, 2008, 2010, 2011, 2012 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap; - -import java.beans.PropertyDescriptor; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.internal.util.GenericsUtils; -import org.apache.tapestry5.ioc.internal.util.InternalUtils; -import org.apache.tapestry5.ioc.services.ClassPropertyAdapter; -import org.apache.tapestry5.ioc.services.PropertyAdapter; - -public class ClassPropertyAdapterImpl implements ClassPropertyAdapter -{ - private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap(); - - private final Class beanType; - - public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> descriptors) - { - this.beanType = beanType; - - // lazy init - Map<String, List<Method>> nonBridgeMethods = null; - - for (PropertyDescriptor pd : descriptors) - { - // Indexed properties will have a null propertyType (and a non-null - // indexedPropertyType). We ignore indexed properties. - - final Class<?> thisPropertyType = pd.getPropertyType(); - if (thisPropertyType == null) - continue; - - Method readMethod = pd.getReadMethod(); - Method writeMethod = pd.getWriteMethod(); - - // TAP5-1493 - if (readMethod != null && readMethod.isBridge()) - { - if (nonBridgeMethods == null) - { - nonBridgeMethods = groupNonBridgeMethodsByName(beanType); - } - readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods); - } - - // TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed - if (readMethod == null) { - final String prefix = thisPropertyType != boolean.class ? "get" : "is"; - try - { - Method method = beanType.getMethod(prefix + capitalize(pd.getName())); - final Class<?> returnType = method.getReturnType(); - if (returnType.equals(thisPropertyType) || returnType.isInstance(thisPropertyType)) { - readMethod = method; - } - } - catch (SecurityException e) { - // getter not usable. - } - catch (NoSuchMethodException e) - { - // getter doesn't exist. - } - } - - if (writeMethod != null && writeMethod.isBridge()) - { - if (nonBridgeMethods == null) - { - nonBridgeMethods = groupNonBridgeMethodsByName(beanType); - } - writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods); - } - - // TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed - if (writeMethod == null) { - try - { - Method method = beanType.getMethod("set" + capitalize(pd.getName()), pd.getPropertyType()); - final Class<?> returnType = method.getReturnType(); - if (returnType.equals(void.class)) { - writeMethod = method; - } - } - catch (SecurityException e) { - // setter not usable. - } - catch (NoSuchMethodException e) - { - // setter doesn't exist. - } - } - - Class propertyType = readMethod == null ? thisPropertyType : GenericsUtils.extractGenericReturnType( - beanType, readMethod); - - PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, writeMethod); - - adapters.put(pa.getName(), pa); - } - - // Now, add any public fields (even if static) that do not conflict - - for (Field f : beanType.getFields()) - { - String name = f.getName(); - - if (!adapters.containsKey(name)) - { - Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f); - PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f); - - adapters.put(name, pa); - } - } - } - - private static String capitalize(String name) - { - return Character.toUpperCase(name.charAt(0)) + name.substring(1); - } - - /** - * Find a replacement for the method (if one exists) - * @param method A method - * @param groupedMethods Methods mapped by name - * @return A method from groupedMethods with the same name / param count - * (default to providedmethod if none found) - */ - private Method findMethodWithSameNameAndParamCount(Method method, Map<String, List<Method>> groupedMethods) { - List<Method> methodGroup = groupedMethods.get(method.getName()); - if (methodGroup != null) - { - for (Method nonBridgeMethod : methodGroup) - { - if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length) - { - // return the non-bridge method with the same name / argument count - return nonBridgeMethod; - } - } - } - - // default to the provided method - return method; - } - - /** - * Find all of the public methods that are not bridge methods and - * group them by method name - * - * {@see Method#isBridge()} - * @param type Bean type - * @return - */ - private Map<String, List<Method>> groupNonBridgeMethodsByName(Class type) - { - Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap(); - for (Method method : type.getMethods()) - { - if (!method.isBridge()) - { - List<Method> methodGroup = methodGroupsByName.get(method.getName()); - if (methodGroup == null) - { - methodGroup = CollectionFactory.newList(); - methodGroupsByName.put(method.getName(), methodGroup); - } - methodGroup.add(method); - } - } - return methodGroupsByName; - } - - @Override - public Class getBeanType() - { - return beanType; - } - - @Override - public String toString() - { - String names = InternalUtils.joinSorted(adapters.keySet()); - - return String.format("<ClassPropertyAdaptor %s: %s>", beanType.getName(), names); - } - - @Override - public List<String> getPropertyNames() - { - return InternalUtils.sortedKeys(adapters); - } - - @Override - public PropertyAdapter getPropertyAdapter(String name) - { - return adapters.get(name); - } - - @Override - public Object get(Object instance, String propertyName) - { - return adaptorFor(propertyName).get(instance); - } - - @Override - public void set(Object instance, String propertyName, Object value) - { - adaptorFor(propertyName).set(instance, value); - } - - @Override - public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) { - return adaptorFor(propertyName).getAnnotation(annotationClass); - } - - private PropertyAdapter adaptorFor(String name) - { - PropertyAdapter pa = adapters.get(name); - - if (pa == null) - throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name)); - - return pa; - } - -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java deleted file mode 100644 index 4a5dece..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2006, 2007 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.ioc.services.Coercion; - -/** - * Combines two coercions to create a coercion through an intermediate type. - * - * @param <S> The source (input) type - * @param <I> The intermediate type - * @param <T> The target (output) type - */ -public class CompoundCoercion<S, I, T> implements Coercion<S, T> -{ - private final Coercion<S, I> op1; - - private final Coercion<I, T> op2; - - public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2) - { - this.op1 = op1; - this.op2 = op2; - } - - @Override - public T coerce(S input) - { - // Run the input through the first operation (S --> I), then run the result of that through - // the second operation (I --> T). - - I intermediate = op1.coerce(input); - - return op2.coerce(intermediate); - } - - @Override - public String toString() - { - return String.format("%s, %s", op1, op2); - } -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java deleted file mode 100644 index 8ebdede..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2011 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.plastic.ClassType; -import org.apache.tapestry5.plastic.PlasticClassEvent; -import org.apache.tapestry5.plastic.PlasticClassListener; -import org.slf4j.Logger; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; - -public class PlasticClassListenerLogger implements PlasticClassListener -{ - private final Logger logger; - - public PlasticClassListenerLogger(Logger logger) - { - this.logger = logger; - } - - @Override - public void classWillLoad(PlasticClassEvent event) - { - if (logger.isDebugEnabled()) - { - Marker marker = MarkerFactory.getMarker(event.getPrimaryClassName()); - - String extendedClassName = event.getType() == ClassType.PRIMARY ? event.getPrimaryClassName() : String - .format("%s (%s for %s)", event.getClassName(), event.getType(), event.getPrimaryClassName()); - - logger.debug(marker, - String.format("Loading class %s:\n%s", extendedClassName, event.getDissasembledBytecode())); - } - } -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java deleted file mode 100644 index 112e29d..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright 2011, 2012 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.internal.plastic.PlasticInternalUtils; -import org.apache.tapestry5.internal.plastic.asm.Type; -import org.apache.tapestry5.internal.plastic.asm.tree.*; -import org.apache.tapestry5.ioc.Location; -import org.apache.tapestry5.ioc.ObjectCreator; -import org.apache.tapestry5.ioc.annotations.IncompatibleChange; -import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.internal.util.InternalUtils; -import org.apache.tapestry5.ioc.services.PlasticProxyFactory; -import org.apache.tapestry5.plastic.*; -import org.slf4j.Logger; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; - -public class PlasticProxyFactoryImpl implements PlasticProxyFactory -{ - public static final String INTERNAL_GET_DELEGATE = "_____internalGetDelegate_DONT_CALL_THIS_METHOD_____"; - - private final PlasticManager manager; - - private final Map<String, Location> memberToLocation = CollectionFactory.newConcurrentMap(); - - public PlasticProxyFactoryImpl(ClassLoader parentClassLoader, Logger logger) - { - this(PlasticManager.withClassLoader(parentClassLoader).create(), logger); - } - - public PlasticProxyFactoryImpl(PlasticManager manager, Logger logger) - { - assert manager != null; - - this.manager = manager; - - if (logger != null) - { - manager.addPlasticClassListener(new PlasticClassListenerLogger(logger)); - } - } - - @Override - public ClassLoader getClassLoader() - { - return manager.getClassLoader(); - } - - @Override - public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback) - { - return manager.createProxy(interfaceType, implementationType, callback); - } - - @Override - public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback) - { - return manager.createProxy(interfaceType, callback); - } - - - @Override - public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, - Class<? extends T> implementationType) - { - return manager.createProxyTransformation(interfaceType, implementationType); - } - - @Override - public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType) - { - return createProxyTransformation(interfaceType, null); - } - - @Override - public <T> T createProxy(final Class<T> interfaceType, final ObjectCreator<T> creator, final String description) - { return createProxy(interfaceType, null, creator, description); - } - - @Override - public <T> T createProxy(final Class<T> interfaceType, final Class<? extends T> implementationType, - final ObjectCreator<T> creator, final String description) - { - assert creator != null; - assert InternalUtils.isNonBlank(description); - - ClassInstantiator<T> instantiator = createProxy(interfaceType, implementationType, new PlasticClassTransformer() - { - @Override - public void transform(PlasticClass plasticClass) - { - final PlasticField objectCreatorField = plasticClass.introduceField(ObjectCreator.class, "creator") - .inject(creator); - - final String interfaceTypeName = interfaceType.getName(); - PlasticMethod delegateMethod = plasticClass.introducePrivateMethod(interfaceTypeName, "delegate", - null, null); - - final InstructionBuilderCallback returnCreateObject = new InstructionBuilderCallback() - { - @Override - public void doBuild(InstructionBuilder builder) - { - builder.loadThis().getField(objectCreatorField); - builder.invoke(ObjectCreator.class, Object.class, "createObject"); - builder.checkcast(interfaceType).returnResult(); - } - }; - - delegateMethod.changeImplementation(returnCreateObject); - - for (Method method : interfaceType.getMethods()) - { - plasticClass.introduceMethod(method).delegateTo(delegateMethod); - } - - // TA5-2235 - MethodDescription getDelegateMethodDescription = - new MethodDescription(interfaceType.getName(), INTERNAL_GET_DELEGATE); - plasticClass.introduceMethod(getDelegateMethodDescription, returnCreateObject); - - plasticClass.addToString(description); - - } - }); - - return interfaceType.cast(instantiator.newInstance()); - } - - private ClassNode readClassNode(Class clazz) - { - byte[] bytecode = PlasticInternalUtils.readBytecodeForClass(manager.getClassLoader(), clazz.getName(), false); - - return bytecode == null ? null : PlasticInternalUtils.convertBytecodeToClassNode(bytecode); - } - - @Override - public Location getMethodLocation(final Method method) - { - ObjectCreator<String> descriptionCreator = new ObjectCreator<String>() - { - @Override - public String createObject() - { - return InternalUtils.asString(method); - } - }; - - return getMemberLocation(method, method.getName(), Type.getMethodDescriptor(method), - descriptionCreator); - } - - @Override - public Location getConstructorLocation(final Constructor constructor) - { - ObjectCreator<String> descriptionCreator = new ObjectCreator<String>() - { - @Override - public String createObject() - { - StringBuilder builder = new StringBuilder(constructor.getDeclaringClass().getName()).append("("); - String sep = ""; - - for (Class parameterType : constructor.getParameterTypes()) - { - builder.append(sep); - builder.append(parameterType.getSimpleName()); - - sep = ", "; - } - - builder.append(")"); - - return builder.toString(); - } - }; - - return getMemberLocation(constructor, "<init>", Type.getConstructorDescriptor(constructor), - descriptionCreator); - } - - @Override - public void clearCache() - { - memberToLocation.clear(); - } - - - public Location getMemberLocation(Member member, String methodName, String memberTypeDesc, ObjectCreator<String> textDescriptionCreator) - { - String className = member.getDeclaringClass().getName(); - - String key = className + ":" + methodName + ":" + memberTypeDesc; - - Location location = memberToLocation.get(key); - - if (location == null) - { - location = constructMemberLocation(member, methodName, memberTypeDesc, textDescriptionCreator.createObject()); - - memberToLocation.put(key, location); - } - - return location; - - } - - private Location constructMemberLocation(Member member, String methodName, String memberTypeDesc, String textDescription) - { - - ClassNode classNode = readClassNode(member.getDeclaringClass()); - - if (classNode == null) - { - throw new RuntimeException(String.format("Unable to read class file for %s (to gather line number information).", - textDescription)); - } - - for (MethodNode mn : (List<MethodNode>) classNode.methods) - { - if (mn.name.equals(methodName) && mn.desc.equals(memberTypeDesc)) - { - int lineNumber = findFirstLineNumber(mn.instructions); - - // If debugging info is not available, we may lose the line number data, in which case, - // just generate the Location from the textDescription. - - if (lineNumber < 1) - { - break; - } - - String description = String.format("%s (at %s:%d)", textDescription, classNode.sourceFile, lineNumber); - - return new StringLocation(description, lineNumber); - } - } - - // Didn't find it. Odd. - - return new StringLocation(textDescription, 0); - } - - private int findFirstLineNumber(InsnList instructions) - { - for (AbstractInsnNode node = instructions.getFirst(); node != null; node = node.getNext()) - { - if (node instanceof LineNumberNode) - { - return ((LineNumberNode) node).line; - } - } - - return -1; - } - - @Override - public void addPlasticClassListener(PlasticClassListener listener) - { - manager.addPlasticClassListener(listener); - } - - @Override - public void removePlasticClassListener(PlasticClassListener listener) - { - manager.removePlasticClassListener(listener); - } - -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java deleted file mode 100644 index 8dd1e02..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2006, 2007, 2008, 2010 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.services.ClassPropertyAdapter; -import org.apache.tapestry5.ioc.services.PropertyAccess; - -@SuppressWarnings("unchecked") -public class PropertyAccessImpl implements PropertyAccess -{ - private final Map<Class, ClassPropertyAdapter> adapters = CollectionFactory.newConcurrentMap(); - - @Override - public Object get(Object instance, String propertyName) - { - return getAdapter(instance).get(instance, propertyName); - } - - @Override - public void set(Object instance, String propertyName, Object value) - { - getAdapter(instance).set(instance, propertyName, value); - } - - @Override - public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) { - return getAdapter(instance).getAnnotation(instance, propertyName, annotationClass); - } - - - /** - * Clears the cache of adapters and asks the {@link Introspector} to clear its cache. - */ - @Override - public synchronized void clearCache() - { - adapters.clear(); - - Introspector.flushCaches(); - } - - @Override - public ClassPropertyAdapter getAdapter(Object instance) - { - return getAdapter(instance.getClass()); - } - - @Override - public ClassPropertyAdapter getAdapter(Class forClass) - { - ClassPropertyAdapter result = adapters.get(forClass); - - if (result == null) - { - result = buildAdapter(forClass); - adapters.put(forClass, result); - } - - return result; - } - - /** - * Builds a new adapter and updates the _adapters cache. This not only guards access to the adapter cache, but also - * serializes access to the Java Beans Introspector, which is not thread safe. In addition, handles the case where - * the class in question is an interface, accumulating properties inherited from super-classes. - */ - private synchronized ClassPropertyAdapter buildAdapter(Class forClass) - { - // In some race conditions, we may hit this method for the same class multiple times. - // We just let it happen, replacing the old ClassPropertyAdapter with a new one. - - try - { - BeanInfo info = Introspector.getBeanInfo(forClass); - - List<PropertyDescriptor> descriptors = CollectionFactory.newList(); - - addAll(descriptors, info.getPropertyDescriptors()); - - // TAP5-921 - Introspector misses interface methods not implemented in an abstract class - if (forClass.isInterface() || Modifier.isAbstract(forClass.getModifiers()) ) - addPropertiesFromExtendedInterfaces(forClass, descriptors); - - addPropertiesFromScala(forClass, descriptors); - - return new ClassPropertyAdapterImpl(forClass, descriptors); - } - catch (Throwable ex) - { - throw new RuntimeException(ex); - } - } - - private <T> void addAll(List<T> list, T[] array) - { - list.addAll(Arrays.asList(array)); - } - - private void addPropertiesFromExtendedInterfaces(Class forClass, List<PropertyDescriptor> descriptors) - throws IntrospectionException - { - LinkedList<Class> queue = CollectionFactory.newLinkedList(); - - // Seed the queue - addAll(queue, forClass.getInterfaces()); - - while (!queue.isEmpty()) - { - Class c = queue.removeFirst(); - - BeanInfo info = Introspector.getBeanInfo(c); - - // Duplicates occur and are filtered out in ClassPropertyAdapter which stores - // a property name to descriptor map. - addAll(descriptors, info.getPropertyDescriptors()); - addAll(queue, c.getInterfaces()); - } - } - - private void addPropertiesFromScala(Class forClass, List<PropertyDescriptor> descriptors) - throws IntrospectionException - { - for (Method method : forClass.getMethods()) - { - addPropertyIfScalaGetterMethod(forClass, descriptors, method); - } - } - - private void addPropertyIfScalaGetterMethod(Class forClass, List<PropertyDescriptor> descriptors, Method method) - throws IntrospectionException - { - if (!isScalaGetterMethod(method)) - return; - - PropertyDescriptor propertyDescriptor = new PropertyDescriptor(method.getName(), forClass, method.getName(), - null); - - // found a getter, looking for the setter now - try - { - Method setterMethod = findScalaSetterMethod(forClass, method); - - propertyDescriptor.setWriteMethod(setterMethod); - } - catch (NoSuchMethodException e) - { - // ignore - } - - // check if the same property was already discovered with java bean accessors - - addScalaPropertyIfNoJavaBeansProperty(descriptors, propertyDescriptor, method); - } - - private void addScalaPropertyIfNoJavaBeansProperty(List<PropertyDescriptor> descriptors, - PropertyDescriptor propertyDescriptor, Method getterMethod) - { - boolean found = false; - - for (PropertyDescriptor currentPropertyDescriptor : descriptors) - { - if (currentPropertyDescriptor.getName().equals(getterMethod.getName())) - { - found = true; - - break; - } - } - - if (!found) - descriptors.add(propertyDescriptor); - } - - private Method findScalaSetterMethod(Class forClass, Method getterMethod) throws NoSuchMethodException - { - return forClass.getMethod(getterMethod.getName() + "_$eq", getterMethod.getReturnType()); - } - - private boolean isScalaGetterMethod(Method method) - { - try - { - return Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0 - && !method.getReturnType().equals(Void.TYPE) - && method.getDeclaringClass().getDeclaredField(method.getName()) != null; - } - catch (NoSuchFieldException ex) - { - return false; - } - } -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java deleted file mode 100644 index 97685ef..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2006-2013 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.ioc.AnnotationProvider; -import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.services.ClassPropertyAdapter; -import org.apache.tapestry5.ioc.services.PropertyAdapter; -import org.apache.tapestry5.ioc.util.ExceptionUtils; - -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.util.List; - -public class PropertyAdapterImpl implements PropertyAdapter -{ - private final ClassPropertyAdapter classAdapter; - - private final String name; - - private final Method readMethod; - - private final Method writeMethod; - - private final Class type; - - private final boolean castRequired; - - // Synchronized by this; lazily initialized - private AnnotationProvider annotationProvider; - - private final Field field; - - private final Class declaringClass; - - PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Method readMethod, - Method writeMethod) - { - this.classAdapter = classAdapter; - this.name = name; - this.type = type; - - this.readMethod = readMethod; - this.writeMethod = writeMethod; - - declaringClass = readMethod != null ? readMethod.getDeclaringClass() : writeMethod.getDeclaringClass(); - - castRequired = readMethod != null && readMethod.getReturnType() != type; - - field = null; - } - - PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Field field) - { - this.classAdapter = classAdapter; - this.name = name; - this.type = type; - - this.field = field; - - declaringClass = field.getDeclaringClass(); - - castRequired = field.getType() != type; - - readMethod = null; - writeMethod = null; - } - - @Override - public String getName() - { - return name; - } - - @Override - public Method getReadMethod() - { - return readMethod; - } - - @Override - public Class getType() - { - return type; - } - - @Override - public Method getWriteMethod() - { - return writeMethod; - } - - @Override - public boolean isRead() - { - return field != null || readMethod != null; - } - - @Override - public boolean isUpdate() - { - return writeMethod != null || (field != null && !isFinal(field)); - } - - private boolean isFinal(Member member) - { - return Modifier.isFinal(member.getModifiers()); - } - - @Override - public Object get(Object instance) - { - if (field == null && readMethod == null) - { - throw new UnsupportedOperationException(String.format("Class %s does not provide an accessor ('getter') method for property '%s'.", toClassName(instance), name)); - } - - Throwable fail; - - try - { - if (field == null) - return readMethod.invoke(instance); - else - return field.get(instance); - } catch (InvocationTargetException ex) - { - fail = ex.getTargetException(); - } catch (Exception ex) - { - fail = ex; - } - - throw new RuntimeException(ServiceMessages.readFailure(name, instance, fail), fail); - } - - @Override - public void set(Object instance, Object value) - { - if (field == null && writeMethod == null) - { - throw new UnsupportedOperationException(String.format("Class %s does not provide a mutator ('setter') method for property '%s'.", - toClassName(instance), - name - )); - } - - Throwable fail; - - try - { - if (field == null) - writeMethod.invoke(instance, value); - else - field.set(instance, value); - - return; - } catch (InvocationTargetException ex) - { - fail = ex.getTargetException(); - } catch (Exception ex) - { - fail = ex; - } - - throw new RuntimeException(String.format("Error updating property '%s' of %s: %s", - name, toClassName(instance), - ExceptionUtils.toMessage(fail)), fail); - } - - private String toClassName(Object instance) - { - return instance == null ? "<null>" : instance.getClass().getName(); - } - - @Override - public <T extends Annotation> T getAnnotation(Class<T> annotationClass) - { - return getAnnnotationProvider().getAnnotation(annotationClass); - } - - /** - * Creates (as needed) the annotation provider for this property. - */ - private synchronized AnnotationProvider getAnnnotationProvider() - { - if (annotationProvider == null) - { - List<AnnotationProvider> providers = CollectionFactory.newList(); - - if (readMethod != null) - providers.add(new AccessableObjectAnnotationProvider(readMethod)); - - if (writeMethod != null) - providers.add(new AccessableObjectAnnotationProvider(writeMethod)); - - // There's an assumption here, that the fields match the property name (we ignore case - // which leads to a manageable ambiguity) and that the field and the getter/setter - // are in the same class (i.e., that we don't have a getter exposing a protected field inherted - // from a base class, or some other oddity). - - Class cursor = getBeanType(); - - out: - while (cursor != null) - { - for (Field f : cursor.getDeclaredFields()) - { - if (f.getName().equalsIgnoreCase(name)) - { - providers.add(new AccessableObjectAnnotationProvider(f)); - - break out; - } - } - - cursor = cursor.getSuperclass(); - } - - annotationProvider = AnnotationProviderChain.create(providers); - } - - return annotationProvider; - } - - @Override - public boolean isCastRequired() - { - return castRequired; - } - - @Override - public ClassPropertyAdapter getClassAdapter() - { - return classAdapter; - } - - @Override - public Class getBeanType() - { - return classAdapter.getBeanType(); - } - - @Override - public boolean isField() - { - return field != null; - } - - @Override - public Field getField() - { - return field; - } - - @Override - public Class getDeclaringClass() - { - return declaringClass; - } -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java deleted file mode 100644 index e92ef2d..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2006, 2007, 2011, 2012 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.ioc.Messages; -import org.apache.tapestry5.ioc.internal.util.MessagesImpl; -import org.apache.tapestry5.ioc.services.Coercion; -import org.apache.tapestry5.plastic.PlasticUtils; - -public class ServiceMessages -{ - private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class); - - private ServiceMessages() - { - } - - public static String noSuchProperty(Class clazz, String propertyName) - { - return MESSAGES.format("no-such-property", clazz.getName(), propertyName); - } - - - public static String readFailure(String propertyName, Object instance, Throwable cause) - { - return MESSAGES.format("read-failure", propertyName, instance, cause); - } - - public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType, - Class expectedType) - { - return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(), - expectedType.getName()); - } - - public static String shutdownListenerError(Object listener, Throwable cause) - { - return MESSAGES.format("shutdown-listener-error", listener, cause); - } - - public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause) - { - return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType), - coercion, cause); - } - - public static String registryShutdown(String serviceId) - { - return MESSAGES.format("registry-shutdown", serviceId); - } - - public static String serviceBuildFailure(String serviceId, Throwable cause) - { - return MESSAGES.format("service-build-failure", serviceId, cause); - } -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java deleted file mode 100644 index 0769b7e..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2007 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.ioc.Location; -import org.apache.tapestry5.ioc.Resource; - -/** - * Implementation of {@link Location} used when the underlying resource isn't really known. - */ -public final class StringLocation implements Location -{ - private final String description; - - private final int line; - - public StringLocation(String description, int line) - { - this.description = description; - this.line = line; - } - - @Override - public String toString() - { - return description; - } - - /** - * Returns 0. - */ - @Override - public int getColumn() - { - return 0; - } - - @Override - public int getLine() - { - return line; - } - - /** - * Returns null; we don't know where the file really is (it's probably a class on the class path). - */ - @Override - public Resource getResource() - { - return null; - } - -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java deleted file mode 100644 index 46f1c0a..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright 2006, 2007, 2008, 2010, 2012 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.services; - -import org.apache.tapestry5.func.F; -import org.apache.tapestry5.ioc.internal.util.CollectionFactory; -import org.apache.tapestry5.ioc.internal.util.InheritanceSearch; -import org.apache.tapestry5.ioc.internal.util.InternalUtils; -import org.apache.tapestry5.ioc.internal.util.LockSupport; -import org.apache.tapestry5.ioc.services.Coercion; -import org.apache.tapestry5.ioc.services.CoercionTuple; -import org.apache.tapestry5.ioc.services.TypeCoercer; -import org.apache.tapestry5.ioc.util.AvailableValues; -import org.apache.tapestry5.ioc.util.UnknownValueException; -import org.apache.tapestry5.plastic.PlasticUtils; -import org.apache.tapestry5.util.StringToEnumCoercion; - -import java.util.*; - -@SuppressWarnings("all") -public class TypeCoercerImpl extends LockSupport implements TypeCoercer -{ - // Constructed from the service's configuration. - - private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap(); - - /** - * A coercion to a specific target type. Manages a cache of coercions to specific types. - */ - private class TargetCoercion - { - private final Class type; - - private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap(); - - TargetCoercion(Class type) - { - this.type = type; - } - - void clearCache() - { - cache.clear(); - } - - Object coerce(Object input) - { - Class sourceType = input != null ? input.getClass() : Void.class; - - if (type.isAssignableFrom(sourceType)) - { - return input; - } - - Coercion c = getCoercion(sourceType); - - try - { - return type.cast(c.coerce(input)); - } catch (Exception ex) - { - throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex); - } - } - - String explain(Class sourceType) - { - return getCoercion(sourceType).toString(); - } - - private Coercion getCoercion(Class sourceType) - { - Coercion c = cache.get(sourceType); - - if (c == null) - { - c = findOrCreateCoercion(sourceType, type); - cache.put(sourceType, c); - } - - return c; - } - } - - /** - * Map from a target type to a TargetCoercion for that type. - */ - private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>(); - - private static final Coercion NO_COERCION = new Coercion<Object, Object>() - { - @Override - public Object coerce(Object input) - { - return input; - } - }; - - private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>() - { - @Override - public Object coerce(Void input) - { - return null; - } - - @Override - public String toString() - { - return "null --> null"; - } - }; - - public TypeCoercerImpl(Collection<CoercionTuple> tuples) - { - for (CoercionTuple tuple : tuples) - { - Class key = tuple.getSourceType(); - - InternalUtils.addToMapList(sourceTypeToTuple, key, tuple); - } - } - - @Override - @SuppressWarnings("unchecked") - public Object coerce(Object input, Class targetType) - { - assert targetType != null; - - Class effectiveTargetType = PlasticUtils.toWrapperType(targetType); - - if (effectiveTargetType.isInstance(input)) - { - return input; - } - - - return getTargetCoercion(effectiveTargetType).coerce(input); - } - - @Override - @SuppressWarnings("unchecked") - public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType) - { - assert sourceType != null; - assert targetType != null; - - Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType); - Class effectiveTargetType = PlasticUtils.toWrapperType(targetType); - - if (effectiveTargetType.isAssignableFrom(effectiveSourceType)) - { - return NO_COERCION; - } - - return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType); - } - - @Override - @SuppressWarnings("unchecked") - public <S, T> String explain(Class<S> sourceType, Class<T> targetType) - { - assert sourceType != null; - assert targetType != null; - - Class effectiveTargetType = PlasticUtils.toWrapperType(targetType); - Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType); - - // Is a coercion even necessary? Not if the target type is assignable from the - // input value. - - if (effectiveTargetType.isAssignableFrom(effectiveSourceType)) - { - return ""; - } - - return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType); - } - - private TargetCoercion getTargetCoercion(Class targetType) - { - try - { - acquireReadLock(); - - TargetCoercion tc = typeToTargetCoercion.get(targetType); - - return tc != null ? tc : createAndStoreNewTargetCoercion(targetType); - } finally - { - releaseReadLock(); - } - } - - private TargetCoercion createAndStoreNewTargetCoercion(Class targetType) - { - try - { - upgradeReadLockToWriteLock(); - - // Inner check since some other thread may have beat us to it. - - TargetCoercion tc = typeToTargetCoercion.get(targetType); - - if (tc == null) - { - tc = new TargetCoercion(targetType); - typeToTargetCoercion.put(targetType, tc); - } - - return tc; - } finally - { - downgradeWriteLockToReadLock(); - } - } - - @Override - public void clearCache() - { - try - { - acquireReadLock(); - - // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and - // will release the keys for classes that are no longer in existence. On the other hand, - // there's likely all sorts of references to unloaded classes inside each TargetCoercion's - // individual cache, so clear all those. - - for (TargetCoercion tc : typeToTargetCoercion.values()) - { - // Can tc ever be null? - - tc.clearCache(); - } - } finally - { - releaseReadLock(); - } - } - - /** - * Here's the real meat; we do a search of the space to find coercions, or a system of - * coercions, that accomplish - * the desired coercion. - * <p/> - * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be - * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps - * hundreds of tuples, I suspect the search will still grind to a conclusion quickly. - * <p/> - * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how - * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and - * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions - * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again - * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and - * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a - * final response. - * <p/> - * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is - * really good at. - * - * @param sourceType - * @param targetType - * @return coercer from sourceType to targetType - */ - @SuppressWarnings("unchecked") - private Coercion findOrCreateCoercion(Class sourceType, Class targetType) - { - if (sourceType == Void.class) - { - return searchForNullCoercion(targetType); - } - - // These are instance variables because this method may be called concurrently. - // On a true race, we may go to the work of seeking out and/or fabricating - // a tuple twice, but it's more likely that different threads are looking - // for different source/target coercions. - - Set<CoercionTuple> consideredTuples = CollectionFactory.newSet(); - LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList(); - - seedQueue(sourceType, targetType, consideredTuples, queue); - - while (!queue.isEmpty()) - { - CoercionTuple tuple = queue.removeFirst(); - - // If the tuple results in a value type that is assignable to the desired target type, - // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or - // "quality" (how close is the tuple target type to the desired target type). Cost - // is currently implicit, as compound tuples are stored deeper in the queue, - // so simpler coercions will be located earlier. - - Class tupleTargetType = tuple.getTargetType(); - - if (targetType.isAssignableFrom(tupleTargetType)) - { - return tuple.getCoercion(); - } - - // So .. this tuple doesn't get us directly to the target type. - // However, it *may* get us part of the way. Each of these - // represents a coercion from the source type to an intermediate type. - // Now we're going to look for conversions from the intermediate type - // to some other type. - - queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue); - } - - // Not found anywhere. Identify the source and target type and a (sorted) list of - // all the known coercions. - - throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.", - sourceType.getName(), targetType.getName()), buildCoercionCatalog()); - } - - /** - * Coercion from null is special; we match based on the target type and its not a spanning - * search. In many cases, we - * return a pass-thru that leaves the value as null. - * - * @param targetType - * desired type - * @return the coercion - */ - private Coercion searchForNullCoercion(Class targetType) - { - List<CoercionTuple> tuples = getTuples(Void.class, targetType); - - for (CoercionTuple tuple : tuples) - { - Class tupleTargetType = tuple.getTargetType(); - - if (targetType.equals(tupleTargetType)) - return tuple.getCoercion(); - } - - // Typical case: no match, this coercion passes the null through - // as null. - - return COERCION_NULL_TO_OBJECT; - } - - /** - * Builds a string listing all the coercions configured for the type coercer, sorted - * alphabetically. - */ - @SuppressWarnings("unchecked") - private AvailableValues buildCoercionCatalog() - { - List<CoercionTuple> masterList = CollectionFactory.newList(); - - for (List<CoercionTuple> list : sourceTypeToTuple.values()) - { - masterList.addAll(list); - } - - return new AvailableValues("Configured coercions", masterList); - } - - /** - * Seeds the pool with the initial set of coercions for the given type. - */ - private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples, - LinkedList<CoercionTuple> queue) - { - // Work from the source type up looking for tuples - - for (Class c : new InheritanceSearch(sourceType)) - { - List<CoercionTuple> tuples = getTuples(c, targetType); - - if (tuples == null) - { - continue; - } - - for (CoercionTuple tuple : tuples) - { - queue.addLast(tuple); - consideredTuples.add(tuple); - } - - // Don't pull in Object -> type coercions when doing - // a search from null. - - if (sourceType == Void.class) - { - return; - } - } - } - - /** - * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds - * compound coercion tuples - * to the end of the queue. - * - * @param sourceType - * the source type of the coercion - * @param targetType - * TODO - * @param intermediateTuple - * a tuple that converts from the source type to some intermediate type (that is not - * assignable to the target type) - * @param consideredTuples - * set of tuples that have already been added to the pool (directly, or as a compound - * coercion) - * @param queue - * the work queue of tuples - */ - @SuppressWarnings("unchecked") - private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple, - Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue) - { - Class intermediateType = intermediateTuple.getTargetType(); - - for (Class c : new InheritanceSearch(intermediateType)) - { - for (CoercionTuple tuple : getTuples(c, targetType)) - { - if (consideredTuples.contains(tuple)) - { - continue; - } - - Class newIntermediateType = tuple.getTargetType(); - - // If this tuple is for coercing from an intermediate type back towards our - // initial source type, then ignore it. This should only be an optimization, - // as branches that loop back towards the source type will - // eventually be considered and discarded. - - if (sourceType.isAssignableFrom(newIntermediateType)) - { - continue; - } - - // The intermediateTuple coercer gets from S --> I1 (an intermediate type). - // The current tuple's coercer gets us from I2 --> X. where I2 is assignable - // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new - // intermediate type, hopefully closer to our eventual target type. - - Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion()); - - CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false); - - // So, every tuple that is added to the queue can take as input the sourceType. - // The target type may be another intermediate type, or may be something - // assignable to the target type, which will bring the search to a successful - // conclusion. - - queue.addLast(compoundTuple); - consideredTuples.add(tuple); - } - } - } - - /** - * Returns a non-null list of the tuples from the source type. - * - * @param sourceType - * used to locate tuples - * @param targetType - * used to add synthetic tuples - * @return non-null list of tuples - */ - private List<CoercionTuple> getTuples(Class sourceType, Class targetType) - { - List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType); - - if (tuples == null) - { - tuples = Collections.emptyList(); - } - - // So, when we see String and an Enum type, we add an additional synthetic tuple to the end - // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading - // safe way (i.e., what if the Enum is defined by a class loader that gets discarded? Don't want to cause - // memory leaks by retaining an instance). In any case, there are edge cases where we may create - // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer - // configuration), but on the whole, this is cheap and works. - - if (sourceType == String.class && Enum.class.isAssignableFrom(targetType)) - { - tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType))); - } - - return tuples; - } - - private static <T> List<T> extend(List<T> list, T extraValue) - { - return F.flow(list).append(extraValue).toList(); - } -} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c7bf35ce/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java deleted file mode 100644 index f1830a7..0000000 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2006 The Apache Software Foundation -// -// 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.apache.tapestry5.ioc.internal.util; - -import org.apache.tapestry5.plastic.PlasticUtils; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Set; - -/** - * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces. - * <p/> - * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but - * skips java.lang.Object. - * <p/> - * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the - * interfaces implemented by the initial class at its super classes. - * <p/> - * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last). - * <p/> - * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is - * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the - * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>, - * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul> - * <p/> - * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class - * search : new InheritanceSearch(startClass)) { ... } </code> - * <p/> - * This class is not thread-safe. - */ -public class InheritanceSearch implements Iterator<Class>, Iterable<Class> -{ - private Class searchClass; - - private final Set<Class> addedInterfaces = CollectionFactory.newSet(); - - private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList(); - - private enum State - { - CLASS, INTERFACE, DONE - } - - private State state; - - public InheritanceSearch(Class searchClass) - { - this.searchClass = searchClass; - - queueInterfaces(searchClass); - - state = searchClass == Object.class ? State.INTERFACE : State.CLASS; - } - - private void queueInterfaces(Class searchClass) - { - for (Class intf : searchClass.getInterfaces()) - { - if (addedInterfaces.contains(intf)) continue; - - interfaceQueue.addLast(intf); - addedInterfaces.add(intf); - } - } - - @Override - public Iterator<Class> iterator() - { - return this; - } - - @Override - public boolean hasNext() - { - return state != State.DONE; - } - - @Override - public Class next() - { - switch (state) - { - case CLASS: - - Class result = searchClass; - - searchClass = parentOf(searchClass); - - if (searchClass == null) state = State.INTERFACE; - else queueInterfaces(searchClass); - - return result; - - case INTERFACE: - - if (interfaceQueue.isEmpty()) - { - state = State.DONE; - return Object.class; - } - - Class intf = interfaceQueue.removeFirst(); - - queueInterfaces(intf); - - return intf; - - default: - throw new IllegalStateException(); - } - - } - - /** - * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of - * Object.class. - */ - private Class parentOf(Class clazz) - { - if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz); - - if (clazz.isArray() && clazz != Object[].class) - { - Class componentType = clazz.getComponentType(); - - while (componentType.isArray()) componentType = componentType.getComponentType(); - - if (!componentType.isPrimitive()) return Object[].class; - } - - Class parent = clazz.getSuperclass(); - - return parent != Object.class ? parent : null; - } - - /** - * @throws UnsupportedOperationException - * always - */ - @Override - public void remove() - { - throw new UnsupportedOperationException(); - } - -}
