http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaSEInjectionExtension.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaSEInjectionExtension.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaSEInjectionExtension.java new file mode 100644 index 0000000..024b895 --- /dev/null +++ b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaSEInjectionExtension.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tamaya.cdi; + + +import org.apache.tamaya.inject.ConfigurationInjection; +import org.apache.tamaya.inject.api.Config; +import org.apache.tamaya.inject.api.ConfigDefaultSections; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.Vetoed; +import javax.enterprise.inject.spi.*; +import javax.inject.Inject; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Set; + +/** + * CDI portable extension that integrates {@link org.apache.tamaya.inject.ConfigurationInjector} + * with CDI by adding configuration features to CDI (config enable CDI beans). + */ +@Vetoed +public final class TamayaSEInjectionExtension implements Extension { + + /** + * Method that injects the values into any configured fields, by wrapping the given + * InjectionTarget. + * @param pit the injection target + * @param <T> the target type + */ + public <T> void initializeConfiguredFields(final @Observes ProcessInjectionTarget<T> pit) { + final AnnotatedType<T> at = pit.getAnnotatedType(); + if (!isConfigured(at.getJavaClass())) { + return; + } + final InjectionTarget<T> it = pit.getInjectionTarget(); + InjectionTarget<T> wrapped = new InjectionTarget<T>() { + @Override + public void inject(T instance, CreationalContext<T> ctx) { + it.inject(instance, ctx); + ConfigurationInjection.getConfigurationInjector().configure(instance); + } + + @Override + public void postConstruct(T instance) { + it.postConstruct(instance); + } + + @Override + public void preDestroy(T instance) { + it.dispose(instance); + } + + @Override + public void dispose(T instance) { + it.dispose(instance); + } + + @Override + public Set<InjectionPoint> getInjectionPoints() { + return it.getInjectionPoints(); + } + + @Override + public T produce(CreationalContext<T> ctx) { + return it.produce(ctx); + } + }; + pit.setInjectionTarget(wrapped); + } + + private boolean isConfigured(Class type) { + if (type.getAnnotation(ConfigDefaultSections.class) != null) { + return true; + } + // if no class level annotation is there we might have field level annotations only + for (Field field : type.getDeclaredFields()) { + if (field.isAnnotationPresent(Config.class) && !field.isAnnotationPresent(Inject.class)) { + return true; + } + } + // if no class level annotation is there we might have method level annotations only + for (Method method : type.getDeclaredMethods()) { + if(method.isAnnotationPresent(Config.class)) { + return true; + } + } + return false; + } + + +}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/extra/ConfiguredVetoExtension.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/extra/ConfiguredVetoExtension.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/extra/ConfiguredVetoExtension.java new file mode 100644 index 0000000..a4c1489 --- /dev/null +++ b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/extra/ConfiguredVetoExtension.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tamaya.cdi.extra; + +import org.apache.tamaya.ConfigurationProvider; + +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; + +/** + * CDI Extension that can be used to veto on beans by configuring the fully qualified class names (as regex expression) + * under {@code javax.enterprise.inject.vetoed}. Multiple expression can be added as comma separated values. + */ +public class ConfiguredVetoExtension implements Extension { + + public void observesBean(@Observes ProcessAnnotatedType<?> type){ + String vetoedTypesVal = ConfigurationProvider.getConfiguration().get("javax.enterprise.inject.vetoed"); + String[] vetoedTypes = vetoedTypesVal.split(","); + for(String typeExpr:vetoedTypes){ + if(type.getAnnotatedType().getJavaClass().getName().matches(typeExpr)){ + type.veto(); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIAwareServiceContext.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIAwareServiceContext.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIAwareServiceContext.java deleted file mode 100644 index 5d65ac8..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIAwareServiceContext.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.ConfigException; -import org.apache.tamaya.spi.ServiceContext; - -import javax.annotation.Priority; -import javax.enterprise.inject.Instance; -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; -import java.io.IOException; -import java.net.URL; -import java.text.MessageFormat; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - * <p>This class implements a {@link ServiceContext}, which basically provides a similar loading mechanism as used - * by the {@link ServiceLoader}. Whereas the {@link ServiceLoader} only loads configurations - * and instances from one classloader, this loader manages configs found and the related instances for each - * classloader along the classloader hierarchies individually. It ensures instances are loaded on the classloader - * level, where they first are visible. Additionally it ensures the same configuration resource (and its - * declared services) are loaded multiple times, when going up the classloader hierarchy.</p> - * - * <p>Finally classloaders are not stored by reference by this class, to ensure they still can be garbage collected. - * Refer also the inherited parent class for further details.</p> - * - * <p>This class uses an ordinal of {@code 10}, so it overrides any default {@link ServiceContext} implementations - * provided with the Tamaya core modules.</p> - */ -public class CDIAwareServiceContext implements ServiceContext { - - /** - * Singletons. - */ - private final Map<Class<?>, Object> singletons = new ConcurrentHashMap<>(); - - private ServiceContext defaultServiceContext = new ServiceLoaderServiceContext(); - - - @Override - public <T> T getService(Class<T> serviceType) { - Object cached = singletons.get(serviceType); - if (cached == null) { - Collection<T> services = getServices(serviceType); - if (services.isEmpty()) { - cached = null; - } else { - cached = getServiceWithHighestPriority(services, serviceType); - } - if(cached!=null) { - singletons.put(serviceType, cached); - } - } - return serviceType.cast(cached); - } - - @Override - public <T> T create(Class<T> serviceType) { - T serv = getService(serviceType); - if(serv!=null){ - try { - return (T)serv.getClass().newInstance(); - } catch (Exception e) { - Logger.getLogger(getClass().getName()) - .log(Level.SEVERE, "Failed to create new instance of: " +serviceType.getName(), e); - } - } - return null; - } - - /** - * Loads and registers services. - * - * @param <T> the concrete type. - * @param serviceType The service type. - * @return the items found, never {@code null}. - */ - @Override - public <T> List<T> getServices(final Class<T> serviceType) { - List<T> found = defaultServiceContext.getServices(serviceType); - BeanManager beanManager = TamayaCDIAccessor.getBeanManager(); - Instance<T> cdiInstances = null; - if(beanManager!=null){ - Set<Bean<?>> instanceBeans = beanManager.getBeans(Instance.class); - Bean<?> bean = instanceBeans.iterator().next(); - cdiInstances = (Instance<T>)beanManager.getReference(bean, Instance.class, - beanManager.createCreationalContext(bean)); - } - if(cdiInstances!=null){ - for(T t:cdiInstances.select(serviceType)){ - found.add(t); - } - } - return found; - } - - @Override - public Enumeration<URL> getResources(String resource, ClassLoader cl) throws IOException { - if(cl==null){ - cl = Thread.currentThread().getContextClassLoader(); - } - if(cl==null){ - cl = getClass().getClassLoader(); - } - return cl.getResources(resource); - } - - @Override - public URL getResource(String resource, ClassLoader cl) { - if(cl==null){ - cl = Thread.currentThread().getContextClassLoader(); - } - if(cl==null){ - cl = getClass().getClassLoader(); - } - return cl.getResource(resource); - } - - /** - * Checks the given instance for a @Priority annotation. If present the annotation's value s evaluated. If no such - * annotation is present, a default priority is returned (1); - * @param o the instance, not null. - * @return a priority, by default 1. - */ - public static int getPriority(Object o){ - int prio = 1; //X TODO discuss default priority - Priority priority = o.getClass().getAnnotation(Priority.class); - if (priority != null) { - prio = priority.value(); - } - return prio; - } - - /** - * @param services to scan - * @param <T> type of the service - * - * @return the service with the highest {@link Priority#value()} - * - * @throws ConfigException if there are multiple service implementations with the maximum priority - */ - private <T> T getServiceWithHighestPriority(Collection<T> services, Class<T> serviceType) { - - // we do not need the priority stuff if the list contains only one element - if (services.size() == 1) { - return services.iterator().next(); - } - - Integer highestPriority = null; - int highestPriorityServiceCount = 0; - T highestService = null; - - for (T service : services) { - int prio = getPriority(service); - if (highestPriority == null || highestPriority < prio) { - highestService = service; - highestPriorityServiceCount = 1; - highestPriority = prio; - } else if (highestPriority == prio) { - highestPriorityServiceCount++; - } - } - - if (highestPriorityServiceCount > 1) { - throw new ConfigException(MessageFormat.format("Found {0} implementations for Service {1} with Priority {2}: {3}", - highestPriorityServiceCount, - serviceType.getName(), - highestPriority, - services)); - } - - return highestService; - } - - /** - * Returns ordinal of 20, overriding defaults as well as the inherited (internally used) CLAwareServiceContext - * instance. - * @return ordinal of 20. - */ - @Override - public int ordinal() { - return 20; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredField.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredField.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredField.java deleted file mode 100644 index fa826f5..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredField.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.Configuration; -import org.apache.tamaya.inject.spi.ConfiguredField; - -import javax.enterprise.inject.spi.InjectionPoint; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * CDI implementation for event publishing of configured instances. - */ -class CDIConfiguredField implements ConfiguredField{ - - private final Field field; - private List<String> keys = new ArrayList<>(); - - CDIConfiguredField(InjectionPoint injectionPoint, List<String> keys){ - this.field = (Field)injectionPoint.getMember(); - this.keys.addAll(keys); - this.keys = Collections.unmodifiableList(this.keys); - } - - @Override - public Class<?> getType() { - return field.getType(); - } - - @Override - public Collection<String> getConfiguredKeys() { - return keys; - } - - @Override - public Field getAnnotatedField() { - return field; - } - - @Override - public String getName() { - return field.getName(); - } - - @Override - public String getSignature() { - return getName()+':'+field.getType().getName(); - } - - @Override - public void configure(Object instance, Configuration config) { - throw new UnsupportedOperationException("Use CDI annotations for configuration injection."); - } - - @Override - public String toString() { - return "CDIConfiguredField["+getSignature()+']'; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredMethod.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredMethod.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredMethod.java deleted file mode 100644 index ed8019a..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredMethod.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.Configuration; -import org.apache.tamaya.inject.spi.ConfiguredMethod; - -import javax.enterprise.inject.spi.InjectionPoint; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * Implementation of a configured methods for CDI module. - */ -public class CDIConfiguredMethod implements ConfiguredMethod{ - - private final Method method; - private List<String> keys = new ArrayList<>(); - - CDIConfiguredMethod(InjectionPoint injectionPoint, List<String> keys){ - this.method = (Method)injectionPoint.getMember(); - this.keys.addAll(keys); - this.keys = Collections.unmodifiableList(this.keys); - } - - @Override - public Collection<String> getConfiguredKeys() { - return keys; - } - - @Override - public Class<?>[] getParameterTypes() { - return method.getParameterTypes(); - } - - @Override - public Method getAnnotatedMethod() { - return method; - } - - @Override - public String getName() { - return method.getName(); - } - - @Override - public String getSignature() { - return null; - } - - @Override - public void configure(Object instance, Configuration config) { - throw new UnsupportedOperationException("Use CDI annotations for configuration injection."); - } - - @Override - public String toString() { - return "CDIConfiguredMethod["+getSignature()+']'; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredType.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredType.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredType.java deleted file mode 100644 index c677065..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/CDIConfiguredType.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.Configuration; -import org.apache.tamaya.inject.spi.ConfiguredField; -import org.apache.tamaya.inject.spi.ConfiguredMethod; -import org.apache.tamaya.inject.spi.ConfiguredType; - -import javax.enterprise.inject.spi.InjectionPoint; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; - -/** - * Event published for items configured by CDI extensions. This is for example used by the documentation module - * to automatically track the configuration endpoints for documentation. - */ -class CDIConfiguredType implements ConfiguredType{ - - private final Class<?> type; - private final List<CDIConfiguredMethod> methods = new ArrayList<>(); - private final List<CDIConfiguredField> fields = new ArrayList<>(); - - public CDIConfiguredType(Class<?> type){ - this.type = Objects.requireNonNull(type); - } - - @Override - public Class getType() { - return type; - } - - @Override - public String getName() { - return type.getName(); - } - - @Override - public Collection<ConfiguredField> getConfiguredFields() { - return null; - } - - @Override - public Collection<ConfiguredMethod> getConfiguredMethods() { - return null; - } - - @Override - public void configure(Object instance, Configuration config) { - throw new UnsupportedOperationException("Use CDI annotations for configuration injection."); - } - - /** - * Used to build up during injection point processing. - * @param injectionPoint the CDI injection ppint, not null. - * @param keys the possible config keys, in order of precedence, not null. - */ - void addConfiguredMember(InjectionPoint injectionPoint, List<String> keys) { - Member member = injectionPoint.getMember(); - if(member instanceof Field){ - this.fields.add(new CDIConfiguredField(injectionPoint, keys)); - } else if(member instanceof Method){ - this.methods.add(new CDIConfiguredMethod(injectionPoint, keys)); - } - } - - @Override - public String toString() { - return "CDIConfiguredType{" + - "type=" + type + - ", methods=" + methods + - ", fields=" + fields + - '}'; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationExtension.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationExtension.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationExtension.java deleted file mode 100644 index 4524461..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationExtension.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.ConfigException; -import org.apache.tamaya.ConfigOperator; -import org.apache.tamaya.Configuration; -import org.apache.tamaya.ConfigurationProvider; -import org.apache.tamaya.inject.api.Config; -import org.apache.tamaya.inject.api.ConfigDefaultSections; -import org.apache.tamaya.inject.api.WithConfigOperator; -import org.apache.tamaya.inject.api.WithPropertyConverter; -import org.apache.tamaya.spi.PropertyConverter; - -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.event.Observes; -import javax.enterprise.inject.spi.AfterBeanDiscovery; -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.Extension; -import javax.enterprise.inject.spi.InjectionPoint; -import javax.enterprise.inject.spi.ProcessBean; -import javax.enterprise.inject.spi.ProcessProducerMethod; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Logger; - - -/** - * CDI Extension module that adds injection mechanism for configuration. - * - * @see org.apache.tamaya.inject.api.Config - * @see org.apache.tamaya.inject.api.ConfigDefaultSections - * @see ConfigException - */ -public class ConfigurationExtension implements Extension { - - private static final Logger LOG = Logger.getLogger(ConfigurationExtension.class.getName()); - - static final Map<Class, ConfigOperator> CUSTOM_OPERATORS = new ConcurrentHashMap<>(); - static final Map<Class, PropertyConverter> CUSTOM_CONVERTERS = new ConcurrentHashMap<>(); - - private final Set<Type> types = new HashSet<>(); - private Bean<?> convBean; - - /** - * Constructor for loading logging its load. - */ - public ConfigurationExtension(){ - LOG.finest("Loading Tamaya CDI Support..."); - } - - /** - * Method that checks the configuration injection points during deployment for available configuration. - * @param pb the bean to process. - * @param beanManager the bean manager to notify about new injections. - */ - public void retrieveTypes(@Observes final ProcessBean<?> pb, BeanManager beanManager) { - - final Set<InjectionPoint> ips = pb.getBean().getInjectionPoints(); - CDIConfiguredType configuredType = new CDIConfiguredType(pb.getBean().getBeanClass()); - - boolean configured = false; - boolean logged = false; - for (InjectionPoint injectionPoint : ips) { - if (injectionPoint.getAnnotated().isAnnotationPresent(Config.class)) { - final Config annotation = injectionPoint.getAnnotated().getAnnotation(Config.class); - final ConfigDefaultSections typeAnnot = injectionPoint.getAnnotated().getAnnotation(ConfigDefaultSections.class); - final List<String> keys = evaluateKeys(injectionPoint.getMember().getName(), - annotation!=null?annotation.value():null, - typeAnnot!=null?typeAnnot.value():null); - - final WithConfigOperator withOperatorAnnot = injectionPoint.getAnnotated().getAnnotation(WithConfigOperator.class); - if(withOperatorAnnot!=null){ - tryLoadOpererator(withOperatorAnnot.value()); - } - final WithPropertyConverter withConverterAnnot = injectionPoint.getAnnotated().getAnnotation(WithPropertyConverter.class); - if(withConverterAnnot!=null){ - tryLoadConverter(withConverterAnnot.value()); - } - - // We don't want to wait until the injection really fails at runtime. - // If there is a non resolvable configuration, we want to know at startup. - Configuration config = ConfigurationProvider.getConfiguration(); - String value = null; - for(String key:keys) { - value = config.get(key); - if(value!=null){ - break; - } - } - if(value==null && !annotation.defaultValue().isEmpty()){ - value = annotation.defaultValue(); - } - if(value==null){ - throw new ConfigException(String.format( - "Cannot resolve any of the possible configuration keys: %s. Please provide one of the given keys " + - "with a value in your configuration sources.", - keys.toString())); - } - types.add(injectionPoint.getType()); - if(annotation!=null){ - configured = true; - if(!logged) { - LOG.finest("Enabling Tamaya CDI Configuration on bean: " + configuredType.getName()); - } - configuredType.addConfiguredMember(injectionPoint, keys); - } - } - } - if(configured) { - beanManager.fireEvent(configuredType); - } - } - - - public void captureConvertBean(@Observes final ProcessProducerMethod<?, ?> ppm) { - if (ppm.getAnnotated().isAnnotationPresent(Config.class)) { - convBean = ppm.getBean(); - } - - } - - public void addConverter(@Observes final AfterBeanDiscovery abd, final BeanManager bm) { - if(!types.isEmpty()) { - abd.addBean(new ConverterBean(convBean, types)); - } - } - - private void tryLoadOpererator(Class<? extends ConfigOperator> operatorClass) { - Objects.requireNonNull(operatorClass); - if(ConfigOperator.class == operatorClass){ - return; - } - try{ - if(!CUSTOM_OPERATORS.containsKey(operatorClass)) { - CUSTOM_OPERATORS.put(operatorClass, operatorClass.newInstance()); - } - } catch(Exception e){ - throw new ConfigException("Custom ConfigOperator could not be loaded: " + operatorClass.getName(), e); - } - } - - private void tryLoadConverter(Class<? extends PropertyConverter> converterClass) { - Objects.requireNonNull(converterClass); - if(PropertyConverter.class == converterClass){ - return; - } - try{ - if(!CUSTOM_CONVERTERS.containsKey(converterClass)) { - CUSTOM_CONVERTERS.put(converterClass, converterClass.newInstance()); - } - } catch(Exception e){ - throw new ConfigException("Custom PropertyConverter could not be loaded: " + converterClass.getName(), e); - } - } - - /** - * Evaluates the effective keys to be used. if no {@code keys} are defined, {@code memberName} is used. - * The effective keys are then combined with the sections given (if any) and only, if the given keys are not - * absolute keys (surrounded by brackets). - * @param memberName the default member name, not null. - * @param keys the keys, may be empty, or null. - * @param sections the default sections, may be empty. May also be null. - * @return the list of keys to be finally used for configuration resolution in order of - * precedence. The first keys in the list that could be successfully resolved define the final - * configuration value. - */ - public static List<String> evaluateKeys(String memberName, String[] keys, String[] sections) { - List<String> effKeys = new ArrayList<>(); - if(keys!=null){ - effKeys.addAll(Arrays.asList(keys)); - } - if (effKeys.isEmpty()) { - effKeys.add(memberName); - } - ListIterator<String> iterator = effKeys.listIterator(); - while (iterator.hasNext()) { - String next = iterator.next(); - if (next.startsWith("[") && next.endsWith("]")) { - // absolute key, strip away brackets, take key as is - iterator.set(next.substring(1, next.length() - 1)); - } else { - if (sections != null && sections.length>0) { - // Remove original entry, since it will be replaced with prefixed entries - iterator.remove(); - // Add prefixed entries, including absolute (root) entry for "" area keys. - for (String area : sections) { - iterator.add(area.isEmpty() ? next : area + '.' + next); - } - } - } - } - return effKeys; - } - - - /** - * Internally used conversion bean. - */ - private static class ConverterBean implements Bean<Object> { - - private final Bean<Object> delegate; - private final Set<Type> types; - - public ConverterBean(final Bean convBean, final Set<Type> types) { - this.types = types; - this.delegate = convBean; - } - - @Override - public Set<Type> getTypes() { - return types; - } - - @Override - public Class<?> getBeanClass() { - return delegate.getBeanClass(); - } - - @Override - public Set<InjectionPoint> getInjectionPoints() { - return delegate.getInjectionPoints(); - } - - @Override - public String getName() { - return delegate.getName(); - } - - @Override - public Set<Annotation> getQualifiers() { - return delegate.getQualifiers(); - } - - @Override - public Class<? extends Annotation> getScope() { - return delegate.getScope(); - } - - @Override - public Set<Class<? extends Annotation>> getStereotypes() { - return delegate.getStereotypes(); - } - - @Override - public boolean isAlternative() { - return delegate.isAlternative(); - } - - @Override - public boolean isNullable() { - return delegate.isNullable(); - } - - @Override - public Object create(CreationalContext<Object> creationalContext) { - return delegate.create(creationalContext); - } - - @Override - public void destroy(Object instance, CreationalContext<Object> creationalContext) { - delegate.destroy(instance, creationalContext); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationProducer.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationProducer.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationProducer.java deleted file mode 100644 index aa3eacc..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationProducer.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.*; -import org.apache.tamaya.inject.api.*; -import org.apache.tamaya.spi.ConfigurationContext; -import org.apache.tamaya.spi.ConfigurationContextBuilder; -import org.apache.tamaya.spi.ConversionContext; -import org.apache.tamaya.spi.PropertyConverter; - -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.inject.Produces; -import javax.enterprise.inject.spi.InjectionPoint; -import java.io.File; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.sql.Time; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Producer bean for configuration properties. - */ -@ApplicationScoped -public class ConfigurationProducer { - - private static final Logger LOGGER = Logger.getLogger(ConfigurationProducer.class.getName()); - - private DynamicValue createDynamicValue(final InjectionPoint injectionPoint) { - Member member = injectionPoint.getMember(); - if (member instanceof Field) { - return DefaultDynamicValue.of((Field) member, ConfigurationProvider.getConfiguration()); - } else if (member instanceof Method) { - return DefaultDynamicValue.of((Method) member, ConfigurationProvider.getConfiguration()); - } - return null; - } - - @Produces - @Config - public File resolveAndConvert_File(final InjectionPoint injectionPoint) { - return (File)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public BigDecimal resolveAndConvert_BigDecimal(final InjectionPoint injectionPoint) { - return (BigDecimal)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public BigInteger resolveAndConvert_BigInteger(final InjectionPoint injectionPoint) { - return (BigInteger)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Number resolveAndConvert_Number(final InjectionPoint injectionPoint) { - return (Number)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Boolean resolveAndConvert_Boolean(final InjectionPoint injectionPoint) { - return (Boolean)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Byte resolveAndConvert_Byte(final InjectionPoint injectionPoint) { - return (Byte)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Short resolveAndConvert_Short(final InjectionPoint injectionPoint) { - return (Short)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Integer resolveAndConvert_Integer(final InjectionPoint injectionPoint) { - return (Integer)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Long resolveAndConvert_Long(final InjectionPoint injectionPoint) { - return (Long)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Float resolveAndConvert_Float(final InjectionPoint injectionPoint) { - return (Float)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Double resolveAndConvert_Double(final InjectionPoint injectionPoint) { - return (Double)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Date resolveAndConvert_Date(final InjectionPoint injectionPoint) { - return (Date)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public String resolveAndConvert_String(final InjectionPoint injectionPoint) { - return (String)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public GregorianCalendar resolveAndConvert_GregorianCalendar(final InjectionPoint injectionPoint) { - return (GregorianCalendar)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Calendar resolveAndConvert_Calendar(final InjectionPoint injectionPoint) { - return (Calendar)resolveAndConvert(injectionPoint); - } - - @Produces - @Config - public Object resolveAndConvert(final InjectionPoint injectionPoint) { - if (DynamicValue.class.equals(injectionPoint.getAnnotated().getBaseType())) { - return createDynamicValue(injectionPoint); - } - final Config annotation = injectionPoint.getAnnotated().getAnnotation(Config.class); - final ConfigDefaultSections typeAnnot = injectionPoint.getAnnotated().getAnnotation(ConfigDefaultSections.class); - final List<String> keys = TamayaCDIInjectionExtension.evaluateKeys(injectionPoint.getMember().getName(), - annotation != null ? annotation.value() : null, - typeAnnot != null ? typeAnnot.value() : null); - - final WithConfigOperator withOperatorAnnot = injectionPoint.getAnnotated().getAnnotation(WithConfigOperator.class); - ConfigOperator operator = null; - if (withOperatorAnnot != null) { - operator = TamayaCDIInjectionExtension.CUSTOM_OPERATORS.get(withOperatorAnnot.value()); - } - PropertyConverter customConverter = null; - final WithPropertyConverter withConverterAnnot = injectionPoint.getAnnotated().getAnnotation(WithPropertyConverter.class); - if (withConverterAnnot != null) { - customConverter = TamayaCDIInjectionExtension.CUSTOM_CONVERTERS.get(withConverterAnnot.value()); - } - - // unless the extension is not installed, this should never happen because the extension - // enforces the resolvability of the config - Configuration config = ConfigurationProvider.getConfiguration(); - if (operator != null) { - config = operator.operate(config); - } - final Class<?> toType = (Class<?>) injectionPoint.getAnnotated().getBaseType(); - String textValue = null; - String defaultTextValue = annotation.defaultValue().isEmpty() ? "" : annotation.defaultValue(); - String keyFound = null; - for (String key : keys) { - textValue = config.get(key); - if (textValue != null) { - keyFound = key; - break; - } - } - ConversionContext.Builder builder = new ConversionContext.Builder(config, - ConfigurationProvider.getConfiguration().getContext(), keyFound, TypeLiteral.of(toType)); - if (injectionPoint.getMember() instanceof AnnotatedElement) { - builder.setAnnotatedElement((AnnotatedElement) injectionPoint.getMember()); - } - ConversionContext conversionContext = builder.build(); - Object value = null; - if (keyFound != null) { - if (customConverter != null) { - value = customConverter.convert(textValue, conversionContext); - } - if (value == null) { - value = config.get(keyFound, toType); - } - } else if (defaultTextValue != null) { - value = defaultTextValue; - if (customConverter != null) { - value = customConverter.convert((String)value, conversionContext); - } - if (value != null) { - List<PropertyConverter<Object>> converters = ConfigurationProvider.getConfiguration().getContext() - .getPropertyConverters(TypeLiteral.of(toType)); - for (PropertyConverter<Object> converter : converters) { - try { - value = converter.convert(defaultTextValue, conversionContext); - if (value != null) { - LOGGER.log(Level.FINEST, "Parsed default value from '" + defaultTextValue + "' into " + - injectionPoint); - break; - } - } catch (Exception e) { - LOGGER.log(Level.FINEST, "Failed to convert default value '" + defaultTextValue + "' for " + - injectionPoint, e); - } - } - } - } - if (value == null) { - throw new ConfigException(String.format( - "Can't resolve any of the possible config keys: %s to the required target type: %s, supported formats: %s", - keys.toString(), toType.getName(), conversionContext.getSupportedFormats().toString())); - } - LOGGER.finest(String.format("Injecting %s for key %s in class %s", keyFound, value.toString(), injectionPoint.toString())); - return value; - } - - @Produces - public Configuration getConfiguration(){ - return ConfigurationProvider.getConfiguration(); - } - - @Produces - public ConfigurationContext getConfigurationContext(){ - return ConfigurationProvider.getConfiguration().getContext(); - } - - @Produces - public ConfigurationContextBuilder getConfigurationContextBuilder(){ - return ConfigurationProvider.getConfigurationContextBuilder(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/DefaultDynamicValue.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/DefaultDynamicValue.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/DefaultDynamicValue.java deleted file mode 100644 index 2c21405..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/DefaultDynamicValue.java +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.ConfigException; -import org.apache.tamaya.Configuration; -import org.apache.tamaya.TypeLiteral; -import org.apache.tamaya.inject.api.DynamicValue; -import org.apache.tamaya.inject.api.LoadPolicy; -import org.apache.tamaya.inject.api.UpdatePolicy; -import org.apache.tamaya.inject.api.WithPropertyConverter; -import org.apache.tamaya.inject.spi.BaseDynamicValue; -import org.apache.tamaya.inject.spi.InjectionUtils; -import org.apache.tamaya.spi.ConversionContext; -import org.apache.tamaya.spi.PropertyConverter; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.*; -import java.util.logging.Logger; - -/** - * A accessor for a single configured value. This can be used to support values that may change during runtime, - * reconfigured or final. Hereby external code (could be Tamaya configuration listners or client code), can set a - * new value. Depending on the {@link UpdatePolicy} the new value is immedeately active or it requires an active commit - * by client code. Similarly an instance also can ignore all later changes to the value. - * <h3>Implementation Details</h3> - * This class is - * <ul> - * <li>Serializable, when also the item stored is serializable</li> - * <li>Thread safe</li> - * </ul> - * - * @param <T> The type of the value. - */ -final class DefaultDynamicValue<T> extends BaseDynamicValue<T> { - - private static final long serialVersionUID = -2071172847144537443L; - - /** - * The property name of the entry. - */ - private final String propertyName; - /** - * The keys to be resolved. - */ - private final String[] keys; - /** - * Back reference to the base configuration instance. This reference is used reevalaute the given property and - * compare the result with the previous value after a configuration change was triggered. - */ - private final Configuration configuration; - /** - * The target type of the property used to lookup a matching {@link PropertyConverter}. - * If null, {@code propertyConverter} is set and used instead. - */ - private final TypeLiteral<T> targetType; - /** - * The property converter to be applied, may be null. In the ladder case targetType is not null. - */ - private final PropertyConverter<T> propertyConverter; - /** - * Policy that defines how new values are applied, be default it is applied initially once, but never updated - * anymore. - */ - private UpdatePolicy updatePolicy; - /** - * Load policy. - */ - private final LoadPolicy loadPolicy; - - /** - * The current value, never null. - */ - private transient T value; - /** - * The new value, or null. - */ - private transient Object[] newValue; - /** - * List of listeners that listen for changes. - */ - private transient WeakList<PropertyChangeListener> listeners; - - /** - * Constructor. - * - * @param propertyName the name of the fields' property/method. - * @param keys the keys of the property, not null. - * @param configuration the configuration, not null. - * @param targetType the target type, not null. - * @param propertyConverter the optional converter to be used. - */ - private DefaultDynamicValue(String propertyName, Configuration configuration, TypeLiteral<T> targetType, - PropertyConverter<T> propertyConverter, List<String> keys, LoadPolicy loadPolicy, - UpdatePolicy updatePolicy) { - this.propertyName = Objects.requireNonNull(propertyName); - this.keys = keys.toArray(new String[keys.size()]); - this.configuration = Objects.requireNonNull(configuration); - this.propertyConverter = propertyConverter; - this.targetType = targetType; - this.loadPolicy = Objects.requireNonNull(loadPolicy); - this.updatePolicy = Objects.requireNonNull(updatePolicy); - if(loadPolicy == LoadPolicy.INITIAL){ - this.value = evaluateValue(); - } - } - - public static DynamicValue of(Field annotatedField, Configuration configuration) { - return of(annotatedField, configuration, LoadPolicy.ALWAYS, UpdatePolicy.IMMEDIATE); - } - - public static DynamicValue of(Field annotatedField, Configuration configuration, LoadPolicy loadPolicy) { - return of(annotatedField, configuration, loadPolicy, UpdatePolicy.IMMEDIATE); - } - - public static DynamicValue of(Field annotatedField, Configuration configuration, UpdatePolicy updatePolicy) { - return of(annotatedField, configuration, LoadPolicy.ALWAYS, updatePolicy); - } - - public static DynamicValue of(Field annotatedField, Configuration configuration, LoadPolicy loadPolicy, UpdatePolicy updatePolicy) { - // Check for adapter/filter - Type targetType = annotatedField.getGenericType(); - if (targetType == null) { - throw new ConfigException("Failed to evaluate target type for " + annotatedField.getDeclaringClass().getName() - + '.' + annotatedField.getName()); - } - if (targetType instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) targetType; - Type[] types = pt.getActualTypeArguments(); - if (types.length != 1) { - throw new ConfigException("Failed to evaluate target type for " + annotatedField.getDeclaringClass().getName() - + '.' + annotatedField.getName()); - } - targetType = types[0]; - } - PropertyConverter<?> propertyConverter = null; - WithPropertyConverter annot = annotatedField.getAnnotation(WithPropertyConverter.class); - if (annot != null) { - try { - propertyConverter = annot.value().newInstance(); - } catch (Exception e) { - throw new ConfigException("Failed to instantiate annotated PropertyConverter on " + - annotatedField.getDeclaringClass().getName() - + '.' + annotatedField.getName(), e); - } - } - List<String> keys = InjectionUtils.getKeys(annotatedField); - return new DefaultDynamicValue(annotatedField.getName(), configuration, - TypeLiteral.of(targetType), propertyConverter, keys, loadPolicy, updatePolicy); - } - - public static DynamicValue of(Method method, Configuration configuration) { - return of(method, configuration, LoadPolicy.ALWAYS, UpdatePolicy.IMMEDIATE); - } - - public static DynamicValue of(Method method, Configuration configuration, UpdatePolicy updatePolicy) { - return of(method, configuration, LoadPolicy.ALWAYS, updatePolicy); - } - - public static DynamicValue of(Method method, Configuration configuration, LoadPolicy loadPolicy) { - return of(method, configuration, loadPolicy, UpdatePolicy.IMMEDIATE); - } - - public static DynamicValue of(Method method, Configuration configuration, LoadPolicy loadPolicy, UpdatePolicy updatePolicy) { - // Check for adapter/filter - Type targetType = method.getGenericReturnType(); - if (targetType == null) { - throw new ConfigException("Failed to evaluate target type for " + method.getDeclaringClass() - .getName() + '.' + method.getName()); - } - if (targetType instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) targetType; - Type[] types = pt.getActualTypeArguments(); - if (types.length != 1) { - throw new ConfigException("Failed to evaluate target type for " + method.getDeclaringClass() - .getName() + '.' + method.getName()); - } - targetType = types[0]; - } - PropertyConverter<Object> propertyConverter = null; - WithPropertyConverter annot = method.getAnnotation(WithPropertyConverter.class); - if (annot != null) { - try { - propertyConverter = (PropertyConverter<Object>) annot.value().newInstance(); - } catch (Exception e) { - throw new ConfigException("Failed to instantiate annotated PropertyConverter on " + - method.getDeclaringClass().getName() - + '.' + method.getName(), e); - } - } - return new DefaultDynamicValue<>(method.getName(), - configuration, TypeLiteral.of(targetType), propertyConverter, InjectionUtils.getKeys(method), - loadPolicy, updatePolicy); - } - - - /** - * Commits a new value that has not been committed yet, make it the new value of the instance. On change any - * registered listeners will be triggered. - */ - public void commit() { - T oldValue = value; - value = newValue==null?null:(T)newValue[0]; - newValue = null; - informListeners(oldValue, value); - } - - private void informListeners(T value, T newValue) { - synchronized (this) { - PropertyChangeEvent evt = new PropertyChangeEvent(this, propertyName, value, - newValue); - if (listeners != null) { - for (PropertyChangeListener consumer : listeners.get()) { - consumer.propertyChange(evt); - } - } - } - } - - /** - * Discards a new value that was published. No listeners will be informed. - */ - public void discard() { - newValue = null; - } - - - /** - * Access the {@link UpdatePolicy} used for updating this value. - * - * @return the update policy, never null. - */ - public UpdatePolicy getUpdatePolicy() { - return updatePolicy; - } - - /** - * Sets a new {@link UpdatePolicy}. - * - * @param updatePolicy the new policy, not null. - */ - public void setUpdatePolicy(UpdatePolicy updatePolicy) { - this.updatePolicy = Objects.requireNonNull(updatePolicy); - } - - /** - * Add a listener to be called as weak reference, when this value has been changed. - * - * @param l the listener, not null - */ - public void addListener(PropertyChangeListener l) { - if (listeners == null) { - listeners = new WeakList<>(); - } - listeners.add(l); - } - - /** - * Removes a listener to be called, when this value has been changed. - * - * @param l the listner to be removed, not null - */ - public void removeListener(PropertyChangeListener l) { - if (listeners != null) { - listeners.remove(l); - } - } - - /** - * If a value is present in this {@code DynamicValue}, returns the value, - * otherwise throws {@code ConfigException}. - * - * @return the non-null value held by this {@code Optional} - * @throws ConfigException if there is no value present - * @see DefaultDynamicValue#isPresent() - */ - public T get() { - T newLocalValue; - if(loadPolicy!=LoadPolicy.INITIAL) { - newLocalValue = evaluateValue(); - if (this.value == null) { - this.value = newLocalValue; - } - if(!Objects.equals(this.value, newLocalValue)){ - switch (updatePolicy){ - case IMMEDEATE: - case IMMEDIATE: - commit(); - break; - case EXPLCIT: - case EXPLICIT: - this.newValue = new Object[]{newLocalValue}; - break; - case LOG_ONLY: - informListeners(this.value, newLocalValue); - this.newValue = null; - break; - case NEVER: - this.newValue = null; - break; - default: - this.newValue = null; - break; - } - } - } - return value; - } - - /** - * Method to check for and apply a new value. Depending on the {@link UpdatePolicy} - * the value is immediately or deferred visible (or it may even be ignored completely). - * - * @return true, if a new value has been detected. The value may not be visible depending on the current - * {@link UpdatePolicy} in place. - */ - public boolean updateValue() { - if(this.value==null && this.newValue==null){ - this.value = evaluateValue(); - return false; - } - T newValue = evaluateValue(); - if (Objects.equals(newValue, this.value)) { - return false; - } - switch (this.updatePolicy) { - case LOG_ONLY: - Logger.getLogger(getClass().getName()).info("Discard change on " + this + ", newValue=" + newValue); - informListeners(value, newValue); - this.newValue = null; - break; - case NEVER: - this.newValue = null; - break; - case EXPLCIT: - case IMMEDEATE: - default: - this.newValue = new Object[]{newValue}; - commit(); - break; - } - return true; - } - - /** - * Evaluates the current value dynamically from the underlying configuration. - * - * @return the current actual value, or null. - */ - public T evaluateValue() { - T value = null; - - for (String key : keys) { - if (propertyConverter == null) { - value = configuration.get(key, targetType); - } else { - String source = configuration.get(key); - ConversionContext ctx = new ConversionContext.Builder(configuration, - configuration.getContext(), key, targetType).build(); - value = propertyConverter.convert(source, ctx); - } - - if (value != null) { - break; - } - } - - return value; - } - - /** - * Access a new value that has not yet been committed. - * - * @return the uncommitted new value, or null. - */ - public T getNewValue() { - T nv = newValue==null?null:(T)newValue[0]; - if (nv != null) { - return nv; - } - return null; - } - - - /** - * Serialization implementation that strips away the non serializable Optional part. - * - * @param oos the output stream - * @throws IOException if serialization fails. - */ - private void writeObject(ObjectOutputStream oos) throws IOException { - oos.writeObject(getUpdatePolicy()); - oos.writeObject(get()); - } - - /** - * Reads an instance from the input stream. - * - * @param ois the object input stream - * @throws IOException if deserialization fails. - * @throws ClassNotFoundException - */ - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - this.updatePolicy = (UpdatePolicy) ois.readObject(); - if (isPresent()) { - this.value = (T) ois.readObject(); - } - newValue = null; - } - - - /** - * Simple helper that allows keeping the listeners registered as weak references, hereby avoiding any - * memory leaks. - * - * @param <I> the type - */ - private class WeakList<I> { - final List<WeakReference<I>> refs = new LinkedList<>(); - - /** - * Adds a new instance. - * - * @param t the new instance, not null. - */ - void add(I t) { - refs.add(new WeakReference<>(t)); - } - - /** - * Removes a instance. - * - * @param t the instance to be removed. - */ - void remove(I t) { - synchronized (refs) { - for (Iterator<WeakReference<I>> iterator = refs.iterator(); iterator.hasNext(); ) { - WeakReference<I> ref = iterator.next(); - I instance = ref.get(); - if (instance == null || instance == t) { - iterator.remove(); - break; - } - } - } - } - - - /** - * Access a list (copy) of the current instances that were not discarded by the GC. - * - * @return the list of accessible items. - */ - public List<I> get() { - synchronized (refs) { - List<I> res = new ArrayList<>(); - for (Iterator<WeakReference<I>> iterator = refs.iterator(); iterator.hasNext(); ) { - WeakReference<I> ref = iterator.next(); - I instance = ref.get(); - if (instance == null) { - iterator.remove(); - } else { - res.add(instance); - } - } - return res; - } - } - } - - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ServiceLoaderServiceContext.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ServiceLoaderServiceContext.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ServiceLoaderServiceContext.java deleted file mode 100644 index 030b7a3..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/ServiceLoaderServiceContext.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.ConfigException; -import org.apache.tamaya.spi.ServiceContext; -import org.apache.tamaya.spisupport.PriorityServiceComparator; - -import javax.annotation.Priority; -import java.io.IOException; -import java.net.URL; -import java.text.MessageFormat; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * This class implements the (default) {@link ServiceContext} interface and hereby uses the JDK - * {@link ServiceLoader} to load the services required. - */ -final class ServiceLoaderServiceContext implements ServiceContext { - private static final Logger LOG = Logger.getLogger(ServiceLoaderServiceContext.class.getName()); - /** - * List current services loaded, per class. - */ - private final ConcurrentHashMap<Class<?>, List<Object>> servicesLoaded = new ConcurrentHashMap<>(); - /** - * Singletons. - */ - private final Map<Class<?>, Object> singletons = new ConcurrentHashMap<>(); - private Map<Class, Class> factoryTypes = new ConcurrentHashMap<>(); - - @Override - public <T> T getService(Class<T> serviceType) { - Object cached = singletons.get(serviceType); - if (cached == null) { - cached = create(serviceType); - if(cached!=null) { - singletons.put(serviceType, cached); - } - } - return serviceType.cast(cached); - } - - @Override - public <T> T create(Class<T> serviceType) { - Class<? extends T> implType = factoryTypes.get(serviceType); - if(implType==null) { - Collection<T> services = getServices(serviceType); - if (services.isEmpty()) { - return null; - } else { - return getServiceWithHighestPriority(services, serviceType); - } - } - try { - return implType.newInstance(); - } catch (Exception e) { - LOG.log(Level.SEVERE, "Failed to create instabce of " + implType.getName(), e); - return null; - } - } - - /** - * Loads and registers services. - * - * @param <T> the concrete type. - * @param serviceType The service type. - * @return the items found, never {@code null}. - */ - @Override - public <T> List<T> getServices(final Class<T> serviceType) { - List<T> found = (List<T>) servicesLoaded.get(serviceType); - if (found != null) { - return found; - } - List<T> services = new ArrayList<>(); - try { - for (T t : ServiceLoader.load(serviceType)) { - services.add(t); - } - Collections.sort(services, PriorityServiceComparator.getInstance()); - services = Collections.unmodifiableList(services); - } catch (ServiceConfigurationError e) { - LOG.log(Level.WARNING, - "Error loading services current type " + serviceType, e); - if(services==null){ - services = Collections.emptyList(); - } - } - final List<T> previousServices = List.class.cast(servicesLoaded.putIfAbsent(serviceType, (List<Object>) services)); - return previousServices != null ? previousServices : services; - } - - /** - * Checks the given instance for a @Priority annotation. If present the annotation's value s evaluated. If no such - * annotation is present, a default priority is returned (1); - * @param o the instance, not null. - * @return a priority, by default 1. - */ - public static int getPriority(Object o){ - int prio = 1; //X TODO discuss default priority - Priority priority = o.getClass().getAnnotation(Priority.class); - if (priority != null) { - prio = priority.value(); - } - return prio; - } - - /** - * @param services to scan - * @param <T> type of the service - * - * @return the service with the highest {@link Priority#value()} - * - * @throws ConfigException if there are multiple service implementations with the maximum priority - */ - private <T> T getServiceWithHighestPriority(Collection<T> services, Class<T> serviceType) { - T highestService = null; - // we do not need the priority stuff if the list contains only one element - if (services.size() == 1) { - highestService = services.iterator().next(); - this.factoryTypes.put(serviceType, highestService.getClass()); - return highestService; - } - - Integer highestPriority = null; - int highestPriorityServiceCount = 0; - - for (T service : services) { - int prio = getPriority(service); - if (highestPriority == null || highestPriority < prio) { - highestService = service; - highestPriorityServiceCount = 1; - highestPriority = prio; - } else if (highestPriority == prio) { - highestPriorityServiceCount++; - } - } - - if (highestPriorityServiceCount > 1) { - throw new ConfigException(MessageFormat.format("Found {0} implementations for Service {1} with Priority {2}: {3}", - highestPriorityServiceCount, - serviceType.getName(), - highestPriority, - services)); - } - this.factoryTypes.put(serviceType, highestService.getClass()); - return highestService; - } - - @Override - public int ordinal() { - return 1; - } - - @Override - public Enumeration<URL> getResources(String resource, ClassLoader cl) throws IOException{ - if(cl==null){ - cl = Thread.currentThread().getContextClassLoader(); - } - return cl.getResources(resource); - } - - @Override - public URL getResource(String resource, ClassLoader cl){ - if(cl==null){ - cl = Thread.currentThread().getContextClassLoader(); - } - return cl.getResource(resource); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/TamayaCDIAccessor.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/TamayaCDIAccessor.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/TamayaCDIAccessor.java deleted file mode 100644 index 1c0b9a8..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/TamayaCDIAccessor.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.tamaya.integration.cdi; - -import javax.enterprise.event.Observes; -import javax.enterprise.inject.spi.AfterDeploymentValidation; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.Extension; - -/** - * Tamaya main integration with CDI, storing the BeanManager reference for implementation, where no - * JNDI is available or {@code java:comp/env/BeanManager} is not set correctly. - */ -public class TamayaCDIAccessor implements Extension { - /** The BeanManager references stored. */ - private static BeanManager beanManager; - - /** - * Initializes the current BeanManager with the instance passed. - * @param validation the event - * @param beanManager the BeanManager instance - */ - @SuppressWarnings("all") - public void initBeanManager(@Observes AfterDeploymentValidation validation, BeanManager beanManager){ - TamayaCDIAccessor.beanManager = beanManager; - } - - /** - * Get the current {@link BeanManager} instance. - * @return the currently used bean manager. - */ - public static BeanManager getBeanManager(){ - return beanManager; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/346a4f38/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/TamayaCDIInjectionExtension.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/TamayaCDIInjectionExtension.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/TamayaCDIInjectionExtension.java deleted file mode 100644 index 130e3a5..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/integration/cdi/TamayaCDIInjectionExtension.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tamaya.integration.cdi; - -import org.apache.tamaya.ConfigException; -import org.apache.tamaya.ConfigOperator; -import org.apache.tamaya.Configuration; -import org.apache.tamaya.ConfigurationProvider; -import org.apache.tamaya.inject.api.Config; -import org.apache.tamaya.inject.api.ConfigDefaultSections; -import org.apache.tamaya.inject.api.WithConfigOperator; -import org.apache.tamaya.inject.api.WithPropertyConverter; -import org.apache.tamaya.spi.PropertyConverter; - -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.event.Observes; -import javax.enterprise.inject.spi.*; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Logger; - - -/** - * CDI Extension module that adds injection mechanism for configuration. - * - * @see Config - * @see ConfigDefaultSections - * @see ConfigException - */ -public class TamayaCDIInjectionExtension implements Extension { - - private static final Logger LOG = Logger.getLogger(TamayaCDIInjectionExtension.class.getName()); - - static final Map<Class, ConfigOperator> CUSTOM_OPERATORS = new ConcurrentHashMap<>(); - static final Map<Class, PropertyConverter> CUSTOM_CONVERTERS = new ConcurrentHashMap<>(); - - private final Set<Type> types = new HashSet<>(); - private Bean<?> convBean; - - /** - * Constructor for loading logging its load. - */ - public TamayaCDIInjectionExtension(){ - LOG.finest("Loading Tamaya CDI Support..."); - } - - /** - * Method that checks the configuration injection points during deployment for available configuration. - * @param pb the bean to process. - * @param beanManager the bean manager to notify about new injections. - */ - public void retrieveTypes(@Observes final ProcessBean<?> pb, BeanManager beanManager) { - - final Set<InjectionPoint> ips = pb.getBean().getInjectionPoints(); - CDIConfiguredType configuredType = new CDIConfiguredType(pb.getBean().getBeanClass()); - - boolean configured = false; - boolean logged = false; - for (InjectionPoint injectionPoint : ips) { - if (injectionPoint.getAnnotated().isAnnotationPresent(Config.class)) { - final Config annotation = injectionPoint.getAnnotated().getAnnotation(Config.class); - final ConfigDefaultSections typeAnnot = injectionPoint.getAnnotated().getAnnotation(ConfigDefaultSections.class); - final List<String> keys = evaluateKeys(injectionPoint.getMember().getName(), - annotation!=null?annotation.value():null, - typeAnnot!=null?typeAnnot.value():null); - - final WithConfigOperator withOperatorAnnot = injectionPoint.getAnnotated().getAnnotation(WithConfigOperator.class); - if(withOperatorAnnot!=null){ - tryLoadOpererator(withOperatorAnnot.value()); - } - final WithPropertyConverter withConverterAnnot = injectionPoint.getAnnotated().getAnnotation(WithPropertyConverter.class); - if(withConverterAnnot!=null){ - tryLoadConverter(withConverterAnnot.value()); - } - - // We don't want to wait until the injection really fails at runtime. - // If there is a non resolvable configuration, we want to know at startup. - Configuration config = ConfigurationProvider.getConfiguration(); - String value = null; - for(String key:keys) { - value = config.get(key); - if(value!=null){ - break; - } - } - if(value==null && !annotation.defaultValue().isEmpty()){ - value = annotation.defaultValue(); - } - if(value==null){ - throw new ConfigException(String.format( - "Cannot resolve any of the possible configuration keys: %s. Please provide one of the given keys " + - "with a value in your configuration sources.", - keys.toString())); - } - types.add(injectionPoint.getType()); - if(annotation!=null){ - configured = true; - if(!logged) { - LOG.finest("Enabling Tamaya CDI Configuration on bean: " + configuredType.getName()); - } - configuredType.addConfiguredMember(injectionPoint, keys); - } - } - } - if(configured) { - beanManager.fireEvent(configuredType); - } - } - - - public void captureConvertBean(@Observes final ProcessProducerMethod<?, ?> ppm) { - if (ppm.getAnnotated().isAnnotationPresent(Config.class)) { - convBean = ppm.getBean(); - } - - } - - public void addConverter(@Observes final AfterBeanDiscovery abd, final BeanManager bm) { - if(!types.isEmpty()) { - abd.addBean(new ConverterBean(convBean, types)); - } - } - - private void tryLoadOpererator(Class<? extends ConfigOperator> operatorClass) { - Objects.requireNonNull(operatorClass); - if(ConfigOperator.class == operatorClass){ - return; - } - try{ - if(!CUSTOM_OPERATORS.containsKey(operatorClass)) { - CUSTOM_OPERATORS.put(operatorClass, operatorClass.newInstance()); - } - } catch(Exception e){ - throw new ConfigException("Custom ConfigOperator could not be loaded: " + operatorClass.getName(), e); - } - } - - private void tryLoadConverter(Class<? extends PropertyConverter> converterClass) { - Objects.requireNonNull(converterClass); - if(PropertyConverter.class == converterClass){ - return; - } - try{ - if(!CUSTOM_CONVERTERS.containsKey(converterClass)) { - CUSTOM_CONVERTERS.put(converterClass, converterClass.newInstance()); - } - } catch(Exception e){ - throw new ConfigException("Custom PropertyConverter could not be loaded: " + converterClass.getName(), e); - } - } - - /** - * Evaluates the effective keys to be used. if no {@code keys} are defined, {@code memberName} is used. - * The effective keys are then combined with the sections given (if any) and only, if the given keys are not - * absolute keys (surrounded by brackets). - * @param memberName the default member name, not null. - * @param keys the keys, may be empty, or null. - * @param sections the default sections, may be empty. May also be null. - * @return the list of keys to be finally used for configuration resolution in order of - * precedence. The first keys in the list that could be successfully resolved define the final - * configuration value. - */ - public static List<String> evaluateKeys(String memberName, String[] keys, String[] sections) { - List<String> effKeys = new ArrayList<>(); - if(keys!=null){ - effKeys.addAll(Arrays.asList(keys)); - } - if (effKeys.isEmpty()) { - effKeys.add(memberName); - } - ListIterator<String> iterator = effKeys.listIterator(); - while (iterator.hasNext()) { - String next = iterator.next(); - if (next.startsWith("[") && next.endsWith("]")) { - // absolute key, strip away brackets, take key as is - iterator.set(next.substring(1, next.length() - 1)); - } else { - if (sections != null && sections.length>0) { - // Remove original entry, since it will be replaced with prefixed entries - iterator.remove(); - // Add prefixed entries, including absolute (root) entry for "" area keys. - for (String area : sections) { - iterator.add(area.isEmpty() ? next : area + '.' + next); - } - } - } - } - return effKeys; - } - - - /** - * Internally used conversion bean. - */ - private static class ConverterBean implements Bean<Object> { - - private final Bean<Object> delegate; - private final Set<Type> types; - - public ConverterBean(final Bean convBean, final Set<Type> types) { - this.types = types; - this.delegate = convBean; - } - - @Override - public Set<Type> getTypes() { - return types; - } - - @Override - public Class<?> getBeanClass() { - return delegate.getBeanClass(); - } - - @Override - public Set<InjectionPoint> getInjectionPoints() { - return delegate.getInjectionPoints(); - } - - @Override - public String getName() { - return delegate.getName(); - } - - @Override - public Set<Annotation> getQualifiers() { - return delegate.getQualifiers(); - } - - @Override - public Class<? extends Annotation> getScope() { - return delegate.getScope(); - } - - @Override - public Set<Class<? extends Annotation>> getStereotypes() { - return delegate.getStereotypes(); - } - - @Override - public boolean isAlternative() { - return delegate.isAlternative(); - } - - @Override - public boolean isNullable() { - return delegate.isNullable(); - } - - @Override - public Object create(CreationalContext<Object> creationalContext) { - return delegate.create(creationalContext); - } - - @Override - public void destroy(Object instance, CreationalContext<Object> creationalContext) { - delegate.destroy(instance, creationalContext); - } - } - -}