Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/reference/ReferenceModel.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/reference/ReferenceModel.java?rev=1807424&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/reference/ReferenceModel.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/reference/ReferenceModel.java Tue Sep 5 22:01:11 2017 @@ -0,0 +1,864 @@ +/** + * 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.aries.cdi.container.internal.reference; + +import static org.apache.aries.cdi.container.internal.model.Model.*; +import static org.apache.aries.cdi.container.internal.util.Reflection.cast; +import static java.lang.String.format; +import static org.apache.aries.cdi.container.internal.model.Constants.CARDINALITY_ATTRIBUTE; +import static org.apache.aries.cdi.container.internal.model.Constants.CDI10_URI; +import static org.apache.aries.cdi.container.internal.model.Constants.NAME_ATTRIBUTE; +import static org.apache.aries.cdi.container.internal.model.Constants.POLICY_ATTRIBUTE; +import static org.apache.aries.cdi.container.internal.model.Constants.POLICY_OPTION_ATTRIBUTE; +import static org.apache.aries.cdi.container.internal.model.Constants.SCOPE_ATTRIBUTE; +import static org.apache.aries.cdi.container.internal.model.Constants.TARGET_ATTRIBUTE; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.enterprise.inject.Instance; +import javax.enterprise.inject.spi.Annotated; +import javax.enterprise.inject.spi.AnnotatedField; +import javax.enterprise.inject.spi.AnnotatedParameter; + +import org.apache.aries.cdi.container.internal.model.CollectionType; +import org.apache.aries.cdi.container.internal.util.Conversions; +import org.apache.aries.cdi.container.internal.util.Maps; +import org.apache.aries.cdi.container.internal.util.Sets; +import org.apache.aries.cdi.container.internal.util.Types; +import org.osgi.framework.Constants; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceObjects; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cdi.annotations.Reference; +import org.osgi.service.cdi.annotations.ReferenceCardinality; +import org.osgi.service.cdi.annotations.ReferencePolicy; +import org.osgi.service.cdi.annotations.ReferencePolicyOption; +import org.osgi.service.cdi.annotations.ReferenceScope; +import org.osgi.service.cdi.annotations.ServiceEvent; +import org.osgi.util.converter.TypeReference; +import org.xml.sax.Attributes; + +public class ReferenceModel { + + public static class Builder { + + public Builder(Attributes attributes) { + _cardinality = _cardinality(attributes); + _name = _name(attributes); + _option = _option(attributes); + _policy = _policy(attributes); + _scope = _scope(attributes); + _target = _target(attributes); + } + + public Builder(Set<Annotation> qualifiers) { + _qualifiers = qualifiers; + Reference reference = getQualifier(_qualifiers, Reference.class); + if (reference != null) { + _cardinality = reference.cardinality(); + _name = reference.name(); + _option = reference.policyOption(); + _policy = reference.policy(); + _scope = reference.scope(); + _service = reference.service(); + _target = reference.target(); + } + } + + public ReferenceModel build() { + if ((_annotated == null) && (_service == null)) { + throw new IllegalArgumentException( + "Either injectionPoint or service must be set!"); + } + + if (_annotated == null) { + _annotated = new ReferenceAnnotated(_service); + } + + Type type = upwrapCDITypes(_annotated.getBaseType()); + + _policy = calculatePolicy(_policy); + _option = calculatePolicyOption(_option); + _scope = calculateScope(_scope); + Multiplicity multiplicity = calculateMultiplicity(_annotated.getBaseType());// we need the pure type to check "Instance" + _cardinality = calculateCardinality(_cardinality, multiplicity, type); + CollectionType collectionType = calculateCollectionType(type); + Class<?> beanClass = calculateBeanClass(type); + _service = calculateServiceClass(_service, _cardinality, collectionType, type, _annotated); + _name = calculateName(_name, _service, _annotated); + + return new ReferenceModel(_service, _cardinality, _name, _policy, _option, _target, _scope, _qualifiers, beanClass, type, collectionType); + } + + public Builder cardinality(ReferenceCardinality cardinality) { + _cardinality = cardinality; + return this; + } + + public Builder annotated(Annotated annotated) { + _annotated = annotated; + return this; + } + + public Builder name(String name) { + _name = name; + return this; + } + + public Builder option(ReferencePolicyOption option) { + _option = option; + return this; + } + + public Builder policy(ReferencePolicy policy) { + _policy = policy; + return this; + } + + public Builder scope(ReferenceScope scope) { + _scope = scope; + return this; + } + + public Builder service(Class<?> service) { + _service = service; + return this; + } + + public Builder target(String target) { + _target = target; + return this; + } + + @SuppressWarnings("unchecked") + private static <T extends Annotation> T getQualifier( + Set<Annotation> qualifiers, Class<T> clazz) { + for (Annotation annotation : qualifiers) { + if (clazz.isAssignableFrom(annotation.annotationType())) { + return (T)annotation; + } + } + return null; + } + + private ReferenceCardinality _cardinality; + private Annotated _annotated; + private String _name; + private ReferencePolicyOption _option; + private ReferencePolicy _policy; + private Set<Annotation> _qualifiers; + private ReferenceScope _scope; + private Class<?> _service; + private String _target; + + } + + private ReferenceModel( + Class<?> service, + ReferenceCardinality cardinality, + String name, + ReferencePolicy policy, + ReferencePolicyOption option, + String target, + ReferenceScope scope, + Set<Annotation> qualifiers, + Class<?> beanClass, + Type injectionPointType, + CollectionType collectionType) { + + _service = service; + _cardinality = cardinality; + _name = name; + _policy = policy; + _option = option; + _target = target; + _scope = scope; + _qualifiers = new LinkedHashSet<>(); + if (qualifiers != null) { + _qualifiers.addAll(qualifiers); + } + _beanClass = beanClass; + _injectionPointType = injectionPointType; + _collectionType = collectionType; + + _types = Sets.immutableHashSet(_injectionPointType, Object.class); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((_beanClass == null) ? 0 : _beanClass.hashCode()); + result = prime * result + ((_cardinality == null) ? 0 : _cardinality.hashCode()); + result = prime * result + ((_name == null) ? 0 : _name.hashCode()); + result = prime * result + ((_option == null) ? 0 : _option.hashCode()); + result = prime * result + ((_policy == null) ? 0 : _policy.hashCode()); + result = prime * result + ((_scope == null) ? 0 : _scope.hashCode()); + result = prime * result + ((_service == null) ? 0 : _service.hashCode()); + result = prime * result + ((_target == null) ? 0 : _target.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ReferenceModel other = (ReferenceModel) obj; + if (_beanClass == null) { + if (other._beanClass != null) + return false; + } else if (!_beanClass.equals(other._beanClass)) + return false; + if (_cardinality != other._cardinality) + return false; + if (_name == null) { + if (other._name != null) + return false; + } else if (!_name.equals(other._name)) + return false; + if (_option != other._option) + return false; + if (_policy != other._policy) + return false; + if (_scope != other._scope) + return false; + if (_service == null) { + if (other._service != null) + return false; + } else if (!_service.equals(other._service)) + return false; + if (_target == null) { + if (other._target != null) + return false; + } else if (!_target.equals(other._target)) + return false; + return true; + } + + public boolean found() { + return _found.get(); + } + + public void found(boolean found) { + _found.set(found); + } + + public Class<?> getBeanClass() { + return _beanClass; + } + + public ReferenceCardinality getCardinality() { + return _cardinality; + } + + public CollectionType getCollectionType() { + return _collectionType; + } + + public Type getInjectionPointType() { + return _injectionPointType; + } + + public String getName() { + return _name; + } + + public ReferencePolicy getPolicy() { + return _policy; + } + + public ReferencePolicyOption getPolicyOption() { + return _option; + } + + public Set<Annotation> getQualifiers() { + return _qualifiers; + } + + public ReferenceScope getScope() { + return _scope; + } + + public Class<?> getServiceClass() { + return _service; + } + + public String getTarget() { + return _target; + } + + public Set<Type> getTypes() { + return _types; + } + + public void setQualifiers(Set<Annotation> qualifiers) { + _qualifiers.clear(); + _qualifiers.addAll(qualifiers); + } + + @Override + public String toString() { + if (_string == null) { + _string = String.format("reference[name='%s', service='%s', scope='%s', target='%s']", _name, _service, _scope, _target); + } + return _string; + } + + public static String buildFilter( + Class<?> serviceType, + String target, + ReferenceScope scope, + Set<Annotation> qualifiers) + throws InvalidSyntaxException { + + StringBuilder sb = new StringBuilder(); + + sb.append("(&("); + sb.append(Constants.OBJECTCLASS); + sb.append("="); + sb.append(serviceType.getName()); + sb.append(")"); + + if (scope == ReferenceScope.PROTOTYPE) { + sb.append("("); + sb.append(Constants.SERVICE_SCOPE); + sb.append("="); + sb.append(Constants.SCOPE_PROTOTYPE); + sb.append(")"); + } + else if (scope == ReferenceScope.SINGLETON) { + sb.append("("); + sb.append(Constants.SERVICE_SCOPE); + sb.append("="); + sb.append(Constants.SCOPE_SINGLETON); + sb.append(")"); + } + else if (scope == ReferenceScope.BUNDLE) { + sb.append("("); + sb.append(Constants.SERVICE_SCOPE); + sb.append("="); + sb.append(Constants.SCOPE_BUNDLE); + sb.append(")"); + } + + String targetFilter = target == null ? "" : target; + + int targetFilterLength = targetFilter.length(); + + if (targetFilterLength > 0) { + FrameworkUtil.createFilter(targetFilter); + + sb.append(targetFilter); + } + + if (qualifiers != null) { + for (Annotation qualifier : qualifiers) { + Class<? extends Annotation> annotationType = qualifier.annotationType(); + + if (annotationType.equals(Reference.class)) { + continue; + } + + Map<String, String> map = Conversions.convert(qualifier).sourceAs(qualifier.annotationType()).to(_mapType); + + Maps.appendFilter(sb, map); + } + } + + sb.append(")"); + + return sb.toString(); + } + + private static Class<?> calculateBeanClass(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType pType = (ParameterizedType)type; + + type = pType.getRawType(); + } + else if (type instanceof WildcardType) { + throw new IllegalArgumentException( + "Cannot use a wildcard as the bean: " + type); + } + + return cast(type); + } + + private static CollectionType calculateCollectionType(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = cast(type); + + Type rawType = parameterizedType.getRawType(); + + if ((List.class == cast(rawType)) || + Collection.class.isAssignableFrom(cast(rawType))) { + + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + + return calculateCollectionType(actualTypeArguments[0]); + } + else if (Map.class == cast(rawType)) { + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + + Type first = actualTypeArguments[0]; + Type second = actualTypeArguments[1]; + + if (!(first instanceof ParameterizedType) && + String.class.isAssignableFrom(cast(first))) { + + if ((!(second instanceof ParameterizedType) && (second == Object.class)) || + (second instanceof WildcardType)) { + + return CollectionType.PROPERTIES; + } + } + } + else if (Map.Entry.class == cast(rawType)) { + return CollectionType.TUPLE; + } + else if (ServiceObjects.class == cast(rawType)) { + return CollectionType.SERVICEOBJECTS; + } + else if (ServiceReference.class == cast(rawType)) { + return CollectionType.REFERENCE; + } + } + else if (Map.Entry.class == cast(type)) { + return CollectionType.TUPLE; + } + else if (ServiceObjects.class == cast(type)) { + return CollectionType.SERVICEOBJECTS; + } + else if (ServiceReference.class == cast(type)) { + return CollectionType.REFERENCE; + } + + return CollectionType.SERVICE; + } + + private static ReferenceCardinality calculateCardinality( + ReferenceCardinality cardinality, Multiplicity multiplicity, Type type) { + + if ((multiplicity == Multiplicity.UNARY) && + ((cardinality == ReferenceCardinality.AT_LEAST_ONE) || (cardinality == ReferenceCardinality.MULTIPLE))) { + + throw new IllegalArgumentException( + format( + "Unary injection point type %s cannot be defined by multiple cardinality %s", + type, cardinality)); + } + else if ((multiplicity == Multiplicity.MULTIPLE) && + ((cardinality == ReferenceCardinality.OPTIONAL) || (cardinality == ReferenceCardinality.MANDATORY))) { + + throw new IllegalArgumentException( + format( + "Multiple injection point type %s cannot be defined by unary cardinality %s", + type, cardinality)); + } + + if ((cardinality == null) || (cardinality == ReferenceCardinality.DEFAULT)) { + switch(multiplicity) { + case MULTIPLE: + return ReferenceCardinality.MULTIPLE; + case UNARY: + return ReferenceCardinality.MANDATORY; + } + } + + return cardinality; + } + + private static Multiplicity calculateMultiplicity(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = cast(type); + + Type rawType = parameterizedType.getRawType(); + + if ((Instance.class == cast(rawType)) || + Collection.class.isAssignableFrom(cast(rawType)) || + ServiceEvent.class == cast(rawType)) { + + return Multiplicity.MULTIPLE; + } + } + + return Multiplicity.UNARY; + } + + public static String calculateName(String name, Class<?> service, Annotated annotated) { + if ((name != null) && (name.length() > 0)) { + return name; + } + + if (annotated != null) { + if (annotated instanceof AnnotatedParameter) { + AnnotatedParameter<?> annotatedParameter = (AnnotatedParameter<?>)annotated; + + return Types.getName(service) + annotatedParameter.getPosition(); + } + if (annotated instanceof AnnotatedField) { + AnnotatedField<?> annotatedField = (AnnotatedField<?>)annotated; + + return annotatedField.getJavaMember().getName(); + } + } + + return Types.getName(service); + } + + private static ReferencePolicy calculatePolicy(ReferencePolicy policy) { + if ((policy == null) || (policy == ReferencePolicy.DEFAULT)) { + return ReferencePolicy.STATIC; + } + + return policy; + } + + private static ReferencePolicyOption calculatePolicyOption(ReferencePolicyOption option) { + if ((option == null) || (option == ReferencePolicyOption.DEFAULT)) { + return ReferencePolicyOption.RELUCTANT; + } + + return option; + } + + private static ReferenceScope calculateScope(ReferenceScope scope) { + if ((scope == null) || (scope == ReferenceScope.DEFAULT)) { + return ReferenceScope.DEFAULT; + } + + return scope; + } + + private static Class<?> calculateServiceClass(Type injectionPointType) { + Type type = injectionPointType; + + if (!(type instanceof ParameterizedType)) { + return cast(type); + } + + ParameterizedType parameterizedType = cast(type); + + Type rawType = parameterizedType.getRawType(); + + if ((List.class == cast(rawType)) || + Collection.class.isAssignableFrom(cast(rawType))) { + + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + + type = actualTypeArguments[0]; + + if (type instanceof ParameterizedType) { + parameterizedType = (ParameterizedType)type; + + rawType = parameterizedType.getRawType(); + } + else if ((type instanceof WildcardType) || + Map.Entry.class.isAssignableFrom(cast(type))) { + + return null; + } + else { + rawType = type; + } + } + + if (!Map.Entry.class.isAssignableFrom(cast(rawType)) && + !ServiceObjects.class.isAssignableFrom(cast(rawType)) && + !ServiceReference.class.isAssignableFrom(cast(rawType))) { + + return cast(rawType); + } + + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + + Type argument = actualTypeArguments[0]; + + if (Map.Entry.class.isAssignableFrom(cast(rawType))) { + if (!checkKey(argument)) { + throw new IllegalArgumentException( + "Tuples must have a key of type Map<String, [? or Object]>: " + argument); + } + + argument = actualTypeArguments[1]; + } + + if (argument instanceof ParameterizedType) { + ParameterizedType parameterizedType1 = cast(argument); + + return cast(parameterizedType1.getRawType()); + } + else if (argument instanceof WildcardType) { + WildcardType wildcardType = (WildcardType)argument; + + if ((wildcardType.getUpperBounds().length == 1)) { + argument = wildcardType.getUpperBounds()[0]; + + if (Object.class.equals(argument)) { + return null; + } + else if (argument instanceof Class) { + return cast(argument); + } + } + + throw new IllegalArgumentException( + "@Reference cannot use nested parameterized types or multiple upper bounds: " + injectionPointType); + } + + return cast(argument); + } + + private static Class<?> calculateServiceClass( + Class<?> service, ReferenceCardinality cardinality, CollectionType collectionType, Type injectionPointType, Annotated annotated) { + + Class<?> calculatedServiceClass = calculateServiceClass(injectionPointType); + + if ((service == null) || (service == Object.class)) { + if (calculatedServiceClass == null) { + throw new IllegalArgumentException( + "Could not determine the service type from @Reference on annotated " + + annotated); + } + + switch(collectionType) { + case PROPERTIES: + if (calculatedServiceClass == Map.class) { + throw new IllegalArgumentException( + "A @Reference cannot bind service properties to a Map<String, Object> without " + + "specifying the @Reference.service property: " + annotated); + } + break; + case REFERENCE: + if (calculatedServiceClass == ServiceReference.class) { + throw new IllegalArgumentException( + "A @Reference cannot bind a ServiceReference without specifying either the " + + "@Reference.service property or a generic type argument (e.g. ServiceReference<Foo>: " + + annotated); + } + break; + case SERVICEOBJECTS: + if (calculatedServiceClass == ServiceObjects.class) { + throw new IllegalArgumentException( + "A @Reference cannot bind a ServiceObjects without specifying either the " + + "@Reference.service property or a generic type argument (e.g. ServiceObjects<Foo>: " + + annotated); + } + break; + case TUPLE: + if (calculatedServiceClass == Map.Entry.class) { + throw new IllegalArgumentException( + "A @Reference cannot bind a Map.Entry without specifying either the " + + "@Reference.service property or a generic type argument (e.g. Map.Entry<Map<String, Object>, Foo>: " + + annotated); + } + break; + default: + } + + return calculatedServiceClass; + } + + switch(collectionType) { + case PROPERTIES: + if (Map.class.isAssignableFrom(calculatedServiceClass)) { + return service; + } + break; + case REFERENCE: + if ((calculatedServiceClass == null) || + ServiceReference.class.isAssignableFrom(calculatedServiceClass)) { + return service; + } + break; + case SERVICEOBJECTS: + if ((calculatedServiceClass == null) || + ServiceObjects.class.isAssignableFrom(calculatedServiceClass)) { + return service; + } + break; + case TUPLE: + if ((calculatedServiceClass != null) && + Map.Entry.class.isAssignableFrom(calculatedServiceClass)) { + + if (!checkKey(calculatedServiceClass)) { + throw new IllegalArgumentException( + "Tuples must have a key of type Map<String, [? or Object]>: " + calculatedServiceClass); + } + + return service; + } + else if ((calculatedServiceClass == null) || + calculatedServiceClass.isAssignableFrom(service)) { + + return service; + } + break; + case SERVICE: + if (((calculatedServiceClass == null) && + ((cardinality == ReferenceCardinality.MULTIPLE) || + (cardinality == ReferenceCardinality.AT_LEAST_ONE))) || + ((calculatedServiceClass != null) && + calculatedServiceClass.isAssignableFrom(service))) { + return service; + } + } + + throw new IllegalArgumentException( + "@Reference.service " + service + " is not compatible with annotated " + annotated); + } + + // check the key type to make sure it complies with Map<String, ?> OR Map<String, Object> + private static boolean checkKey(Type mapEntryType) { + if (!(mapEntryType instanceof ParameterizedType)) { + return false; + } + + ParameterizedType parameterizedKeyType = (ParameterizedType)mapEntryType; + + if ((!Map.class.isAssignableFrom(cast(parameterizedKeyType.getRawType()))) || + (!parameterizedKeyType.getActualTypeArguments()[0].equals(String.class))) { + + return false; + } + + Type valueType = parameterizedKeyType.getActualTypeArguments()[1]; + + if ((!valueType.equals(Object.class) && + ( + (!(valueType instanceof WildcardType)) || + (((WildcardType)valueType).getUpperBounds().length != 1) || + (!((WildcardType)valueType).getUpperBounds()[0].equals(Object.class))))) { + + return false; + } + + return true; + } + + private static ReferenceCardinality _cardinality(Attributes attributes) { + return ReferenceCardinality.get( + getValue(CDI10_URI, CARDINALITY_ATTRIBUTE, attributes, ReferenceCardinality.DEFAULT.toString())); + } + + private static String _name(Attributes attributes) { + return getValue(CDI10_URI, NAME_ATTRIBUTE, attributes); + } + + private static ReferencePolicyOption _option(Attributes attributes) { + return ReferencePolicyOption.get( + getValue(CDI10_URI, POLICY_OPTION_ATTRIBUTE, attributes, ReferencePolicyOption.DEFAULT.toString())); + } + + private static ReferencePolicy _policy(Attributes attributes) { + return ReferencePolicy.get( + getValue(CDI10_URI, POLICY_ATTRIBUTE, attributes, ReferencePolicy.DEFAULT.toString())); + } + + private static ReferenceScope _scope(Attributes attributes) { + return ReferenceScope.get(getValue( + CDI10_URI, SCOPE_ATTRIBUTE, attributes, ReferenceScope.DEFAULT.toString())); + } + + private static String _target(Attributes attributes) { + return getValue(CDI10_URI, TARGET_ATTRIBUTE, attributes); + } + + private static Type upwrapCDITypes(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType pType = (ParameterizedType)type; + + Type rawType = pType.getRawType(); + + if (Instance.class == cast(rawType) || + ServiceEvent.class == cast(rawType)) { + + type = pType.getActualTypeArguments()[0]; + } + } + + return type; + } + + private static final TypeReference<Map<String, String>> _mapType = new TypeReference<Map<String, String>>(){}; + + private final Class<?> _beanClass; + private final ReferenceCardinality _cardinality; + private final CollectionType _collectionType; + private final AtomicBoolean _found = new AtomicBoolean(); + private final Type _injectionPointType; + private final String _name; + private final ReferencePolicyOption _option; + private final ReferencePolicy _policy; + private final Set<Annotation> _qualifiers; + private final ReferenceScope _scope; + private final Class<?> _service; + private String _string; + private final String _target; + private final Set<Type> _types; + + private static class ReferenceAnnotated implements Annotated { + + public ReferenceAnnotated(Class<?> service) { + _service = service; + } + + @Override + public <T extends Annotation> T getAnnotation(Class<T> annotationType) { + return null; + } + + @Override + public Set<Annotation> getAnnotations() { + return Collections.emptySet(); + } + + @Override + public Type getBaseType() { + return _service; + } + + @Override + public Set<Type> getTypeClosure() { + return Sets.hashSet(_service); + } + + @Override + public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { + return false; + } + + private final Class<?> _service; + + } + +}
Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/service/ServiceDeclaration.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/service/ServiceDeclaration.java?rev=1807424&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/service/ServiceDeclaration.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/service/ServiceDeclaration.java Tue Sep 5 22:01:11 2017 @@ -0,0 +1,173 @@ +/** + * 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.aries.cdi.container.internal.service; + +import static org.apache.aries.cdi.container.internal.util.Reflection.cast; + +import java.util.Arrays; +import java.util.Dictionary; +import java.util.stream.Collectors; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; + +import org.apache.aries.cdi.container.internal.component.ComponentModel; +import org.apache.aries.cdi.container.internal.component.ComponentProperties; +import org.apache.aries.cdi.container.internal.container.ContainerState; +import org.apache.aries.cdi.container.internal.util.Types; +import org.osgi.framework.Bundle; +import org.osgi.framework.PrototypeServiceFactory; +import org.osgi.framework.ServiceFactory; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.cdi.annotations.ServiceScope; + +public class ServiceDeclaration { + + public ServiceDeclaration( + ContainerState containerState, + ComponentModel componentModel, + Bean<?> bean, + CreationalContext<?> creationalContext) { + + _containerState = containerState; + _bean = bean; + _creationalContext = creationalContext; + + _componentModel = componentModel; + + Object instance = null; + + if (_componentModel.getServiceScope() == ServiceScope.SINGLETON) { + instance = new SingletonScopeWrapper(); + } + else if (_componentModel.getServiceScope() == ServiceScope.BUNDLE) { + instance = new BundleScopeWrapper(); + } + else if (_componentModel.getServiceScope() == ServiceScope.PROTOTYPE) { + instance = new PrototypeScopeWrapper(); + } + + _instance = instance; + } + + public String[] getClassNames() { + return Arrays.stream( + Types.types(_componentModel, _componentModel.getBeanClass(), _containerState.classLoader()) + ).map( + c -> c.getName() + ).collect( + Collectors.toList() + ).toArray( + new String[0] + ); + } + + public String getName() { + return _componentModel.getName(); + } + + public ServiceScope getScope() { + return _componentModel.getServiceScope(); + } + + public Object getServiceInstance() { + return _instance; + } + + public Dictionary<String, ?> getServiceProperties() { + return new ComponentProperties().bean( + _bean + ).componentModel( + _componentModel + ).containerState( + _containerState + ).build(); + } + + private final Bean<?> _bean; + private final ComponentModel _componentModel; + private final ContainerState _containerState; + private final CreationalContext<?> _creationalContext; + private final Object _instance; + + @SuppressWarnings({"rawtypes"}) + private class BundleScopeWrapper implements ServiceFactory { + + @Override + public Object getService(Bundle bundle, ServiceRegistration registration) { + return _bean.create(cast(_creationalContext)); + } + + @Override + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + _bean.destroy(cast(service), cast(_creationalContext)); + } + + } + + @SuppressWarnings({"rawtypes"}) + private class PrototypeScopeWrapper implements PrototypeServiceFactory { + + @Override + public Object getService(Bundle bundle, ServiceRegistration registration) { + return _bean.create(cast(_creationalContext)); + } + + @Override + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + _bean.destroy(cast(service), cast(_creationalContext)); + } + + } + + @SuppressWarnings({"rawtypes"}) + private class SingletonScopeWrapper implements ServiceFactory { + + @Override + public Object getService(Bundle bundle, ServiceRegistration registration) { + if (_instance == null) { + _instance = _bean.create(cast(_creationalContext)); + } + return _instance; + } + + @Override + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + } + + private Object _instance; + + } + +// private class ManagedServiceFactoryWrapper implements ManagedServiceFactory { +// +// @Override +// public String getName() { +// return _component.name(); +// } +// +// @Override +// public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException { +// } +// +// @Override +// public void deleted(String pid) { +// } +// +// private final Map<String, Object> _instances = new ConcurrentHashMap<>(); +// +// } + +} Modified: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Conversions.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Conversions.java?rev=1807424&r1=1807423&r2=1807424&view=diff ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Conversions.java (original) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Conversions.java Tue Sep 5 22:01:11 2017 @@ -18,6 +18,7 @@ import java.util.Arrays; import org.osgi.util.converter.Converter; import org.osgi.util.converter.ConverterBuilder; +import org.osgi.util.converter.Converting; import org.osgi.util.converter.StandardConverter; import org.osgi.util.converter.TypeRule; @@ -27,8 +28,8 @@ public class Conversions { return INSTANCE._converter.convert(object).defaultValue("").to(String.class); } - public static Converter c() { - return INSTANCE._converter; + public static Converting convert(Object object) { + return INSTANCE._converter.convert(object); } private Conversions() { Modified: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Maps.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Maps.java?rev=1807424&r1=1807423&r2=1807424&view=diff ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Maps.java (original) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Maps.java Tue Sep 5 22:01:11 2017 @@ -70,20 +70,21 @@ public class Maps { map(map, key, type, value); } + @SuppressWarnings("unchecked") static void map(Map<String, Object> map, String key, String type, String value) { PropertyType propertyType = PropertyType.find(type); Object object = map.get(key); if (object == null) { - Object valueObject = Conversions.c().convert(value).to(propertyType.getType()); + Object valueObject = Conversions.convert(value).to(propertyType.getType()); map.put(key, valueObject); return; } - Object valueObject = Conversions.c().convert(value).to(propertyType.componentType()); + Object valueObject = Conversions.convert(value).to(propertyType.componentType()); if (propertyType.isRaw()) { if (!object.getClass().isArray()) { @@ -101,10 +102,12 @@ public class Maps { } } else if (propertyType.isList()) { + @SuppressWarnings("rawtypes") List list = Collections.checkedList((List)object, propertyType.componentType()); list.add(valueObject); } else if (propertyType.isSet()) { + @SuppressWarnings("rawtypes") Set set = Collections.checkedSet((Set)object, propertyType.componentType()); set.add(valueObject); } Modified: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Strings.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Strings.java?rev=1807424&r1=1807423&r2=1807424&view=diff ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Strings.java (original) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Strings.java Tue Sep 5 22:01:11 2017 @@ -19,6 +19,8 @@ import java.util.regex.Pattern; public class Strings { + public static final String[] EMPTY_ARRAY = new String[0]; + private Strings() { // no instances } Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Types.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Types.java?rev=1807424&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Types.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Types.java Tue Sep 5 22:01:11 2017 @@ -0,0 +1,134 @@ +/** + * 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.aries.cdi.container.internal.util; + +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import javax.enterprise.inject.spi.InjectionPoint; + +import org.apache.aries.cdi.container.internal.component.ComponentModel; +import org.osgi.service.cdi.annotations.ServiceScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Types { + + public static String getName(InjectionPoint injectionPoint) { + return getName(injectionPoint.getType()); + } + + public static String getName(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType)type; + + Type rawType = pt.getRawType(); + + if (rawType instanceof Class) { + Class<?> clazz = (Class<?>)rawType; + + return clazz.getSimpleName(); + } + else { + return rawType.getTypeName(); + } + } + else if (type instanceof GenericArrayType) { + GenericArrayType gat = (GenericArrayType)type; + + Type genericComponentType = gat.getGenericComponentType(); + + if (genericComponentType instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType)genericComponentType; + + Type rawType = pt.getRawType(); + + if (rawType instanceof Class) { + Class<?> clazz = (Class<?>)rawType; + + return clazz.getSimpleName(); + } + else { + return rawType.getTypeName(); + } + } + else if (genericComponentType instanceof Class) { + Class<?> clazz = (Class<?>)genericComponentType; + + return clazz.getSimpleName(); + } + else { + return genericComponentType.getTypeName(); + } + } + else if (type instanceof Class) { + Class<?> clazz = (Class<?>)type; + + String simpleName = clazz.getSimpleName(); + + char lowerCase = Character.toLowerCase(simpleName.charAt(0)); + + return lowerCase + simpleName.substring(1, simpleName.length()); + } + + return type.getTypeName(); + } + + public static Class<?>[] types( + ComponentModel componentModel, Class<?> beanClass, ClassLoader classLoader) { + + List<Class<?>> classes = new ArrayList<>(); + + if ((componentModel.getServiceScope() == ServiceScope.DEFAULT) || + (componentModel.getServiceScope() == ServiceScope.NONE)) { + + return new Class<?>[0]; + } + else if (!componentModel.getProvides().isEmpty()) { + for (String provide : componentModel.getProvides()) { + try { + classes.add(classLoader.loadClass(provide)); + } + catch (ReflectiveOperationException roe) { + if (_log.isWarnEnabled()) { + _log.warn( + "CDIe - component {} cannot load provided type {}. Skipping!", + componentModel.getBeanClass(), provide, roe); + } + } + } + } + else { + Class<?>[] interfaces = beanClass.getInterfaces(); + + if (interfaces.length > 0) { + for (Class<?> iface : interfaces) { + classes.add(iface); + } + } + else { + classes.add(beanClass); + } + } + + return classes.toArray(new Class[0]); + } + + public static final Logger _log = LoggerFactory.getLogger(Types.class); + +} \ No newline at end of file Modified: aries/trunk/cdi/cdi-extender/src/main/resources/META-INF/cdi.xsd URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/resources/META-INF/cdi.xsd?rev=1807424&r1=1807423&r2=1807424&view=diff ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/resources/META-INF/cdi.xsd (original) +++ aries/trunk/cdi/cdi-extender/src/main/resources/META-INF/cdi.xsd Tue Sep 5 22:01:11 2017 @@ -29,46 +29,82 @@ the OSGi CDI Extender. OSGi Bean description documents may be embedded in other XML documents. The OSGi CDI Extender will process all XML documents listed in the osgi.beans - attribute of the CDI extender requirement. XML documents containing - OSGi Bean descriptions may contain one or more bean, configuration, - and/or reference elements embedded in a larger document. Use of - the namespace for bean descriptions is mandatory. The attributes - and subelements of bean, configuration, and/or reference elements - are always unqualified. + attribute of the CDI extender requirement. CDI Beans named by the + descriptor are described as components. XML documents containing + OSGi Bean descriptions may contain one or more component elements. + Use of the namespace for bean descriptions is mandatory. The + attributes and subelements of component elements are always + unqualified. </documentation> </annotation> - <element name="bean" type="cdi:Tbean" /> - <complexType name="Tbean"> + <element name="component" type="cdi:Tcomponent" /> + <complexType name="Tcomponent"> <sequence> - <element name="service" maxOccurs="1" minOccurs="0" - type="cdi:Tservice" /> - <any namespace="##other" minOccurs="0" maxOccurs="unbounded" - processContents="lax" /> + <annotation> + <documentation xml:lang="en"> + Implementations of CDI Support must not require component + descriptions to specify the sub-elements of the component + element in the order as required by the schema. CDI Support + implementations must allow other orderings since + arbitrary orderings do not affect the meaning of the + component description. Only the relative ordering of + property elements have meaning. + </documentation> + </annotation> + <element name="configuration" maxOccurs="unbounded" minOccurs="0" type="cdi:Tconfiguration" /> + <element name="property" maxOccurs="unbounded" minOccurs="0" type="cdi:Tproperty" /> + <element name="provide" maxOccurs="unbounded" minOccurs="0" type="cdi:Tprovide" /> + <element name="reference" maxOccurs="unbounded" minOccurs="0" type="cdi:Treference" /> + <any namespace="##other" maxOccurs="unbounded" minOccurs="0" processContents="lax" /> </sequence> <attribute name="class" type="token" use="required" /> + <attribute name="name" type="token" use="optional"> + <annotation> + <documentation xml:lang="en"> + The default value of this attribute is the value of + the class attribute. If multiple component elements use the same + value for the class attribute, then using the default value + for this attribute will result in duplicate names. + In this case, this attribute must be specified with + a unique value. + </documentation> + </annotation> + </attribute> + <attribute name="service-scope" default="none" type="cdi:Tservice_scope" use="optional" /> <anyAttribute processContents="lax" /> </complexType> - <element name="configuration" type="cdi:Tconfiguration" /> <complexType name="Tconfiguration"> <sequence> - <any namespace="##other" minOccurs="0" maxOccurs="unbounded" - processContents="lax" /> + <any namespace="##any" processContents="lax" + minOccurs="0" maxOccurs="unbounded" /> </sequence> - <attribute name="beanClass" type="token" use="required" /> - <attribute name="pid" type="token" use="required" /> - <attribute name="required" type="boolean" default="true" use="optional" /> + <attribute name="configuration-policy" default="optional" type="cdi:Tconfiguration-policy" use="optional" /> + <attribute name="configuration-pid" use="optional"> + <annotation> + <documentation xml:lang="en"> + The default value is the name attribute of the component. + </documentation> + </annotation> + <simpleType> + <restriction> + <simpleType> + <list itemType="token" /> + </simpleType> + <minLength value="1" /> + </restriction> + </simpleType> + </attribute> + <attribute name="type" type="token" use="required" /> <anyAttribute processContents="lax" /> </complexType> - <element name="reference" type="cdi:Treference" /> - <complexType name="Treference"> + <complexType name="Tmulti-value"> <sequence> - <any namespace="##any" processContents="lax" - minOccurs="0" maxOccurs="unbounded" /> + <element name="value" minOccurs="0" maxOccurs="unbounded" type="cdi:Tvalue"/> + <any namespace="##other" minOccurs="0" maxOccurs="unbounded" + processContents="lax" /> </sequence> - <attribute name="beanClass" type="token" use="required" /> - <attribute name="target" type="token" use="required" /> <anyAttribute processContents="lax" /> </complexType> @@ -79,52 +115,92 @@ <element name="list" type="cdi:Tmulti-value"/> <element name="set" type="cdi:Tmulti-value"/> </choice> - <any namespace="##other" minOccurs="0" maxOccurs="unbounded" - processContents="lax" /> + <any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </sequence> <attribute name="name" type="string" use="required" /> <attribute name="value" type="string" use="optional" /> - <attribute name="value-type" type="cdi:Tvalue-types" default="String" use="optional" /> + <attribute name="value-type" default="String" type="cdi:Tvalue-types" use="optional" /> <anyAttribute processContents="lax" /> </complexType> - <complexType name="Tmulti-value"> + <complexType name="Tprovide"> <sequence> - <element name="value" minOccurs="0" maxOccurs="unbounded" type="cdi:Tvalue"/> - <any namespace="##other" minOccurs="0" maxOccurs="unbounded" - processContents="lax" /> + <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded" /> </sequence> + <attribute name="interface" type="token" use="required" /> <anyAttribute processContents="lax" /> </complexType> - <complexType name="Tvalue" mixed="true"> + <complexType name="Treference"> <sequence> - <any namespace="##other" minOccurs="0" maxOccurs="unbounded" - processContents="lax" /> + <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded" /> </sequence> + <attribute name="cardinality" default="1..1" type="cdi:Tcardinality" use="optional" /> + <attribute name="name" type="token" use="optional" /> + <attribute name="policy" default="static" type="cdi:Tpolicy" use="optional" /> + <attribute name="policy-option" default="reluctant" type="cdi:Tpolicy-option" use="optional" /> + <attribute name="scope" default="bundle" type="cdi:Treference_scope" use="optional" /> + <attribute name="service" type="token" use="required" /> + <attribute name="target" type="string" use="optional" /> <anyAttribute processContents="lax" /> </complexType> - <complexType name="Tprovide"> + <complexType name="Tvalue" mixed="true"> <sequence> - <any namespace="##any" processContents="lax" - minOccurs="0" maxOccurs="unbounded" /> + <any namespace="##other" minOccurs="0" maxOccurs="unbounded" + processContents="lax" /> </sequence> - <attribute name="interface" type="token" use="required" /> <anyAttribute processContents="lax" /> </complexType> - <complexType name="Tservice"> - <sequence> - <element name="property" type="cdi:Tproperty" - maxOccurs="unbounded" minOccurs="0" /> - <element name="provide" type="cdi:Tprovide" - minOccurs="1" maxOccurs="unbounded" /> - <any namespace="##other" processContents="lax" - minOccurs="0" maxOccurs="unbounded" /> - </sequence> - <anyAttribute processContents="lax" /> - </complexType> + <simpleType name="Tcardinality"> + <restriction base="string"> + <enumeration value="0..1" /> + <enumeration value="0..n" /> + <enumeration value="1..1" /> + <enumeration value="1..n" /> + </restriction> + </simpleType> + + <simpleType name="Tconfiguration-policy"> + <restriction base="string"> + <enumeration value="factory" /> + <enumeration value="ignore" /> + <enumeration value="optional" /> + <enumeration value="require" /> + </restriction> + </simpleType> + + <simpleType name="Tpolicy"> + <restriction base="string"> + <enumeration value="dynamic" /> + <enumeration value="static" /> + </restriction> + </simpleType> + + <simpleType name="Tpolicy-option"> + <restriction base="string"> + <enumeration value="greedy" /> + <enumeration value="reluctant" /> + </restriction> + </simpleType> + + <simpleType name="Treference_scope"> + <restriction base="string"> + <enumeration value="bundle" /> + <enumeration value="prototype" /> + <enumeration value="prototype_required" /> + </restriction> + </simpleType> + + <simpleType name="Tservice_scope"> + <restriction base="string"> + <enumeration value="bundle" /> + <enumeration value="none" /> + <enumeration value="prototype" /> + <enumeration value="singleton" /> + </restriction> + </simpleType> <!-- Specifies the data type of a property or of the elements in a multi-value property. Numerical and boolean values are trimmed before they are processed. @@ -133,23 +209,23 @@ type of property it will automatically be boxed. --> <simpleType name="Tvalue-types"> <restriction base="string"> - <enumeration value="String" /> - <enumeration value="long" /> - <enumeration value="Long" /> + <enumeration value="boolean" /> + <enumeration value="Boolean" /> + <enumeration value="byte" /> + <enumeration value="Byte" /> + <enumeration value="char" /> + <enumeration value="Character" /> <enumeration value="double" /> <enumeration value="Double" /> <enumeration value="float" /> <enumeration value="Float" /> <enumeration value="int" /> <enumeration value="Integer" /> - <enumeration value="byte" /> - <enumeration value="Byte" /> - <enumeration value="char" /> - <enumeration value="Character" /> - <enumeration value="boolean" /> - <enumeration value="Boolean" /> + <enumeration value="long" /> + <enumeration value="Long" /> <enumeration value="short" /> <enumeration value="Short" /> + <enumeration value="String" /> </restriction> </simpleType> Added: aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/component/ComponentExtension_Ctor_static_reluctant_Test.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/component/ComponentExtension_Ctor_static_reluctant_Test.java?rev=1807424&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/component/ComponentExtension_Ctor_static_reluctant_Test.java (added) +++ aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/component/ComponentExtension_Ctor_static_reluctant_Test.java Tue Sep 5 22:01:11 2017 @@ -0,0 +1,318 @@ +/** + * 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.aries.cdi.container.internal.component; + +import static org.apache.aries.cdi.container.test.TestUtil.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.aries.cdi.container.internal.model.BeansModel; +import org.apache.aries.cdi.container.internal.reference.ReferenceModel; +import org.apache.aries.cdi.container.test.MockCdiContainer; +import org.apache.aries.cdi.container.test.MockCdiContainerAndComponents; +import org.apache.aries.cdi.container.test.beans.Bar; +import org.apache.aries.cdi.container.test.beans.CtorArrayListFoo; +import org.apache.aries.cdi.container.test.beans.CtorFoo; +import org.apache.aries.cdi.container.test.beans.CtorFooBar; +import org.apache.aries.cdi.container.test.beans.CtorFooFoo; +import org.apache.aries.cdi.container.test.beans.CtorFooFooNamed; +import org.apache.aries.cdi.container.test.beans.CtorFooOptional; +import org.apache.aries.cdi.container.test.beans.CtorListFoo; +import org.apache.aries.cdi.container.test.beans.Foo; +import org.apache.aries.cdi.container.test.beans.CtorCollectionFoo; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.osgi.service.cdi.annotations.ReferenceCardinality; +import org.osgi.service.cdi.annotations.ReferencePolicy; +import org.osgi.service.cdi.annotations.ReferencePolicyOption; + +public class ComponentExtension_Ctor_static_reluctant_Test { + + @Test + public void test_CtorArrayListFoo() throws Exception { + try (MockCdiContainerAndComponents container = + new MockCdiContainerAndComponents( + "test", CtorArrayListFoo.class.getName())) { + + BeansModel beansModel = container.containerState().beansModel(); + + Collection<ComponentModel> models = sort(beansModel.getComponentModels()); + + Assert.assertEquals(1, models.size()); + +// List<ReferenceModel> references = container.getTrackedReferences(); +// +// Assert.assertEquals(1, references.size()); +// +// ReferenceModel referenceModel = references.get(0); +// +// Assert.assertEquals(ArrayList.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MULTIPLE, referenceModel.getCardinality()); +// Assert.assertEquals("Foo0", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + } + } + + @Test + public void test_CtorCollectionFoo() throws Exception { + try (MockCdiContainerAndComponents container = new MockCdiContainerAndComponents( + "test", CtorCollectionFoo.class.getName())) { + + BeansModel beansModel = container.containerState().beansModel(); + + Collection<ComponentModel> models = sort(beansModel.getComponentModels()); + + Assert.assertEquals(1, models.size()); + +// List<ReferenceModel> references = container.getTrackedReferences(); +// +// Assert.assertEquals(1, references.size()); +// +// ReferenceModel referenceModel = references.get(0); +// +// Assert.assertEquals(Collection.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MULTIPLE, referenceModel.getCardinality()); +// Assert.assertEquals("Foo0", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + } + } + + @Test + public void test_CtorFooFoo() throws Exception { + try (MockCdiContainerAndComponents container = new MockCdiContainerAndComponents( + "test", CtorFooFoo.class.getName())) { + + BeansModel beansModel = container.containerState().beansModel(); + + Collection<ComponentModel> models = sort(beansModel.getComponentModels()); + + Assert.assertEquals(1, models.size()); + +// List<ReferenceModel> references = container.getTrackedReferences(); +// +// Assert.assertEquals(2, references.size()); +// +// ReferenceModel referenceModel = references.get(0); +// +// Assert.assertEquals(Foo.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MANDATORY, referenceModel.getCardinality()); +// Assert.assertEquals("Foo0", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + } + } + + @Test + public void test_CtorFoo() throws Exception { + try (MockCdiContainerAndComponents container = new MockCdiContainerAndComponents( + "test", CtorFoo.class.getName())) { + + BeansModel beansModel = container.containerState().beansModel(); + + Collection<ComponentModel> models = sort(beansModel.getComponentModels()); + + Assert.assertEquals(1, models.size()); + +// List<ReferenceModel> references = container.getTrackedReferences(); +// +// Assert.assertEquals(1, references.size()); +// +// ReferenceModel referenceModel = references.get(0); +// +// Assert.assertEquals(Foo.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MANDATORY, referenceModel.getCardinality()); +// Assert.assertEquals("Foo0", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + } + } + + @Test + public void test_CtorListFoo() throws Exception { + try (MockCdiContainerAndComponents container = new MockCdiContainerAndComponents( + "test", CtorListFoo.class.getName())) { + + BeansModel beansModel = container.containerState().beansModel(); + + Collection<ComponentModel> models = sort(beansModel.getComponentModels()); + + Assert.assertEquals(1, models.size()); + +// List<ReferenceModel> references = container.getTrackedReferences(); +// +// Assert.assertEquals(1, references.size()); +// +// ReferenceModel referenceModel = references.get(0); +// +// Assert.assertEquals(List.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MULTIPLE, referenceModel.getCardinality()); +// Assert.assertEquals("Foo0", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + } + } + + @Test + public void test_CtorFooBar() throws Exception { + try (MockCdiContainerAndComponents container = new MockCdiContainerAndComponents( + "test", CtorFooBar.class.getName())) { + + BeansModel beansModel = container.containerState().beansModel(); + + Collection<ComponentModel> models = sort(beansModel.getComponentModels()); + + Assert.assertEquals(1, models.size()); + +// List<ReferenceModel> references = container.getTrackedReferences(); +// +// Assert.assertEquals(2, references.size()); +// +// ReferenceModel referenceModel = references.get(0); +// +// Assert.assertEquals(Foo.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MANDATORY, referenceModel.getCardinality()); +// Assert.assertEquals("Foo0", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + +// referenceModel = references.get(1); +// +// Assert.assertEquals(Bar.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MANDATORY, referenceModel.getCardinality()); +// Assert.assertEquals("Bar1", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Bar.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + } + } + + @Test + public void test_CtorFooFooNamed() throws Exception { + try (MockCdiContainerAndComponents container = new MockCdiContainerAndComponents( + "test", CtorFooFooNamed.class.getName())) { + + BeansModel beansModel = container.containerState().beansModel(); + + Collection<ComponentModel> models = sort(beansModel.getComponentModels()); + + Assert.assertEquals(1, models.size()); + +// Collection<ReferenceModel> references = sort(container.getTrackedReferences(), (c1, c2) -> c1.toString().compareTo(c2.toString())); +// +// Assert.assertEquals(2, references.size()); +// +// Iterator<ReferenceModel> referenceIterator = references.iterator(); +// +// ReferenceModel referenceModel = referenceIterator.next(); +// +// Assert.assertEquals(Foo.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MANDATORY, referenceModel.getCardinality()); +// Assert.assertEquals("foo_a", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); +// +// referenceModel = referenceIterator.next(); +// +// Assert.assertEquals(Foo.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.MANDATORY, referenceModel.getCardinality()); +// Assert.assertEquals("foo_b", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + } + } + + @Test + public void test_CtorFooOptional() throws Exception { + try (MockCdiContainerAndComponents container = new MockCdiContainerAndComponents( + "test", CtorFooOptional.class.getName())) { + + BeansModel beansModel = container.containerState().beansModel(); + + Collection<ComponentModel> models = sort(beansModel.getComponentModels()); + + Assert.assertEquals(1, models.size()); + +// Collection<ReferenceModel> references = container.getTrackedReferences(); +// +// Assert.assertEquals(1, references.size()); +// +// Iterator<ReferenceModel> referenceIterator = references.iterator(); +// +// ReferenceModel referenceModel = referenceIterator.next(); +// +// Assert.assertEquals(Foo.class, referenceModel.getBeanClass()); +// Assert.assertEquals( +// ReferenceCardinality.OPTIONAL, referenceModel.getCardinality()); +// Assert.assertEquals("Foo0", referenceModel.getName()); +// Assert.assertEquals(ReferencePolicy.STATIC, referenceModel.getPolicy()); +// Assert.assertEquals( +// ReferencePolicyOption.RELUCTANT, referenceModel.getPolicyOption()); +// Assert.assertNull(referenceModel.getScope()); +// Assert.assertEquals(Foo.class, referenceModel.getServiceClass()); +// Assert.assertEquals("", referenceModel.getTarget()); + } + } + +} \ No newline at end of file Added: aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/configuration/ConfigurationCallbackTest_Ignore.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/configuration/ConfigurationCallbackTest_Ignore.java?rev=1807424&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/configuration/ConfigurationCallbackTest_Ignore.java (added) +++ aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/configuration/ConfigurationCallbackTest_Ignore.java Tue Sep 5 22:01:11 2017 @@ -0,0 +1,355 @@ +/** + * 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.aries.cdi.container.internal.configuration; + +import static org.osgi.framework.Constants.SERVICE_PID; +import static org.apache.aries.cdi.container.test.TestUtil.*; + +import java.util.Dictionary; +import java.util.Hashtable; + +import org.junit.Assert; +import org.junit.Test; +import org.osgi.service.cdi.annotations.ConfigurationPolicy; + +public class ConfigurationCallbackTest_Ignore { + + @Test + public void test_emptyAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + + callback.added(properties); + } + + @Test + public void test_emptyUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + + callback.updated(properties); + } + + @Test + public void test_nullAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.added(null); + } + + @Test + public void test_nullUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.updated(null); + } + + @Test + public void test_addAfterAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.added(properties); + } + + @Test + public void test_addAfterRemove() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + } + + @Test + public void test_addAfterUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.added(properties); + } + + @Test + public void test_removeAfterAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + } + + @Test + public void test_removeAfterRemove() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + } + + @Test + public void test_removeAfterUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "fum"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + } + + @Test + public void test_removeBeforeAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + } + + @Test + public void test_updateAfterAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "fum"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + } + + @Test + public void test_updateAfterRemove() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.updated(properties); + } + + @Test + public void test_updateAfterUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "fum"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "fee"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + } + + @Test + public void test_updateBeforeAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.updated(properties); + } + + private ConfigurationPolicy POLICY = ConfigurationPolicy.IGNORE; + +} Added: aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/configuration/ConfigurationCallbackTest_Optional.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/configuration/ConfigurationCallbackTest_Optional.java?rev=1807424&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/configuration/ConfigurationCallbackTest_Optional.java (added) +++ aries/trunk/cdi/cdi-extender/src/test/java/org/apache/aries/cdi/container/internal/configuration/ConfigurationCallbackTest_Optional.java Tue Sep 5 22:01:11 2017 @@ -0,0 +1,362 @@ +/** + * 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.aries.cdi.container.internal.configuration; + +import static org.osgi.framework.Constants.SERVICE_PID; +import static org.apache.aries.cdi.container.test.TestUtil.*; + +import java.util.Dictionary; +import java.util.Hashtable; + +import org.junit.Assert; +import org.junit.Test; +import org.osgi.service.cdi.annotations.ConfigurationPolicy; + +public class ConfigurationCallbackTest_Optional { + + @Test(expected = IllegalArgumentException.class) + public void test_emptyAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + + callback.added(properties); + } + + @Test(expected = IllegalArgumentException.class) + public void test_emptyUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + + callback.updated(properties); + } + + @Test(expected = IllegalArgumentException.class) + public void test_nullAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.added(null); + } + + @Test(expected = IllegalArgumentException.class) + public void test_nullUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.updated(null); + } + + @Test(expected = IllegalStateException.class) + public void test_addAfterAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + + callback.added(properties); + } + + @Test + public void test_addAfterRemove() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + } + + @Test(expected = IllegalStateException.class) + public void test_addAfterUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + + callback.added(properties); + } + + @Test + public void test_removeAfterAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + } + + @Test(expected = IllegalStateException.class) + public void test_removeAfterRemove() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + } + + @Test + public void test_removeAfterUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + Assert.assertEquals("foo", callback.properties().get(SERVICE_PID)); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "fum"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + Assert.assertEquals("fum", callback.properties().get(SERVICE_PID)); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + } + + @Test(expected = IllegalStateException.class) + public void test_removeBeforeAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.removed(); + } + + @Test + public void test_updateAfterAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + Assert.assertEquals("foo", callback.properties().get(SERVICE_PID)); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "fum"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + Assert.assertEquals("fum", callback.properties().get(SERVICE_PID)); + } + + @Test(expected = IllegalStateException.class) + public void test_updateAfterRemove() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + + callback.removed(); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + callback.updated(properties); + } + + @Test + public void test_updateAfterUpdate() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.added(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + Assert.assertEquals("foo", callback.properties().get(SERVICE_PID)); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "fum"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + Assert.assertEquals("fum", callback.properties().get(SERVICE_PID)); + + properties = new Hashtable<>(); + properties.put(SERVICE_PID, "fee"); + + callback.updated(properties); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertFalse(callback.properties().isEmpty()); + Assert.assertEquals("fee", callback.properties().get(SERVICE_PID)); + } + + @Test(expected = IllegalStateException.class) + public void test_updateBeforeAdd() throws Exception { + ConfigurationCallback callback = getCallback(POLICY); + + Assert.assertTrue(callback.resolved()); + Assert.assertNotNull(callback.properties()); + Assert.assertTrue(callback.properties().isEmpty()); + + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(SERVICE_PID, "foo"); + + callback.updated(properties); + } + + private ConfigurationPolicy POLICY = ConfigurationPolicy.OPTIONAL; + +}
