/**
* Copyright (C) 2016 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.bootstrapper;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.jboss.errai.codegen.meta.MetaClassFactory.parameterizedAs;
import static org.jboss.errai.codegen.meta.MetaClassFactory.typeParametersOf;
import static org.jboss.errai.codegen.util.Stmt.castTo;
import static org.jboss.errai.codegen.util.Stmt.declareFinalVariable;
import static org.jboss.errai.codegen.util.Stmt.loadLiteral;
import static org.jboss.errai.codegen.util.Stmt.loadVariable;
import java.util.ArrayList;
import java.util.List;
import org.jboss.errai.codegen.Statement;
import org.jboss.errai.codegen.builder.ClassStructureBuilder;
import org.jboss.errai.codegen.builder.ContextualStatementBuilder;
import org.jboss.errai.codegen.meta.MetaClass;
import org.jboss.errai.ioc.client.api.Disposer;
import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraph;
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.Injectable;
import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectionContext;
/**
*
* @author Max Barkley <mbarkley@redhat.com>
*/
public abstract class BaseProviderGenerator extends AbstractBodyGenerator {
@Override
protected List<Statement> generateCreateInstanceStatements(final ClassStructureBuilder<?> bodyBlockBuilder,
final Injectable injectable, final DependencyGraph graph, final InjectionContext injectionContext) {
final List<Statement> stmts = new ArrayList<>(2);
final Injectable providerInjectable = getProviderInjectable(injectable);
final MetaClass paramterizedProviderType = parameterizedAs(getProviderRawType(), typeParametersOf(injectable.getInjectedType()));
stmts.add(declareFinalVariable("provider", paramterizedProviderType, lookupProviderStmt(providerInjectable, paramterizedProviderType)));
stmts.add(declareFinalVariable("instance", injectable.getInjectedType(), invokeProviderStmt(loadVariable("provider"))));
if (providerInjectable.getInjectedType().isAssignableTo(Disposer.class)) {
stmts.add(loadVariable("this").invoke("setReference", loadVariable("instance"), "disposer", loadVariable("provider")));
}
stmts.add(loadVariable("instance").returnValue());
return stmts;
}
@Override
protected List<Statement> generateDestroyInstanceStatements(final ClassStructureBuilder<?> bodyBlockBuilder,
final Injectable injectable, final DependencyGraph graph, final InjectionContext injectionContext) {
final Injectable provider = getProviderInjectable(injectable);
if (provider.getInjectedType().isAssignableTo(Disposer.class)) {
return singletonList(castTo(Disposer.class,
loadVariable("this").invoke("getReferenceAs", loadVariable("instance"), "disposer", Disposer.class))
.invoke("dispose", loadVariable("instance")));
}
else {
return emptyList();
}
}
protected Injectable getProviderInjectable(final Injectable depInjectable) {
for (final Dependency dep : depInjectable.getDependencies()) {
if (dep.getDependencyType().equals(DependencyType.ProducerMember)) {
final MetaClass providerType = dep.getInjectable().getInjectedType();
if (providerType.isAssignableTo(getProviderRawType())) {
return dep.getInjectable();
}
else {
throw new RuntimeException("Unrecognized contextual provider type " + providerType.getFullyQualifiedName());
}
}
}
throw new RuntimeException();
}
protected ContextualStatementBuilder lookupProviderStmt(final Injectable providerInjectable, final MetaClass paramterizedProviderType) {
final ContextualStatementBuilder provider = castTo(paramterizedProviderType,
loadVariable("contextManager").invoke("getInstance", loadLiteral(providerInjectable.getFactoryName())));
return provider;
}
protected abstract Class<?> getProviderRawType();
protected abstract ContextualStatementBuilder invokeProviderStmt(ContextualStatementBuilder provider);
}