/* * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * 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.jboss.errai.ioc.rebind.ioc.graph.impl; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Predicate; import org.jboss.errai.codegen.meta.HasAnnotations; import org.jboss.errai.codegen.meta.MetaClass; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraphBuilder.Dependency; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraphBuilder.DependencyType; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraphBuilder.InjectableType; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraphBuilder.ProducerInstanceDependency; import org.jboss.errai.ioc.rebind.ioc.graph.api.Injectable; import org.jboss.errai.ioc.rebind.ioc.graph.api.Qualifier; import org.jboss.errai.ioc.rebind.ioc.injector.api.WiringElementType; /** * Concrete here does not mean "for a concrete class". Rather, it means that * this injectable was for bean that we know how to produce (either because it * is a scoped type or from producer member). In contrast, * {@link InjectableReference abstract injectables} are used in unresolved * dependencies to represent a injectable that we do not yet know how to * construct. * * When the {@link DependencyGraphImpl} is constructed, resolution has occurred * and it will contain only concrete injecables. * * @author Max Barkley <mbarkley@redhat.com> */ class InjectableImpl extends InjectableBase implements Injectable { final InjectableType injectableType; final Collection<WiringElementType> wiringTypes; final List<BaseDependency> dependencies = new ArrayList<>(); final Class<? extends Annotation> literalScope; Boolean proxiable = null; boolean requiresProxy = false; Integer hashContent = null; final String factoryName; final Predicate<List<InjectableHandle>> pathPredicate; InjectableImpl(final MetaClass type, final Qualifier qualifier, final Predicate<List<InjectableHandle>> pathPredicate, final String factoryName, final Class<? extends Annotation> literalScope, final InjectableType injectorType, final Collection<WiringElementType> wiringTypes) { super(type, qualifier); this.pathPredicate = pathPredicate; this.factoryName = factoryName; this.literalScope = literalScope; this.wiringTypes = wiringTypes; this.injectableType = injectorType; } @Override public String getFactoryName() { return factoryName; } @Override public Class<? extends Annotation> getScope() { return literalScope; } @Override public InjectableType getInjectableType() { return injectableType; } @Override public Collection<Dependency> getDependencies() { return Collections.<Dependency>unmodifiableCollection(dependencies); } @Override public boolean loadAsync() { return wiringTypes.contains(WiringElementType.LoadAsync); } @Override public boolean requiresProxy() { switch (injectableType) { case ContextualProvider: case Provider: return false; case Producer: case Type: case JsType: case ExtensionProvided: return requiresProxy || wiringTypes.contains(WiringElementType.NormalScopedBean); case Extension: default: throw new RuntimeException("Not yet implemented!"); } } @Override public Optional<HasAnnotations> getAnnotatedObject() { switch (injectableType) { case Type: return Optional.of(type); case Producer: case Static: case Provider: case ContextualProvider: return dependencies .stream() .filter(dep -> DependencyType.ProducerMember.equals(dep.dependencyType)) .map(dep -> (HasAnnotations) ((ProducerInstanceDependency) dep).getProducingMember()) .findFirst(); case ExtensionProvided: case Extension: case JsType: case Disabled: default: return Optional.empty(); } } @Override public Collection<WiringElementType> getWiringElementTypes() { return Collections.unmodifiableCollection(wiringTypes); } @Override public boolean isContextual() { return InjectableType.ContextualProvider.equals(injectableType); } @Override public void setRequiresProxyTrue() { requiresProxy = true; } @Override public boolean isExtension() { return false; } @Override public int hashContent() { if (hashContent == null) { hashContent = computeHashContent(); } return hashContent; } private int computeHashContent() { int hashContent = type.hashContent(); for (final BaseDependency dep: dependencies) { hashContent ^= dep.injectable.resolution.getInjectedType().hashContent(); } return hashContent; } @Override public String toString() { final String injectableDescriptor; switch (injectableType) { case ContextualProvider: injectableDescriptor = "ContextualProvider"; break; case Disabled: injectableDescriptor = "Disabled"; break; case Extension: injectableDescriptor = "Extension"; break; case ExtensionProvided: injectableDescriptor = "ExtensionProvided"; break; case JsType: injectableDescriptor = "@JsType"; break; case Producer: injectableDescriptor = "@Produces"; break; case Provider: injectableDescriptor = "Provider"; break; case Static: injectableDescriptor = "@Produces"; break; case Type: injectableDescriptor = "Class"; break; default: injectableDescriptor = ""; break; } return String.format("%s %s %s", injectableDescriptor, getQualifier(), getInjectedType().getFullyQualifiedNameWithTypeParms()); } }