| /** |
| * 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.bean; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Type; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.Optional; |
| import java.util.Set; |
| import java.util.SortedMap; |
| import java.util.stream.Collectors; |
| |
| import javax.enterprise.context.Dependent; |
| import javax.enterprise.context.spi.CreationalContext; |
| import javax.enterprise.inject.Default; |
| import javax.enterprise.inject.spi.Bean; |
| import javax.enterprise.inject.spi.BeanManager; |
| import javax.enterprise.inject.spi.InjectionPoint; |
| import javax.inject.Provider; |
| |
| import org.apache.aries.cdi.container.internal.container.Mark; |
| import org.apache.aries.cdi.container.internal.model.CollectionType; |
| import org.apache.aries.cdi.container.internal.model.ExtendedReferenceDTO; |
| import org.apache.aries.cdi.container.internal.model.ExtendedReferenceTemplateDTO; |
| import org.apache.aries.cdi.container.internal.util.Logs; |
| import org.apache.aries.cdi.container.internal.util.Sets; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.service.cdi.ComponentType; |
| import org.osgi.service.cdi.MaximumCardinality; |
| import org.osgi.service.cdi.ReferencePolicy; |
| import org.osgi.service.cdi.ReferencePolicyOption; |
| import org.osgi.service.cdi.annotations.ComponentScoped; |
| import org.osgi.service.cdi.annotations.Reference; |
| import org.osgi.service.cdi.annotations.Reluctant; |
| import org.osgi.service.cdi.runtime.dto.template.ComponentTemplateDTO; |
| import org.osgi.service.log.Logger; |
| |
| public class ReferenceBean implements Bean<Object> { |
| |
| public ReferenceBean( |
| Logs logs, |
| ComponentTemplateDTO component, |
| ExtendedReferenceTemplateDTO template) { |
| |
| _component = component; |
| _template = template; |
| |
| _log = logs.getLogger(getClass()); |
| _qualifiers = Sets.hashSet(Reference.Literal.of(Object.class, ""), Default.Literal.INSTANCE); |
| |
| if (_template.policyOption == ReferencePolicyOption.RELUCTANT) { |
| _qualifiers.add(Reluctant.Literal.INSTANCE); |
| } |
| |
| _types = Sets.hashSet(_template.injectionPointType, Object.class); |
| } |
| |
| @Override |
| public Object create(CreationalContext<Object> c) { |
| Objects.requireNonNull(_bm); |
| Objects.requireNonNull(_snapshot); |
| |
| _log.debug(l -> l.debug("Creating {}", this)); |
| |
| final SortedMap<ServiceReference<Object>, Object> tracked = _snapshot.serviceTracker.getTracked(); |
| |
| if (_template.collectionType == CollectionType.BINDER_SERVICE || |
| _template.collectionType == CollectionType.BINDER_REFERENCE || |
| _template.collectionType == CollectionType.BINDER_BEAN_SERVICE_OBJECTS) { |
| |
| return _snapshot.binder; |
| } |
| else if (_template.policy == ReferencePolicy.DYNAMIC) { |
| if (_template.maximumCardinality == MaximumCardinality.MANY) { |
| return new Provider<List<Object>>() { |
| @Override |
| public List<Object> get() { |
| return tracked.values().stream().map( |
| s -> decorate(c, s) |
| ).collect(Collectors.toList()); |
| } |
| }; |
| } |
| else if (_template.minimumCardinality == 0) { |
| return new Provider<Optional<Object>>() { |
| @Override |
| public Optional<Object> get() { |
| Iterator<Object> iterator = tracked.values().iterator(); |
| if (iterator.hasNext()) { |
| return Optional.of(decorate(c, iterator.next())); |
| } |
| return Optional.empty(); |
| } |
| }; |
| } |
| else { |
| return new Provider<Object>() { |
| @Override |
| public Object get() { |
| Iterator<Object> iterator = tracked.values().iterator(); |
| if (iterator.hasNext()) { |
| return decorate(c, iterator.next()); |
| } |
| return null; |
| } |
| }; |
| } |
| } |
| else { |
| if (_template.maximumCardinality == MaximumCardinality.MANY) { |
| return tracked.values().stream().map( |
| s -> decorate(c, s) |
| ).collect(Collectors.toList()); |
| } |
| else if (_template.minimumCardinality == 0) { |
| Iterator<Object> iterator = tracked.values().iterator(); |
| if (iterator.hasNext()) { |
| return Optional.of(decorate(c, iterator.next())); |
| } |
| return Optional.empty(); |
| } |
| else { |
| Iterator<Object> iterator = tracked.values().iterator(); |
| if (iterator.hasNext()) { |
| return decorate(c, iterator.next()); |
| } |
| return null; |
| } |
| } |
| } |
| |
| private <S> S decorate(CreationalContext<S> c, S s) { |
| return s; |
| |
| // TODO do we want to support decorators/interceptors on in-bound services one day??? |
| // ================================================================================== |
| |
| // if (s == null) return null; |
| // |
| // List<javax.enterprise.inject.spi.Decorator<?>> decorators = _bm.resolveDecorators( |
| // Collections.singleton(_template.serviceClass), |
| // new Annotation[0]); |
| // |
| // if (decorators.isEmpty()) { |
| // return s; |
| // } |
| // |
| // org.jboss.weld.manager.BeanManagerImpl bmi = |
| // ((org.jboss.weld.bean.builtin.BeanManagerProxy)_bm).delegate(); |
| // org.jboss.weld.injection.CurrentInjectionPoint cip = bmi.getServices().get( |
| // org.jboss.weld.injection.CurrentInjectionPoint.class); |
| // InjectionPoint ip = cip.peek(); |
| // return org.jboss.weld.util.Decorators.getOuterDelegate( |
| // (Bean<S>)this, s, c, (Class<S>)_template.serviceClass, |
| // (org.jboss.weld.injection.EmptyInjectionPoint.INSTANCE.equals(ip) ? null : ip), |
| // bmi, decorators); |
| } |
| |
| @Override |
| public void destroy(Object instance, CreationalContext<Object> creationalContext) { |
| } |
| |
| @Override |
| public Class<?> getBeanClass() { |
| return _template.beanClass; |
| } |
| |
| @Override |
| public Set<InjectionPoint> getInjectionPoints() { |
| return Collections.emptySet(); |
| } |
| |
| @Override |
| public String getName() { |
| return null;//_template.name; |
| } |
| |
| @Override |
| public Set<Annotation> getQualifiers() { |
| return _qualifiers; |
| } |
| |
| @Override |
| public Class<? extends Annotation> getScope() { |
| if (_component.type == ComponentType.CONTAINER) { |
| return Dependent.class; |
| } |
| return ComponentScoped.class; |
| } |
| |
| @Override |
| public Set<Class<? extends Annotation>> getStereotypes() { |
| return Collections.emptySet(); |
| } |
| |
| @Override |
| public Set<Type> getTypes() { |
| return _types; |
| } |
| |
| @Override |
| public boolean isAlternative() { |
| return false; |
| } |
| |
| @Override |
| public boolean isNullable() { |
| return false; |
| } |
| |
| public void setMark(Mark mark) { |
| _qualifiers.add(mark); |
| _string = null; // invalidate the toString |
| } |
| |
| public void setReferenceDTO(ExtendedReferenceDTO snapshot) { |
| _snapshot = snapshot; |
| } |
| |
| public void setBeanManager(BeanManager bm) { |
| _bm = bm; |
| } |
| |
| @Override |
| public String toString() { |
| if (_string == null) { |
| _string = "ReferenceBean[" + _template.name + ", " + _template.injectionPointType + ", " + getScope().getSimpleName() + ", " + _qualifiers + "]"; |
| } |
| return _string; |
| } |
| |
| private volatile BeanManager _bm; |
| private final ComponentTemplateDTO _component; |
| private final Logger _log; |
| private final Set<Annotation> _qualifiers; |
| private volatile ExtendedReferenceDTO _snapshot; |
| private volatile String _string; |
| private final ExtendedReferenceTemplateDTO _template; |
| private final Set<Type> _types; |
| |
| } |