Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/FactoryActivator.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/FactoryActivator.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/FactoryActivator.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/FactoryActivator.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,279 @@ +/** + * 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.model; + +import java.lang.annotation.Annotation; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.enterprise.context.BeforeDestroyed; +import javax.enterprise.context.Destroyed; +import javax.enterprise.context.Initialized; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; + +import org.apache.aries.cdi.container.internal.bean.ReferenceBean; +import org.apache.aries.cdi.container.internal.container.ComponentContext.With; +import org.apache.aries.cdi.container.internal.container.ContainerState; +import org.apache.aries.cdi.container.internal.container.Op; +import org.apache.aries.cdi.container.internal.container.Op.Mode; +import org.apache.aries.cdi.container.internal.container.Op.Type; +import org.apache.aries.cdi.container.internal.util.Maps; +import org.apache.aries.cdi.container.internal.util.SRs; +import org.apache.aries.cdi.container.internal.util.Sets; +import org.apache.aries.cdi.container.internal.util.Syncro; +import org.apache.aries.cdi.container.internal.util.Throw; +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.ServiceScope; +import org.osgi.service.cdi.annotations.ComponentScoped; +import org.osgi.service.log.Logger; + +public class FactoryActivator extends InstanceActivator { + + public static class Builder extends InstanceActivator.Builder<Builder> { + + public Builder(ContainerState containerState) { + super(containerState, null); + } + + @Override + public FactoryActivator build() { + return new FactoryActivator(this); + } + + } + + private FactoryActivator(Builder builder) { + super(builder); + _log = containerState.containerLogs().getLogger(getClass()); + } + + @Override + public boolean close() { + try (Syncro synchro = _lock.open()) { + if (serviceRegistration != null) { + serviceRegistration.unregister(); + serviceRegistration = null; + } + + instance.activations.removeIf( + a -> { + ExtendedActivationDTO extended = (ExtendedActivationDTO)a; + extended.onClose.accept(extended); + return true; + } + ); + + instance.active = false; + + return true; + } + } + + @Override + public Op closeOp() { + return Op.of(Mode.CLOSE, Type.FACTORY_ACTIVATOR, instance.template.name); + } + + @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + public boolean open() { + try (Syncro synchro = _lock.open()) { + if (!instance.referencesResolved() || instance.active) { + return false; + } + + final BeanManager beanManager = containerState.beanManager(); + + ExtendedActivationTemplateDTO activationTemplate = + (ExtendedActivationTemplateDTO)instance.template.activations.get(0); + + instance.template.references.stream().map(ExtendedReferenceTemplateDTO.class::cast).forEach( + t -> { + instance.references.stream().filter( + r -> r.template == t + ).findFirst().map( + ExtendedReferenceDTO.class::cast + ).ifPresent( + r -> { + ReferenceBean bean = t.bean; + bean.setBeanManager(beanManager); + bean.setReferenceDTO(r); + } + ); + } + ); + + instance.template.configurations.stream().map(ExtendedConfigurationTemplateDTO.class::cast).filter( + t -> Objects.nonNull(t.injectionPointType) + ).forEach( + t -> { + t.bean.setProperties(instance.properties); + } + ); + + ExtendedComponentTemplateDTO extended = (ExtendedComponentTemplateDTO)instance.template; + + Set<Bean<?>> beans = beanManager.getBeans( + extended.bean.getBeanClass(), extended.bean.getQualifiers().toArray(new Annotation[0])); + Bean<? extends Object> bean = beanManager.resolve(beans); + + if (activationTemplate.serviceClasses.isEmpty() /* immediate */) { + activate(bean, activationTemplate, beanManager); + + _log.debug(l -> l.debug("CCR `immediate component` {} activated on {}", instance.ident(), bundle())); + } + else if (activationTemplate.scope == ServiceScope.SINGLETON) { + Entry<ExtendedActivationDTO, Object> entry = activate( + bean, activationTemplate, beanManager); + serviceRegistration = containerState.bundleContext().registerService( + activationTemplate.serviceClasses.toArray(new String[0]), + entry.getValue(), + Maps.dict(instance.properties)); + entry.getKey().service = SRs.from(serviceRegistration.getReference()); + + _log.debug(l -> l.debug("CCR `singleton scope service` {} activated on {}", instance.ident(), bundle())); + } + else if (activationTemplate.scope == ServiceScope.BUNDLE) { + serviceRegistration = containerState.bundleContext().registerService( + activationTemplate.serviceClasses.toArray(new String[0]), + new ServiceFactory() { + + @Override + public Object getService(Bundle bundle, ServiceRegistration registration) { + Entry<ExtendedActivationDTO, Object> entry = activate( + bean, activationTemplate, beanManager); + entry.getKey().service = SRs.from(registration.getReference()); + _locals.put(entry.getValue(), entry.getKey()); + return entry.getValue(); + } + + @Override + public void ungetService(Bundle bundle, ServiceRegistration registration, Object object) { + ExtendedActivationDTO activationDTO = _locals.remove(object); + + if (activationDTO != null) { + activationDTO.onClose.accept(activationDTO); + } + } + + final Map<Object, ExtendedActivationDTO> _locals = new ConcurrentHashMap<>(); + + }, + Maps.dict(instance.properties) + ); + + _log.debug(l -> l.debug("CCR `bundle scope service` {} activated on {}", instance.ident(), bundle())); + } + else if (activationTemplate.scope == ServiceScope.PROTOTYPE) { + serviceRegistration = containerState.bundleContext().registerService( + activationTemplate.serviceClasses.toArray(new String[0]), + new PrototypeServiceFactory() { + + @Override + public Object getService(Bundle bundle, ServiceRegistration registration) { + Entry<ExtendedActivationDTO, Object> entry = activate( + bean, activationTemplate, beanManager); + entry.getKey().service = SRs.from(registration.getReference()); + _locals.put(entry.getValue(), entry.getKey()); + return entry.getValue(); + } + + @Override + public void ungetService(Bundle bundle, ServiceRegistration registration, Object object) { + ExtendedActivationDTO activationDTO = _locals.remove(object); + + if (activationDTO != null) { + activationDTO.onClose.accept(activationDTO); + } + } + + final Map<Object, ExtendedActivationDTO> _locals = new ConcurrentHashMap<>(); + + }, + Maps.dict(instance.properties) + ); + + _log.debug(l -> l.debug("CCR `prototype scope service` {} activated on {}", instance.ident(), bundle())); + } + + instance.active = true; + + return true; + } + } + + @Override + public Op openOp() { + return Op.of(Mode.OPEN, Type.FACTORY_ACTIVATOR, instance.template.name); + } + + @Override + public String toString() { + return Arrays.asList(getClass().getSimpleName(), instance.ident()).toString(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + Entry<ExtendedActivationDTO, Object> activate( + Bean<? extends Object> bean, + ExtendedActivationTemplateDTO activationTemplate, + BeanManager beanManager) { + + ExtendedActivationDTO activationDTO = new ExtendedActivationDTO(); + activationDTO.errors = new CopyOnWriteArrayList<>(); + activationDTO.template = activationTemplate; + instance.activations.add(activationDTO); + + try (With with = new With(activationDTO)) { + try { + final Object object = containerState.componentContext().get( + (Bean)bean, + (CreationalContext)beanManager.createCreationalContext(bean)); + final Set<Annotation> qualifiers = bean.getQualifiers(); + beanManager.fireEvent(object, Sets.hashSet(qualifiers, Initialized.Literal.of(ComponentScoped.class)).toArray(new Annotation[0])); + activationDTO.onClose = a -> { + try (With with2 = new With(a)) { + beanManager.fireEvent(object, Sets.hashSet(qualifiers, BeforeDestroyed.Literal.of(ComponentScoped.class)).toArray(new Annotation[0])); + containerState.componentContext().destroy(); + beanManager.fireEvent(object, Sets.hashSet(qualifiers, Destroyed.Literal.of(ComponentScoped.class)).toArray(new Annotation[0])); + instance.activations.remove(a); + } + }; + instance.fireEvents(); + return new AbstractMap.SimpleImmutableEntry<>(activationDTO, object); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR Error single activator create for {} on {}", instance, bundle(), t)); + activationDTO.errors.add(Throw.asString(t)); + return new AbstractMap.SimpleImmutableEntry<>(activationDTO, null); + } + } + } + + private final Syncro _lock = new Syncro(true); + private final Logger _log; + private volatile ServiceRegistration<?> serviceRegistration; + +}
Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/FactoryComponent.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/FactoryComponent.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/FactoryComponent.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/FactoryComponent.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,155 @@ +/** + * 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.model; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.aries.cdi.container.internal.container.ContainerState; +import org.apache.aries.cdi.container.internal.container.Op; +import org.apache.aries.cdi.container.internal.container.Op.Mode; +import org.apache.aries.cdi.container.internal.container.Op.Type; +import org.osgi.service.cdi.MaximumCardinality; +import org.osgi.service.cdi.runtime.dto.ComponentDTO; +import org.osgi.service.cdi.runtime.dto.ComponentInstanceDTO; +import org.osgi.service.cdi.runtime.dto.template.ComponentTemplateDTO; +import org.osgi.service.cdi.runtime.dto.template.ConfigurationTemplateDTO; +import org.osgi.service.log.Logger; + +public class FactoryComponent extends Component { + + public static class Builder extends Component.Builder<Builder> { + + public Builder(ContainerState containerState, FactoryActivator.Builder activatorBuilder) { + super(containerState, activatorBuilder); + } + + @Override + public FactoryComponent build() { + return new FactoryComponent(this); + } + + } + + protected FactoryComponent(Builder builder) { + super(builder); + + _log = containerState.containerLogs().getLogger(getClass()); + + _template = builder._templateDTO; + + _snapshot = new ComponentDTO(); + _snapshot.instances = new CopyOnWriteArrayList<>(); + _snapshot.template = _template; + + containerState.containerDTO().components.add(_snapshot); + + configurationTemplates().stream().filter( + t -> t.maximumCardinality == MaximumCardinality.MANY + ).forEach( + t -> { + containerState.findConfigs(t.pid, true).ifPresent( + arr -> Arrays.stream(arr).forEach( + c -> { + ExtendedComponentInstanceDTO instanceDTO = new ExtendedComponentInstanceDTO(containerState, builder._activatorBuilder); + instanceDTO.activations = new CopyOnWriteArrayList<>(); + instanceDTO.configurations = new CopyOnWriteArrayList<>(); + instanceDTO.pid = c.getPid(); + instanceDTO.properties = null; + instanceDTO.references = new CopyOnWriteArrayList<>(); + instanceDTO.template = builder._templateDTO; + + _snapshot.instances.add(instanceDTO); + } + ) + ); + } + ); + } + + @Override + public boolean close() { + _snapshot.instances.stream().map( + instance -> (ExtendedComponentInstanceDTO)instance + ).forEach( + instance -> { + submit(instance.closeOp(), instance::close).onFailure( + f -> { + _log.error(l -> l.error("CCR Error in factory component close for {} on {}", instance.ident(), containerState.bundle())); + } + ); + } + ); + + return true; + } + + @Override + public Op closeOp() { + return Op.of(Mode.CLOSE, Type.FACTORY_COMPONENT, _template.name); + } + + @Override + public List<ConfigurationTemplateDTO> configurationTemplates() { + return _template.configurations; + } + + @Override + public List<ComponentInstanceDTO> instances() { + return _snapshot.instances; + } + + @Override + public ComponentDTO snapshot() { + return _snapshot; + } + + @Override + public boolean open() { + if (!snapshot().enabled || !containerState.containerDTO().components.get(0).enabled) { + return false; + } + + _snapshot.instances.stream().map( + instance -> (ExtendedComponentInstanceDTO)instance + ).forEach( + instance -> { + submit(instance.openOp(), instance::open).onFailure( + f -> { + _log.error(l -> l.error("CCR Error in factory component open for {} on {}", instance.ident(), containerState.bundle())); + } + ); + } + ); + + return true; + } + + @Override + public Op openOp() { + return Op.of(Mode.OPEN, Type.FACTORY_COMPONENT, _template.name); + } + + @Override + public ComponentTemplateDTO template() { + return _template; + } + + private final Logger _log; + private final ComponentDTO _snapshot; + private final ComponentTemplateDTO _template; + +} Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/InstanceActivator.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/InstanceActivator.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/InstanceActivator.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/InstanceActivator.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,76 @@ +/** + * 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.model; + +import org.apache.aries.cdi.container.internal.container.ContainerState; +import org.apache.aries.cdi.container.internal.container.Op; +import org.apache.aries.cdi.container.internal.container.Phase; +import org.osgi.framework.ServiceReference; + +public abstract class InstanceActivator extends Phase { + + public abstract static class Builder<T extends Builder<T>> { + + public Builder(ContainerState containerState, Phase next) { + _containerState = containerState; + _next = next; + } + + public abstract InstanceActivator build(); + + @SuppressWarnings("unchecked") + public T setInstance(ExtendedComponentInstanceDTO instance) { + _instance = instance; + return (T)this; + } + + @SuppressWarnings("unchecked") + public T setReference(ServiceReference<Object> reference) { + _reference = reference; + return (T)this; + } + + @SuppressWarnings("unchecked") + public T setReferenceDTO(ExtendedReferenceDTO referenceDTO) { + _referenceDTO = referenceDTO; + return (T)this; + } + + private ContainerState _containerState; + private ExtendedComponentInstanceDTO _instance; + private Phase _next; + private ServiceReference<Object> _reference; + private ExtendedReferenceDTO _referenceDTO; + } + + protected InstanceActivator(Builder<?> builder) { + super(builder._containerState, builder._next); + + this.instance = builder._instance; + this.referenceDTO = builder._referenceDTO; + this.reference = builder._reference; + } + + @Override + public abstract Op closeOp(); + + @Override + public abstract Op openOp(); + + protected final ExtendedComponentInstanceDTO instance; + protected final ExtendedReferenceDTO referenceDTO; + protected final ServiceReference<Object> reference; + +} Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/OSGiBean.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/OSGiBean.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/OSGiBean.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/OSGiBean.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,152 @@ +/** + * 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.model; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.aries.cdi.container.internal.bean.ConfigurationBean; +import org.apache.aries.cdi.container.internal.bean.ReferenceBean; +import org.apache.aries.cdi.container.internal.util.Logs; +import org.apache.aries.cdi.container.internal.util.Syncro; +import org.osgi.service.cdi.runtime.dto.template.ComponentTemplateDTO; +import org.osgi.service.cdi.runtime.dto.template.ConfigurationTemplateDTO; +import org.osgi.service.cdi.runtime.dto.template.ReferenceTemplateDTO; + +public class OSGiBean implements Comparable<OSGiBean> { + + public static class Builder { + + public Builder(Logs logs, Class<?> beanClass) { + Objects.requireNonNull(beanClass); + _logs = logs; + _beanClass = beanClass; + } + + public OSGiBean build() { + return new OSGiBean(_logs, _beanClass); + } + + private final Class<?> _beanClass; + private final Logs _logs; + + } + + private OSGiBean(Logs logs, Class<?> beanClass) { + _logs = logs; + _beanClass = beanClass; + } + + public synchronized void addConfiguration(ConfigurationTemplateDTO dto) { + try (Syncro syncro = _lock.open()) { + if (_componentTemplate == null) { + _configurationsQueue.add(dto); + } + else { + ((ExtendedConfigurationTemplateDTO)dto).bean = new ConfigurationBean( + _componentTemplate, (ExtendedConfigurationTemplateDTO)dto); + + _componentTemplate.configurations.add(dto); + } + } + } + + public synchronized void addReference(ReferenceTemplateDTO dto) { + try (Syncro syncro = _lock.open()) { + if (_componentTemplate == null) { + _referencesQueue.add(dto); + } + else { + ((ExtendedReferenceTemplateDTO)dto).bean = new ReferenceBean( + _logs, _componentTemplate, (ExtendedReferenceTemplateDTO)dto); + + _componentTemplate.references.add(dto); + } + } + } + + @Override + public int compareTo(OSGiBean other) { + return _beanClass.getName().compareTo(other._beanClass.getName()); + } + + public boolean found() { + return _found.get(); + } + + public void found(boolean found) { + _found.set(found); + } + + public Class<?> getBeanClass() { + return _beanClass; + } + + public synchronized ComponentTemplateDTO geComponentTemplateDTO() { + try (Syncro syncro = _lock.open()) { + return _componentTemplate; + } + } + + public ComponentTemplateDTO getComponent() { + return _componentTemplate; + } + + public void setComponent(ComponentTemplateDTO componentTemplate) { + try (Syncro syncro = _lock.open()) { + if (_componentTemplate != null) { + return; + } + _componentTemplate = componentTemplate; + _configurationsQueue.removeIf( + dto -> { + ((ExtendedConfigurationTemplateDTO)dto).bean = new ConfigurationBean( + _componentTemplate, (ExtendedConfigurationTemplateDTO)dto); + + _componentTemplate.configurations.add(dto); + return true; + } + ); + _referencesQueue.removeIf( + dto -> { + ((ExtendedReferenceTemplateDTO)dto).bean = new ReferenceBean( + _logs, _componentTemplate, (ExtendedReferenceTemplateDTO)dto); + + _componentTemplate.references.add(dto); + return true; + } + ); + } + } + + @Override + public String toString() { + if (_string == null) { + _string = String.format("OSGiBean[%s]", _beanClass.getName()); + } + return _string; + } + + private final Syncro _lock = new Syncro(true); + private final Logs _logs; + private final Class<?> _beanClass; + private final List<ConfigurationTemplateDTO> _configurationsQueue = new CopyOnWriteArrayList<>(); + private final List<ReferenceTemplateDTO> _referencesQueue = new CopyOnWriteArrayList<>(); + private volatile ComponentTemplateDTO _componentTemplate; + private final AtomicBoolean _found = new AtomicBoolean(); + private volatile String _string; +} Modified: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/ReferenceEventImpl.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/ReferenceEventImpl.java?rev=1829115&r1=1829114&r2=1829115&view=diff ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/ReferenceEventImpl.java (original) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/ReferenceEventImpl.java Sat Apr 14 01:10:27 2018 @@ -14,138 +14,364 @@ package org.apache.aries.cdi.container.internal.model; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.AbstractMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; +import org.apache.aries.cdi.container.internal.container.ContainerState; +import org.apache.aries.cdi.container.internal.container.ReferenceServiceObjectsImpl; +import org.apache.aries.cdi.container.internal.util.Maps; +import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.cdi.reference.ReferenceEvent; import org.osgi.service.cdi.reference.ReferenceServiceObjects; +import org.osgi.service.log.Logger; -public class ReferenceEventImpl<T> implements ReferenceEvent<T> { +public class ReferenceEventImpl<T> implements ParameterizedType, ReferenceEvent<T> { - public static enum Event { ADDING, MODIFIED, REMOVED } - - private final T _t; - private final ReferenceEventImpl.Event _event; - - public ReferenceEventImpl(T t, ReferenceEventImpl.Event event) { - _t = t; - _event = event; + private final Type[] _actualTypeArguments; + private final ContainerState _containerState; + private final Logger _log; + private final Type _rawType = ReferenceEvent.class; + + private final List<ServiceReference<T>> _queue = new CopyOnWriteArrayList<>(); + private final AtomicBoolean _enqueue = new AtomicBoolean(true); + private List<Consumer<T>> onAdding = new CopyOnWriteArrayList<>(); + private List<Consumer<ServiceReference<T>>> onAddingServiceReference = new CopyOnWriteArrayList<>(); + private List<Consumer<ReferenceServiceObjects<T>>> onAddingServiceObjects = new CopyOnWriteArrayList<>(); + private List<Consumer<Map<String, ?>>> onAddingProperties = new CopyOnWriteArrayList<>(); + private List<Consumer<Entry<Map<String, ?>, T>>> onAddingTuple = new CopyOnWriteArrayList<>(); + private List<Consumer<T>> onUpdate = new CopyOnWriteArrayList<>(); + private List<Consumer<ServiceReference<T>>> onUpdateServiceReference = new CopyOnWriteArrayList<>(); + private List<Consumer<ReferenceServiceObjects<T>>> onUpdateServiceObjects = new CopyOnWriteArrayList<>(); + private List<Consumer<Map<String, ?>>> onUpdateProperties = new CopyOnWriteArrayList<>(); + private List<Consumer<Entry<Map<String, ?>, T>>> onUpdateTuple = new CopyOnWriteArrayList<>(); + private List<Consumer<T>> onRemove = new CopyOnWriteArrayList<>(); + private List<Consumer<ServiceReference<T>>> onRemoveServiceReference = new CopyOnWriteArrayList<>(); + private List<Consumer<ReferenceServiceObjects<T>>> onRemoveServiceObjects = new CopyOnWriteArrayList<>(); + private List<Consumer<Map<String, ?>>> onRemoveProperties = new CopyOnWriteArrayList<>(); + private List<Consumer<Entry<Map<String, ?>, T>>> onRemoveTuple = new CopyOnWriteArrayList<>(); + + private volatile T service; + private volatile ReferenceServiceObjects<T> serviceObjects; + + public ReferenceEventImpl(ContainerState containerState, Class<T> serviceClass) { + _containerState = containerState; + _actualTypeArguments = new Type[] {serviceClass}; + _log = _containerState.containerLogs().getLogger(getClass()); + } + + @Override + public Type getRawType() { + return _rawType; + } + + @Override + public Type[] getActualTypeArguments() { + return _actualTypeArguments; + } + + @Override + public Type getOwnerType() { + return null; + } + + public ReferenceEventImpl<T> addingService(ServiceReference<T> reference) { + if (_enqueue.get()) { + _queue.add(reference); + return this; + } + + BundleContext bundleContext = _containerState.bundleContext(); + service = bundleContext.getService(reference); + serviceObjects = new ReferenceServiceObjectsImpl<T>(bundleContext.getServiceObjects(reference)); + Map<String, Object> map = Maps.of(reference.getProperties()); + Entry<Map<String, ?>, T> tuple = new AbstractMap.SimpleImmutableEntry<>(map, service); + + onAdding.removeIf( + c -> { + try { + c.accept(service); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onAddingServiceReference.removeIf( + c -> { + try { + c.accept(reference); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onAddingServiceObjects.removeIf( + c -> { + try { + c.accept(serviceObjects); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onAddingProperties.removeIf( + c -> { + try { + c.accept(map); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onAddingTuple.removeIf( + c -> { + try { + c.accept(tuple); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + + return this; + } + + public ReferenceEventImpl<T> modifiedService(ServiceReference<T> reference) { + if (_enqueue.get()) { + return this; // i.e. do nothing + } + + Map<String, Object> map = Maps.of(reference.getProperties()); + Entry<Map<String, ?>, T> tuple = new AbstractMap.SimpleImmutableEntry<>(map, service); + + onUpdate.removeIf( + c -> { + try { + c.accept(service); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onUpdateServiceReference.removeIf( + c -> { + try { + c.accept(reference); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onUpdateServiceObjects.removeIf( + c -> { + try { + c.accept(serviceObjects); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onUpdateProperties.removeIf( + c -> { + try { + c.accept(map); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onUpdateTuple.removeIf( + c -> { + try { + c.accept(tuple); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + + return this; + } + + public ReferenceEventImpl<T> removedService(ServiceReference<T> reference) { + if (_enqueue.get()) { + _queue.remove(reference); + return this; + } + + Map<String, Object> map = Maps.of(reference.getProperties()); + Entry<Map<String, ?>, T> tuple = new AbstractMap.SimpleImmutableEntry<>(map, service); + + onRemove.removeIf( + c -> { + try { + c.accept(service); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onRemoveServiceReference.removeIf( + c -> { + try { + c.accept(reference); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onRemoveServiceObjects.removeIf( + c -> { + try { + c.accept(serviceObjects); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onRemoveProperties.removeIf( + c -> { + try { + c.accept(map); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + onRemoveTuple.removeIf( + c -> { + try { + c.accept(tuple); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR error in {}", this, t)); + } + return true; + } + ); + + return this; + } + + public boolean flush() { + _enqueue.set(false); + _queue.removeIf( + reference -> { + addingService(reference); + return true; + } + ); + return true; } @Override public void onAdding(Consumer<T> action) { - // TODO Auto-generated method stub - + onAdding.add(action); } @Override public void onAddingServiceReference(Consumer<ServiceReference<T>> consumer) { - // TODO Auto-generated method stub - + onAddingServiceReference.add(consumer); } @Override public void onAddingServiceObjects(Consumer<ReferenceServiceObjects<T>> consumer) { - // TODO Auto-generated method stub - + onAddingServiceObjects.add(consumer); } @Override public void onAddingProperties(Consumer<Map<String, ?>> consumer) { - // TODO Auto-generated method stub - + onAddingProperties.add(consumer); } @Override public void onAddingTuple(Consumer<Entry<Map<String, ?>, T>> consumer) { - // TODO Auto-generated method stub - + onAddingTuple.add(consumer); } @Override - public void onUpdate(Consumer<T> action) { - // TODO Auto-generated method stub - + public void onUpdate(Consumer<T> consumer) { + onUpdate.add(consumer); } @Override public void onUpdateServiceReference(Consumer<ServiceReference<T>> consumer) { - // TODO Auto-generated method stub - + onUpdateServiceReference.add(consumer); } @Override public void onUpdateServiceObjects(Consumer<ReferenceServiceObjects<T>> consumer) { - // TODO Auto-generated method stub - + onUpdateServiceObjects.add(consumer); } @Override public void onUpdateProperties(Consumer<Map<String, ?>> consumer) { - // TODO Auto-generated method stub - + onUpdateProperties.add(consumer); } @Override public void onUpdateTuple(Consumer<Entry<Map<String, ?>, T>> consumer) { - // TODO Auto-generated method stub - + onUpdateTuple.add(consumer); } @Override public void onRemove(Consumer<T> consumer) { - // TODO Auto-generated method stub - + onRemove.add(consumer); } @Override public void onRemoveServiceReference(Consumer<ServiceReference<T>> consumer) { - // TODO Auto-generated method stub - + onRemoveServiceReference.add(consumer); } @Override public void onRemoveServiceObjects(Consumer<ReferenceServiceObjects<T>> consumer) { - // TODO Auto-generated method stub - + onRemoveServiceObjects.add(consumer); } @Override public void onRemoveProperties(Consumer<Map<String, ?>> consumer) { - // TODO Auto-generated method stub - + onRemoveProperties.add(consumer); } @Override public void onRemoveTuple(Consumer<Entry<Map<String, ?>, T>> consumer) { - // TODO Auto-generated method stub - + onRemoveTuple.add(consumer); } -// @Override -// public ServiceEvent<T> adding(Consumer<T> consumer) { -// if (_event == Event.ADDING) { -// consumer.accept(_t); -// }; -// return this; -// } -// -// @Override -// public ServiceEvent<T> modified(Consumer<T> consumer) { -// if (_event == Event.MODIFIED) { -// consumer.accept(_t); -// } -// return this; -// } -// -// @Override -// public ServiceEvent<T> removed(Consumer<T> consumer) { -// if (_event == Event.REMOVED) { -// consumer.accept(_t); -// } -// return this; -// } - } \ No newline at end of file Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/ReferenceModel.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/ReferenceModel.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/ReferenceModel.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/ReferenceModel.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,590 @@ +/** + * 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.model; + +import static org.apache.aries.cdi.container.internal.util.Filters.*; +import static org.apache.aries.cdi.container.internal.util.Reflection.*; + +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.enterprise.inject.Instance; +import javax.enterprise.inject.spi.Annotated; +import javax.enterprise.inject.spi.AnnotatedCallable; +import javax.enterprise.inject.spi.AnnotatedConstructor; +import javax.enterprise.inject.spi.AnnotatedField; +import javax.enterprise.inject.spi.AnnotatedMethod; +import javax.enterprise.inject.spi.AnnotatedParameter; +import javax.enterprise.inject.spi.InjectionPoint; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Qualifier; + +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cdi.MaximumCardinality; +import org.osgi.service.cdi.ReferencePolicy; +import org.osgi.service.cdi.ReferencePolicyOption; +import org.osgi.service.cdi.annotations.Greedy; +import org.osgi.service.cdi.annotations.Prototype; +import org.osgi.service.cdi.annotations.Reference; +import org.osgi.service.cdi.reference.ReferenceEvent; +import org.osgi.service.cdi.reference.ReferenceServiceObjects; + +public class ReferenceModel { + + public static class Builder { + + public Builder() {} + + public Builder(AnnotatedField<?> annotated) { + _annotated = annotated; + _declaringClass = annotated.getDeclaringType().getJavaClass(); + } + + public Builder(AnnotatedMethod<?> annotated) { + _annotated = annotated; + _declaringClass = annotated.getDeclaringType().getJavaClass(); + } + + public Builder(AnnotatedParameter<?> annotated) { + _annotated = annotated; + _declaringClass = annotated.getDeclaringCallable().getDeclaringType().getJavaClass(); + } + + public ReferenceModel build() { + Objects.requireNonNull(_annotated); + Objects.requireNonNull(_declaringClass); + Objects.requireNonNull(_type); + return new ReferenceModel(_type, _declaringClass, _annotated); + } + + public Builder injectionPoint(InjectionPoint injectionPoint) { + _annotated = injectionPoint.getAnnotated(); + _type = injectionPoint.getType(); + + if (_annotated instanceof AnnotatedParameter) { + AnnotatedParameter<?> parameter = (AnnotatedParameter<?>)_annotated; + + _declaringClass = parameter.getDeclaringCallable().getDeclaringType().getJavaClass(); + } + else if (_annotated instanceof AnnotatedField) { + AnnotatedField<?> field = (AnnotatedField<?>)_annotated; + + _declaringClass = field.getDeclaringType().getJavaClass(); + } + + return this; + } + + public Builder type(Type type) { + _type = type; + return this; + } + + private Annotated _annotated; + private Class<?> _declaringClass; + private Type _type; + + } + + public static enum Scope { + BUNDLE, PROTOTYPE, SINGLETON + } + + private ReferenceModel( + Type injectionPointType, + Class<?> declaringClass, + Annotated annotated) { + + _annotated = annotated; + _injectionPointType = injectionPointType; + _declaringClass = declaringClass; + + _reference = _annotated.getAnnotation(Reference.class); + + _referenceType = getReferenceType(); + _referenceTarget = getReferenceTarget(); + _prototype = getQualifiers().stream().filter( + ann -> ann.annotationType().equals(Prototype.class) + ).findFirst().isPresent(); + + calculateServiceType(_injectionPointType); + + _referenceType.ifPresent(c -> { + if ((_serviceType != null) && !_serviceType.isAssignableFrom(c)) { + throw new IllegalArgumentException( + "The service type specified in @Reference (" + c + + ") is not compatible with the type calculated from the injection point: " + + _serviceType + " on " + _annotated); + } + + _serviceType = c; + }); + + Type rawType = _injectionPointType; + + if (rawType instanceof ParameterizedType) { + ParameterizedType pt = cast(_injectionPointType); + + rawType = pt.getRawType(); + } + + _beanClass = cast(rawType); + + _name = calculateName(_serviceType, _annotated); + + if (_annotated.isAnnotationPresent(Greedy.class)) { + _greedy = true; + } + + _targetFilter = buildFilter(); + } + + private Optional<String> getReferenceTarget() { + if ((_reference != null) && (_reference.target().length() > 0)) { + return Optional.of(_reference.target()); + } + return Optional.empty(); + } + + private Optional<Class<?>> getReferenceType() { + if ((_reference != null) && (_reference.value() != null) && (_reference.value() != Object.class)) { + return Optional.of(_reference.value()); + } + return Optional.empty(); + } + + public Annotated getAnnotated() { + return _annotated; + } + + public Class<?> getBeanClass() { + return _beanClass; + } + + public CollectionType getCollectionType() { + return _collectionType; + } + + public Type getInjectionPointType() { + return _injectionPointType; + } + + public String getName() { + return _name; + } + + public Set<Annotation> getQualifiers() { + return _annotated.getAnnotations().stream().filter( + ann -> ann.annotationType().isAnnotationPresent(Qualifier.class) + ).collect(Collectors.toSet()); + } + + public Class<?> getServiceType() { + return _serviceType; + } + + public String getTarget() { + return _targetFilter; + } + + public boolean dynamic() { + return _dynamic; + } + + public boolean optional() { + return _optional; + } + + public ExtendedReferenceTemplateDTO toDTO() { + ExtendedReferenceTemplateDTO dto = new ExtendedReferenceTemplateDTO(); + dto.beanClass = _beanClass; + dto.collectionType = _collectionType; + dto.declaringClass = _declaringClass; + dto.injectionPointType = _injectionPointType; + dto.maximumCardinality = _multiplicity; + dto.minimumCardinality = (_multiplicity == MaximumCardinality.ONE) ? (_optional?0:1) : (0); + dto.name = _name; + dto.policy = (_dynamic) ? ReferencePolicy.DYNAMIC : ReferencePolicy.STATIC; + dto.policyOption = (_greedy) ? ReferencePolicyOption.GREEDY: ReferencePolicyOption.RELUCTANT; + dto.serviceClass = _serviceType; + dto.serviceType = _serviceType.getName(); + dto.targetFilter = _targetFilter; + + return dto; + } + + @Override + public String toString() { + if (_string == null) { + _string = toDTO().toString(); + } + return _string; + } + + public boolean unary() { + return _multiplicity == MaximumCardinality.ONE; + } + + private String buildFilter() { + String targetFilter = _referenceTarget.orElse(_emptyFilter); + boolean filterValid = false; + + int targetFilterLength = targetFilter.length(); + + if ((targetFilterLength > 0) && isValid(targetFilter)) { + filterValid = true; + } + + StringBuilder sb = new StringBuilder(); + + if (_prototype && filterValid) { + sb.append("(&"); + } + + if (_prototype) { + sb.append("("); + sb.append(Constants.SERVICE_SCOPE); + sb.append("="); + sb.append(Constants.SCOPE_PROTOTYPE); + sb.append(")"); + } + + if (filterValid) { + sb.append(targetFilter); + } + +// for (Annotation qualifier : getQualifiers()) { +// Class<? extends Annotation> annotationType = qualifier.annotationType(); +// +// if (annotationType.equals(Reference.class) || +// annotationType.equals(Prototype.class)) { +// +// // TODO filter out blacklisted qualifiers +// +// continue; +// } +// +// Map<String, String> map = Conversions.convert(qualifier).sourceAs(qualifier.annotationType()).to(_mapType); +// +// Maps.appendFilter(sb, map); +// } + + if (_prototype && filterValid) { + sb.append(")"); + } + + return sb.toString(); + } + + private String calculateName(Class<?> service, Annotated annotated) { + Named named = annotated.getAnnotation(Named.class); + + if (named != null) { + if (named.value() == null | named.value().equals("")) { + throw new IllegalArgumentException( + "It's illegal to specify @Name without specifying a value with @Reference: " + + annotated + " on " + _annotated); + } + return named.value(); + } + + String prefix = _declaringClass.getName() + "."; + + if (annotated instanceof AnnotatedParameter) { + AnnotatedParameter<?> parameter = (AnnotatedParameter<?>)annotated; + + AnnotatedCallable<?> declaringCallable = parameter.getDeclaringCallable(); + + if (declaringCallable instanceof AnnotatedConstructor) { + return prefix + "new" + parameter.getPosition(); + } + else { + AnnotatedMethod<?> method = (AnnotatedMethod<?>)declaringCallable; + + return prefix + method.getJavaMember().getName() + parameter.getPosition(); + } + } + else if (annotated instanceof AnnotatedMethod) { + AnnotatedMethod<?> method = (AnnotatedMethod<?>)annotated; + + return prefix + method.getJavaMember().getName(); + } + else { + AnnotatedField<?> annotatedField = (AnnotatedField<?>)annotated; + + return prefix + annotatedField.getJavaMember().getName(); + } + } + + private void calculateServiceType(Type type) { + if (!(type instanceof ParameterizedType)) { + if (!(type instanceof Class)) { + throw new IllegalArgumentException( + "The service type must not be generic: " + type + " on " + _annotated); + } + + Class<?> clazz = cast(type); + + if (Map.class == clazz) { + throw new IllegalArgumentException( + "Map must specify a generic type arguments: " + clazz); + } + else if (Map.Entry.class == clazz) { + throw new IllegalArgumentException( + "Map.Entry must specify a generic type arguments: " + clazz); + } + else if ((ReferenceServiceObjects.class == clazz) && !_referenceType.isPresent()) { + throw new IllegalArgumentException( + "ReferenceServiceObjects must specify a generic type argument: " + clazz); + } + else if ((ServiceReference.class == clazz) && !_referenceType.isPresent()) { + throw new IllegalArgumentException( + "ServiceReference must specify a generic type argument: " + type); + } + else if ((Collection.class == clazz || Iterable.class == clazz || List.class == clazz) && + !_referenceType.isPresent()) { + + throw new IllegalArgumentException( + type + " must specify a generic type argument"); + } + else if (ReferenceServiceObjects.class == clazz) { + _collectionType = CollectionType.SERVICEOBJECTS; + return; + } + else if (ServiceReference.class == clazz) { + _collectionType = CollectionType.REFERENCE; + return; + } + else if (Collection.class == clazz || Iterable.class == clazz || List.class == clazz) { + _collectionType = CollectionType.SERVICE; + _multiplicity = MaximumCardinality.MANY; + _optional = true; + return; + } + + _serviceType = clazz; + + return; + } + + ParameterizedType parameterizedType = cast(type); + + Type rawType = parameterizedType.getRawType(); + + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + + Type argument = actualTypeArguments[0]; + + if (Instance.class == cast(rawType)) { + throw new IllegalArgumentException( + "Instance<T> is not supported with @Reference: " + type); + } + + if (ReferenceEvent.class == cast(rawType)) { + _collectionType = CollectionType.OBSERVER; + _dynamic = true; + _multiplicity = MaximumCardinality.MANY; + _optional = true; + _greedy = true; + + if (argument instanceof WildcardType || + argument instanceof ParameterizedType) { + + throw new IllegalArgumentException( + "Type argument <S> of ReferenceEvent must not be generic: " + argument); + } + + _serviceType = cast(argument); + + return; + } + + if ((!_dynamic) && (Provider.class == cast(rawType))) { + _dynamic = true; + + calculateServiceType(argument); + + return; + } + + if ((!_optional) && (Optional.class == cast(rawType))) { + _optional = true; + + if ((argument instanceof WildcardType) && _referenceType.isPresent()) { + return; + } + + calculateServiceType(argument); + + return; + } + + if ((_multiplicity == MaximumCardinality.ONE) && + ((Collection.class == cast(rawType)) || + (Iterable.class == cast(rawType)) || + (List.class == cast(rawType)))) { + + _optional = true; + _multiplicity = MaximumCardinality.MANY; + + if ((argument instanceof WildcardType) && _referenceType.isPresent()) { + return; + } + + calculateServiceType(argument); + + return; + } + + if (Map.class == cast(rawType)) { + if (String.class != cast(argument)) { + throw new IllegalArgumentException( + "Maps of properties must use the form Map<String, (? | Object)>: " + type); + } + + argument = actualTypeArguments[1]; + + if ((Object.class != cast(argument)) && + (!(argument instanceof WildcardType))) { + + throw new IllegalArgumentException( + "Maps of properties must use the form Map<String, (? | Object)>: " + type); + } + + _collectionType = CollectionType.PROPERTIES; + + if (!_referenceType.isPresent()) { + throw new IllegalArgumentException( + "Maps of properties must specify service type with @Reference.value(): " + argument + " on " + _annotated); + } + + return; + } + + if (Map.Entry.class == cast(rawType)) { + if (!checkKey(argument)) { + throw new IllegalArgumentException( + "Tuples must have a key of type Map<String, (? | Object)>: " + argument + " on " + _annotated); + } + + _collectionType = CollectionType.TUPLE; + + Type second = actualTypeArguments[1]; + + if ((second instanceof WildcardType) && _referenceType.isPresent()) { + return; + } + + if (!(second instanceof Class)) { + throw new IllegalArgumentException( + "The service type must not be generic: " + second + " on " + _annotated); + } + + _serviceType = cast(second); + + return; + } + + if (ReferenceServiceObjects.class == cast(rawType)) { + _collectionType = CollectionType.SERVICEOBJECTS; + + if ((argument instanceof WildcardType) && _referenceType.isPresent()) { + return; + } + + calculateServiceType(argument); + + return; + } + + if (ServiceReference.class == cast(rawType)) { + _collectionType = CollectionType.REFERENCE; + + if ((argument instanceof WildcardType) && _referenceType.isPresent()) { + return; + } + + calculateServiceType(argument); + + return; + } + + _serviceType = cast(rawType); + + if (_serviceType.getTypeParameters().length > 0) { + throw new IllegalArgumentException( + "Illegal service type: " + argument + " on " + _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 final String _emptyFilter = ""; + + private final Annotated _annotated; + private Class<?> _beanClass; + private CollectionType _collectionType = CollectionType.SERVICE; + private final Class<?> _declaringClass; + private boolean _dynamic = false; + private boolean _greedy = false; + private final Type _injectionPointType; + private MaximumCardinality _multiplicity = MaximumCardinality.ONE; + private final String _name; + private boolean _optional = false; + private final boolean _prototype; + private final Reference _reference; + private final Optional<Class<?>> _referenceType; + private final Optional<String> _referenceTarget; + private Class<?> _serviceType; + private String _string; + private final String _targetFilter; +} Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/SingleActivator.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/SingleActivator.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/SingleActivator.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/SingleActivator.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,278 @@ +/** + * 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.model; + +import java.lang.annotation.Annotation; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.enterprise.context.BeforeDestroyed; +import javax.enterprise.context.Destroyed; +import javax.enterprise.context.Initialized; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; + +import org.apache.aries.cdi.container.internal.bean.ReferenceBean; +import org.apache.aries.cdi.container.internal.container.ComponentContext.With; +import org.apache.aries.cdi.container.internal.container.ContainerState; +import org.apache.aries.cdi.container.internal.container.Op; +import org.apache.aries.cdi.container.internal.container.Op.Mode; +import org.apache.aries.cdi.container.internal.util.Maps; +import org.apache.aries.cdi.container.internal.util.SRs; +import org.apache.aries.cdi.container.internal.util.Sets; +import org.apache.aries.cdi.container.internal.util.Syncro; +import org.apache.aries.cdi.container.internal.util.Throw; +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.ServiceScope; +import org.osgi.service.cdi.annotations.ComponentScoped; +import org.osgi.service.log.Logger; + +public class SingleActivator extends InstanceActivator { + + public static class Builder extends InstanceActivator.Builder<Builder> { + + public Builder(ContainerState containerState) { + super(containerState, null); + } + + @Override + public SingleActivator build() { + return new SingleActivator(this); + } + + } + + private SingleActivator(Builder builder) { + super(builder); + _log = containerState.containerLogs().getLogger(getClass()); + } + + @Override + public boolean close() { + try (Syncro synchro = _lock.open()) { + if (serviceRegistration != null) { + serviceRegistration.unregister(); + serviceRegistration = null; + } + + instance.activations.removeIf( + a -> { + ExtendedActivationDTO extended = (ExtendedActivationDTO)a; + extended.onClose.accept(extended); + return true; + } + ); + + instance.active = false; + + return true; + } + } + + @Override + public Op closeOp() { + return Op.of(Mode.CLOSE, Op.Type.SINGLE_ACTIVATOR, instance.template.name); + } + + @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + public boolean open() { + try (Syncro synchro = _lock.open()) { + if (!instance.referencesResolved() || instance.active) { + return false; + } + + final BeanManager beanManager = containerState.beanManager(); + + ExtendedActivationTemplateDTO activationTemplate = + (ExtendedActivationTemplateDTO)instance.template.activations.get(0); + + instance.template.references.stream().map(ExtendedReferenceTemplateDTO.class::cast).forEach( + t -> { + instance.references.stream().filter( + r -> r.template == t + ).findFirst().map( + ExtendedReferenceDTO.class::cast + ).ifPresent( + r -> { + ReferenceBean bean = t.bean; + bean.setBeanManager(beanManager); + bean.setReferenceDTO(r); + } + ); + } + ); + + instance.template.configurations.stream().map(ExtendedConfigurationTemplateDTO.class::cast).filter( + t -> Objects.nonNull(t.injectionPointType) + ).forEach( + t -> { + t.bean.setProperties(instance.properties); + } + ); + + ExtendedComponentTemplateDTO extended = (ExtendedComponentTemplateDTO)instance.template; + + Set<Bean<?>> beans = beanManager.getBeans( + extended.bean.getBeanClass(), extended.bean.getQualifiers().toArray(new Annotation[0])); + Bean<? extends Object> bean = beanManager.resolve(beans); + + if (activationTemplate.serviceClasses.isEmpty() /* immediate */) { + activate(bean, activationTemplate, beanManager); + + _log.debug(l -> l.debug("CCR `immediate component` {} activated on {}", instance.ident(), bundle())); + } + else if (activationTemplate.scope == ServiceScope.SINGLETON) { + Entry<ExtendedActivationDTO, Object> entry = activate( + bean, activationTemplate, beanManager); + serviceRegistration = containerState.bundleContext().registerService( + activationTemplate.serviceClasses.toArray(new String[0]), + entry.getValue(), + Maps.dict(instance.properties)); + entry.getKey().service = SRs.from(serviceRegistration.getReference()); + + _log.debug(l -> l.debug("CCR `singleton scope service` {} activated on {}", instance.ident(), bundle())); + } + else if (activationTemplate.scope == ServiceScope.BUNDLE) { + serviceRegistration = containerState.bundleContext().registerService( + activationTemplate.serviceClasses.toArray(new String[0]), + new ServiceFactory() { + + @Override + public Object getService(Bundle bundle, ServiceRegistration registration) { + Entry<ExtendedActivationDTO, Object> entry = activate( + bean, activationTemplate, beanManager); + entry.getKey().service = SRs.from(registration.getReference()); + _locals.put(entry.getValue(), entry.getKey()); + return entry.getValue(); + } + + @Override + public void ungetService(Bundle bundle, ServiceRegistration registration, Object object) { + ExtendedActivationDTO activationDTO = _locals.remove(object); + + if (activationDTO != null) { + activationDTO.onClose.accept(activationDTO); + } + } + + final Map<Object, ExtendedActivationDTO> _locals = new ConcurrentHashMap<>(); + + }, + Maps.dict(instance.properties) + ); + + _log.debug(l -> l.debug("CCR `bundle scope service` {} activated on {}", instance.ident(), bundle())); + } + else if (activationTemplate.scope == ServiceScope.PROTOTYPE) { + serviceRegistration = containerState.bundleContext().registerService( + activationTemplate.serviceClasses.toArray(new String[0]), + new PrototypeServiceFactory() { + + @Override + public Object getService(Bundle bundle, ServiceRegistration registration) { + Entry<ExtendedActivationDTO, Object> entry = activate( + bean, activationTemplate, beanManager); + entry.getKey().service = SRs.from(registration.getReference()); + _locals.put(entry.getValue(), entry.getKey()); + return entry.getValue(); + } + + @Override + public void ungetService(Bundle bundle, ServiceRegistration registration, Object object) { + ExtendedActivationDTO activationDTO = _locals.remove(object); + + if (activationDTO != null) { + activationDTO.onClose.accept(activationDTO); + } + } + + final Map<Object, ExtendedActivationDTO> _locals = new ConcurrentHashMap<>(); + + }, + Maps.dict(instance.properties) + ); + + _log.debug(l -> l.debug("CCR `prototype scope service` {} activated on {}", instance.ident(), bundle())); + } + + instance.active = true; + + return true; + } + } + + @Override + public Op openOp() { + return Op.of(Mode.OPEN, Op.Type.SINGLE_ACTIVATOR, instance.template.name); + } + + @Override + public String toString() { + return Arrays.asList(getClass().getSimpleName(), instance.ident()).toString(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + Entry<ExtendedActivationDTO, Object> activate( + Bean<? extends Object> bean, + ExtendedActivationTemplateDTO activationTemplate, + BeanManager beanManager) { + + ExtendedActivationDTO activationDTO = new ExtendedActivationDTO(); + activationDTO.errors = new CopyOnWriteArrayList<>(); + activationDTO.template = activationTemplate; + instance.activations.add(activationDTO); + + try (With with = new With(activationDTO)) { + try { + final Object object = containerState.componentContext().get( + (Bean)bean, + (CreationalContext)beanManager.createCreationalContext(bean)); + final Set<Annotation> qualifiers = bean.getQualifiers(); + beanManager.fireEvent(object, Sets.hashSet(qualifiers, Initialized.Literal.of(ComponentScoped.class)).toArray(new Annotation[0])); + activationDTO.onClose = a -> { + try (With with2 = new With(a)) { + beanManager.fireEvent(object, Sets.hashSet(qualifiers, BeforeDestroyed.Literal.of(ComponentScoped.class)).toArray(new Annotation[0])); + containerState.componentContext().destroy(); + beanManager.fireEvent(object, Sets.hashSet(qualifiers, Destroyed.Literal.of(ComponentScoped.class)).toArray(new Annotation[0])); + instance.activations.remove(a); + } + }; + instance.fireEvents(); + return new AbstractMap.SimpleImmutableEntry<>(activationDTO, object); + } + catch (Throwable t) { + _log.error(l -> l.error("CCR Error single activator create for {} on {}", instance, bundle(), t)); + activationDTO.errors.add(Throw.asString(t)); + return new AbstractMap.SimpleImmutableEntry<>(activationDTO, null); + } + } + } + + private final Syncro _lock = new Syncro(true); + private final Logger _log; + private volatile ServiceRegistration<?> serviceRegistration; + +} Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/SingleComponent.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/SingleComponent.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/SingleComponent.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/model/SingleComponent.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,130 @@ +/** + * 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.model; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.aries.cdi.container.internal.container.ContainerState; +import org.apache.aries.cdi.container.internal.container.Op; +import org.apache.aries.cdi.container.internal.container.Op.Mode; +import org.osgi.service.cdi.runtime.dto.ComponentDTO; +import org.osgi.service.cdi.runtime.dto.ComponentInstanceDTO; +import org.osgi.service.cdi.runtime.dto.template.ComponentTemplateDTO; +import org.osgi.service.cdi.runtime.dto.template.ConfigurationTemplateDTO; +import org.osgi.service.log.Logger; + +public class SingleComponent extends Component { + + public static class Builder extends Component.Builder<Builder> { + + public Builder(ContainerState containerState, SingleActivator.Builder activatorBuilder) { + super(containerState, activatorBuilder); + } + + @Override + public SingleComponent build() { + return new SingleComponent(this); + } + + } + + protected SingleComponent(Builder builder) { + super(builder); + + _log = containerState.containerLogs().getLogger(getClass()); + + _template = builder._templateDTO; + + _snapshot = new ComponentDTO(); + _snapshot.instances = new CopyOnWriteArrayList<>(); + _snapshot.template = _template; + + _instanceDTO = new ExtendedComponentInstanceDTO(containerState, builder._activatorBuilder); + _instanceDTO.activations = new CopyOnWriteArrayList<>(); + _instanceDTO.configurations = new CopyOnWriteArrayList<>(); + _instanceDTO.pid = _template.configurations.get(0).pid; + _instanceDTO.properties = null; + _instanceDTO.references = new CopyOnWriteArrayList<>(); + _instanceDTO.template = builder._templateDTO; + + _snapshot.instances.add(_instanceDTO); + + containerState.containerDTO().components.add(_snapshot); + } + + @Override + public boolean close() { + submit(_instanceDTO.closeOp(), _instanceDTO::close).onFailure( + f -> { + _log.error(l -> l.error("CCR Error in single component close for {} on {}", _instanceDTO.ident(), containerState.bundle())); + } + ); + + return true; + } + + @Override + public Op closeOp() { + return Op.of(Mode.CLOSE, Op.Type.SINGLE_COMPONENT, _template.name); + } + + @Override + public List<ConfigurationTemplateDTO> configurationTemplates() { + return _template.configurations; + } + + @Override + public List<ComponentInstanceDTO> instances() { + return Collections.singletonList(_instanceDTO); + } + + @Override + public ComponentDTO snapshot() { + return _snapshot; + } + + @Override + public boolean open() { + if (!snapshot().enabled || !containerState.containerDTO().components.get(0).enabled) { + return false; + } + + submit(_instanceDTO.openOp(), _instanceDTO::open).onFailure( + f -> { + _log.error(l -> l.error("CCR Error in single component open for {} on {}", _instanceDTO.ident(), containerState.bundle())); + } + ); + + return true; + } + + @Override + public Op openOp() { + return Op.of(Mode.OPEN, Op.Type.SINGLE_COMPONENT, _template.name); + } + + @Override + public ComponentTemplateDTO template() { + return _template; + } + + private final ExtendedComponentInstanceDTO _instanceDTO; + private final Logger _log; + private final ComponentDTO _snapshot; + private final ComponentTemplateDTO _template; + +} Copied: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Filters.java (from r1829114, aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Throw.java) URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Filters.java?p2=aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Filters.java&p1=aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Throw.java&r1=1829114&r2=1829115&rev=1829115&view=diff ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Throw.java (original) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Filters.java Sat Apr 14 01:10:27 2018 @@ -14,19 +14,34 @@ package org.apache.aries.cdi.container.internal.util; -public class Throw { +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; - private Throw() { +public class Filters { + + private Filters() { // no instances } - public static <T> T exception(Throwable throwable) { - return Throw.<T, RuntimeException>_exception(throwable); + public static final Filter asFilter(String pattern, Object... objects) { + try { + return FrameworkUtil.createFilter(String.format(pattern, objects)); + } + catch (InvalidSyntaxException ise) { + return Throw.exception(ise); + } } - @SuppressWarnings("unchecked") - private static <T, E extends Throwable> T _exception(Throwable throwable) throws E { - throw (E)throwable; + public static final boolean isValid(String filterString) { + try { + FrameworkUtil.createFilter(filterString); + + return true; + } + catch (InvalidSyntaxException ise) { + return false; + } } -} \ No newline at end of file +} Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Logs.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Logs.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Logs.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Logs.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,241 @@ +/** + * 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 org.osgi.framework.BundleContext; +import org.osgi.service.log.Logger; +import org.osgi.service.log.LoggerConsumer; +import org.osgi.service.log.LoggerFactory; +import org.osgi.util.tracker.ServiceTracker; + +public class Logs { + + public static class Builder { + + public Builder(BundleContext bundleContext) { + _bundleContext = bundleContext; + } + + public Logs build() { + return new Logs(_bundleContext); + } + + private final BundleContext _bundleContext; + + } + + private Logs(BundleContext bundleContext) { + LoggerFactory loggerFactory = null; + + if (bundleContext != null) { + ServiceTracker<LoggerFactory, LoggerFactory> tracker = new ServiceTracker<>(bundleContext, LoggerFactory.class, null); + + tracker.open(); + + loggerFactory = tracker.getService(); + } + + _loggerFactory = loggerFactory; + } + + public Logger getLogger(Class<?> clazz) { + return getLogger(clazz.getName()); + } + + public Logger getLogger(String name) { + if (_loggerFactory != null) { + return _loggerFactory.getLogger(name); + } + + return new SysoutLogger(name); + } + + public LoggerFactory getLoggerFactory() { + return _loggerFactory; + } + + private final LoggerFactory _loggerFactory; + + private static abstract class BaseLogger implements Logger { + + @Override + public <E extends Exception> void debug(LoggerConsumer<E> consumer) throws E { + if (isDebugEnabled()) + consumer.accept(this); + } + + @Override + public <E extends Exception> void error(LoggerConsumer<E> consumer) throws E { + if (isErrorEnabled()) + consumer.accept(this); + } + + @Override + public <E extends Exception> void info(LoggerConsumer<E> consumer) throws E { + if (isInfoEnabled()) + consumer.accept(this); + } + + @Override + public <E extends Exception> void trace(LoggerConsumer<E> consumer) throws E { + if (isTraceEnabled()) + consumer.accept(this); + } + + @Override + public <E extends Exception> void warn(LoggerConsumer<E> consumer) throws E { + if (isWarnEnabled()) + consumer.accept(this); + } + + @Override + public void audit(String message) { + } + + @Override + public void audit(String format, Object arg) { + } + + @Override + public void audit(String format, Object arg1, Object arg2) { + } + + @Override + public void audit(String format, Object... arguments) { + } + + } + + public static class SysoutLogger extends BaseLogger { + + private final String name; + + public SysoutLogger(String name) { + this.name = name; + } + + @Override + public void debug(String message) { + } + + @Override + public void debug(String format, Object arg) { + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + } + + @Override + public void debug(String format, Object... arguments) { + } + + @Override + public void error(String message) { + } + + @Override + public void error(String format, Object arg) { + } + + @Override + public void error(String format, Object arg1, Object arg2) { + } + + @Override + public void error(String format, Object... arguments) { + } + + @Override + public String getName() { + return name; + } + + @Override + public void info(String message) { + } + + @Override + public void info(String format, Object arg) { + } + + @Override + public void info(String format, Object arg1, Object arg2) { + } + + @Override + public void info(String format, Object... arguments) { + } + + @Override + public boolean isDebugEnabled() { + return true; + } + + @Override + public boolean isErrorEnabled() { + return true; + } + + @Override + public boolean isInfoEnabled() { + return true; + } + + @Override + public boolean isTraceEnabled() { + return true; + } + + @Override + public boolean isWarnEnabled() { + return true; + } + + @Override + public void trace(String message) { + } + + @Override + public void trace(String format, Object arg) { + } + + @Override + public void trace(String format, Object arg1, Object arg2) { + } + + @Override + public void trace(String format, Object... arguments) { + } + + @Override + public void warn(String message) { + } + + @Override + public void warn(String format, Object arg) { + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + } + + @Override + public void warn(String format, Object... arguments) { + } + + } + +} \ No newline at end of file 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=1829115&r1=1829114&r2=1829115&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 Sat Apr 14 01:10:27 2018 @@ -14,12 +14,30 @@ package org.apache.aries.cdi.container.internal.util; -import java.lang.reflect.Array; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.Dictionary; +import java.util.Enumeration; import java.util.HashMap; +import java.util.Hashtable; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.enterprise.inject.spi.Annotated; +import javax.enterprise.inject.spi.AnnotatedConstructor; +import javax.enterprise.inject.spi.AnnotatedField; +import javax.enterprise.inject.spi.AnnotatedMethod; +import javax.enterprise.inject.spi.AnnotatedParameter; +import javax.enterprise.inject.spi.AnnotatedType; + +import org.osgi.service.cdi.annotations.ComponentPropertyType; +import org.osgi.util.converter.TypeReference; public class Maps { @@ -39,78 +57,97 @@ public class Maps { sb.append(entry.getValue()); sb.append(")"); } - } - public static Map<String, Object> map(String[] properties) { - Map<String,Object> map = new HashMap<>(); + public static Map<String, Object> of(Dictionary<String, ?> dict) { + Map<String, Object> map = new HashMap<>(); - for (String property : properties) { - map(map, property); + for (Enumeration<String> enu = dict.keys(); enu.hasMoreElements();) { + String key = enu.nextElement(); + map.put(key, dict.get(key)); } return map; } - static void map(Map<String, Object> map, String property) { - int eq = property.indexOf('='); - - String key = property.substring(0, eq); - String type = "String"; - String value = property.substring(eq + 1, property.length()); + public static Dictionary<String, ?> dict(Map<String, Object> map) { + Dictionary<String, Object> dict = new Hashtable<>(); - int colon = key.indexOf(':'); - - if (colon != -1) { - property = key; - key = property.substring(0, colon); - type = property.substring(colon + 1, property.length()); + if (map != null) { + for (Entry<String, Object> entry : map.entrySet()) { + dict.put(entry.getKey(), entry.getValue()); + } } - map(map, key, type, value); + return dict; } - @SuppressWarnings("unchecked") - static void map(Map<String, Object> map, String key, String type, String value) { - PropertyType propertyType = PropertyType.find(type); + public static Dictionary<String, ?> dict(Object... args) { + Dictionary<String, Object> map = new Hashtable<>(); - Object object = map.get(key); + if ((args.length % 2) != 0) throw new IllegalArgumentException("requires even number of args"); - if (object == null) { - Object valueObject = Conversions.convert(value).to(propertyType.getType()); + for (int i = 0; i < args.length; i+=2) { + map.put(String.valueOf(args[i]), args[i+1]); + } - map.put(key, valueObject); + return map; + } - return; + @SafeVarargs + public static <T> Map<String, T> of(T... args) { + Map<String, T> map = new HashMap<>(); + + if ((args.length % 2) != 0) throw new IllegalArgumentException("requires even number of args"); + + for (int i = 0; i < args.length; i+=2) { + map.put(String.valueOf(args[i]), args[i+1]); } - Object valueObject = Conversions.convert(value).to(propertyType.componentType()); + return map; + } - if (propertyType.isRaw()) { - if (!object.getClass().isArray()) { - Object array = Array.newInstance(propertyType.componentType(), 2); - Array.set(array, 0, object); - Array.set(array, 1, valueObject); - map.put(key, array); - } - else { - int length = Array.getLength(object); - Object array = Array.newInstance(propertyType.componentType(), length + 1); - System.arraycopy(object, 0, array, 0, length); - Array.set(array, length, valueObject); - map.put(key, array); - } + public static Map<String, Object> componentProperties(Annotated annotated) { + if (annotated instanceof AnnotatedType) { + return merge(Arrays.asList(((AnnotatedType<?>)annotated).getJavaClass().getAnnotations())); + } + else if (annotated instanceof AnnotatedParameter) { + return merge(Arrays.asList(((AnnotatedParameter<?>)annotated).getJavaParameter().getAnnotations())); + } + else if (annotated instanceof AnnotatedField) { + return merge(Arrays.asList(((AnnotatedField<?>)annotated).getJavaMember().getAnnotations())); } - 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); + else if (annotated instanceof AnnotatedConstructor) { + return merge(Arrays.asList(((AnnotatedConstructor<?>)annotated).getJavaMember().getAnnotations())); } + else if (annotated instanceof AnnotatedMethod) { + return merge(Arrays.asList(((AnnotatedMethod<?>)annotated).getJavaMember().getAnnotations())); + } + return merge(new ArrayList<>(annotated.getAnnotations())); + } + + public static Map<String, Object> merge(List<Annotation> annotations) { + return annotations.stream().filter( + ann -> Objects.nonNull(ann.annotationType().getAnnotation(ComponentPropertyType.class)) + ).map( + ann -> Conversions.convert(ann).sourceAs(ann.annotationType()).to(new TypeReference<Map<String, Object>>() {}) + ).map(Map::entrySet).flatMap(Collection::stream).collect( + Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + Maps::merge + ) + ); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static List<?> merge(Object a, Object b) { + List<?> aList = Conversions.convert(a).to(new TypeReference<List<?>>() {}); + List<?> bList = Conversions.convert(b).to(new TypeReference<List<?>>() {}); + List checkedList = Collections.checkedList(new ArrayList(), aList.get(0).getClass()); + checkedList.addAll(aList); + checkedList.addAll(bList); + return checkedList; } } Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Predicates.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Predicates.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Predicates.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Predicates.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,54 @@ +/** + * 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.util.function.Predicate; + +import org.osgi.service.cdi.MaximumCardinality; +import org.osgi.service.cdi.runtime.dto.template.ConfigurationTemplateDTO; +import org.osgi.service.cm.ConfigurationEvent; + +public class Predicates { + + private Predicates() { + // no instances + } + + public static Predicate<ConfigurationTemplateDTO> isMatchingConfiguration(ConfigurationEvent event) { + return new MatchingConfigurationPredicate(event); + } + + private static class MatchingConfigurationPredicate implements Predicate<ConfigurationTemplateDTO> { + + public MatchingConfigurationPredicate(ConfigurationEvent event) { + this.event = event; + } + + @Override + public boolean test(ConfigurationTemplateDTO t) { + if (t.pid == null) { + return false; + } + if (((t.maximumCardinality == MaximumCardinality.MANY) && t.pid.equals(event.getFactoryPid())) || + ((t.maximumCardinality == MaximumCardinality.ONE) && t.pid.equals(event.getPid()))) { + return true; + } + return false; + } + + private final ConfigurationEvent event; + + } +} Added: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/SRs.java URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/SRs.java?rev=1829115&view=auto ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/SRs.java (added) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/SRs.java Sat Apr 14 01:10:27 2018 @@ -0,0 +1,64 @@ +/** + * 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.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.dto.ServiceReferenceDTO; + +public class SRs { + + private SRs() { + // no instances + } + + public static <T> ServiceReferenceDTO from(ServiceReference<T> reference) { + for (ServiceReferenceDTO dto : reference.getBundle().adapt(ServiceReferenceDTO[].class)) { + if (dto.id == id(reference)) { + return dto; + } + } + return null; + } + + @SafeVarargs + public static <T> List<ServiceReferenceDTO> from(ServiceReference<T>[] references, ServiceReference<T>... more) { + if (references == null) return Arrays.stream(more).sorted().map( + r -> from(r) + ).collect(Collectors.toList()); + + return Stream.concat(Arrays.stream(references), Arrays.stream(more)).sorted().map( + r -> from(r) + ).collect(Collectors.toList()); + } + + @SafeVarargs + public static <T> List<ServiceReferenceDTO> from(Collection<ServiceReference<T>> references, ServiceReference<T>... more) { + return Stream.concat(references.stream(), Arrays.stream(more)).sorted().map( + r -> from(r) + ).collect(Collectors.toList()); + } + + public static <T> long id(ServiceReference<T> reference) { + return (Long)reference.getProperty(Constants.SERVICE_ID); + } + +} Copied: aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Syncro.java (from r1829114, aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/exception/BlacklistQualifierException.java) URL: http://svn.apache.org/viewvc/aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Syncro.java?p2=aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Syncro.java&p1=aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/exception/BlacklistQualifierException.java&r1=1829114&r2=1829115&rev=1829115&view=diff ============================================================================== --- aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/exception/BlacklistQualifierException.java (original) +++ aries/trunk/cdi/cdi-extender/src/main/java/org/apache/aries/cdi/container/internal/util/Syncro.java Sat Apr 14 01:10:27 2018 @@ -12,14 +12,31 @@ * limitations under the License. */ -package org.apache.aries.cdi.container.internal.exception; +package org.apache.aries.cdi.container.internal.util; -public class BlacklistQualifierException extends IllegalArgumentException { +import java.util.concurrent.locks.ReentrantLock; + +public class Syncro extends ReentrantLock implements AutoCloseable { private static final long serialVersionUID = 1L; - public BlacklistQualifierException(String message, Throwable cause) { - super(message, cause); + public Syncro() { + super(); + } + + public Syncro(boolean fair) { + super(fair); + } + + public Syncro open() { + lock(); + return this; + } + + + @Override + public void close() { + unlock(); } }
