/* * Copyright (C) 2013 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.databinding.rebind; 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.declareFinalVariable; import static org.jboss.errai.codegen.util.Stmt.invokeStatic; import static org.jboss.errai.codegen.util.Stmt.loadVariable; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.enterprise.context.Dependent; import org.jboss.errai.codegen.Statement; import org.jboss.errai.codegen.builder.ClassStructureBuilder; import org.jboss.errai.codegen.meta.HasAnnotations; import org.jboss.errai.codegen.meta.MetaClass; import org.jboss.errai.databinding.client.api.DataBinder; import org.jboss.errai.ioc.client.api.IOCExtension; import org.jboss.errai.ioc.client.container.RefHolder; import org.jboss.errai.ioc.rebind.ioc.bootstrapper.AbstractBodyGenerator; import org.jboss.errai.ioc.rebind.ioc.bootstrapper.FactoryBodyGenerator; import org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCProcessingContext; import org.jboss.errai.ioc.rebind.ioc.extension.IOCExtensionConfigurator; import org.jboss.errai.ioc.rebind.ioc.graph.api.CustomFactoryInjectable; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraph; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraphBuilder.InjectableType; import org.jboss.errai.ioc.rebind.ioc.graph.api.Injectable; import org.jboss.errai.ioc.rebind.ioc.graph.api.InjectionSite; import org.jboss.errai.ioc.rebind.ioc.graph.impl.DefaultCustomFactoryInjectable; import org.jboss.errai.ioc.rebind.ioc.graph.impl.FactoryNameGenerator; import org.jboss.errai.ioc.rebind.ioc.graph.impl.InjectableHandle; import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectableProvider; import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectionContext; import org.jboss.errai.ioc.rebind.ioc.injector.api.WiringElementType; import org.jboss.errai.ui.shared.api.annotations.Model; /** * The purpose of this IOC extension is to provide bean instances of bindable types that are qualified with * {@link Model} and to expose the {@link DataBinder}s that manage these model instances using {@link RefHolder} s. * * @author Christian Sadilek <csadilek@redhat.com> * @author Mike Brock */ @IOCExtension public class DataBindingIOCExtension implements IOCExtensionConfigurator { @Override public void configure(final IOCProcessingContext context, final InjectionContext injectionContext) { } @Override public void afterInitialization(final IOCProcessingContext context, final InjectionContext injectionContext) { final Collection<MetaClass> allBindableTypes = DataBindingUtil.getAllBindableTypes(context.getGeneratorContext()); final Model anno = new Model() { @Override public Class<? extends Annotation> annotationType() { return Model.class; } }; for (final MetaClass modelBean : allBindableTypes) { final InjectableHandle handle = new InjectableHandle(modelBean, injectionContext.getQualifierFactory().forSource(new HasAnnotations() { @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotation) { return Model.class.equals(annotation); } @Override public Annotation[] getAnnotations() { return new Annotation[] { anno }; } @SuppressWarnings("unchecked") @Override public <A extends Annotation> A getAnnotation(Class<A> annotation) { if (isAnnotationPresent(annotation)) { return (A) anno; } else { return null; } } })); injectionContext.registerInjectableProvider(handle, new InjectableProvider() { private CustomFactoryInjectable provided; @Override public CustomFactoryInjectable getInjectable(final InjectionSite injectionSite, final FactoryNameGenerator nameGenerator) { if (injectionSite.isAnnotationPresent(Model.class)) { if (provided == null) { final FactoryBodyGenerator generator = new AbstractBodyGenerator() { @Override protected List<Statement> generateCreateInstanceStatements( final ClassStructureBuilder<?> bodyBlockBuilder, final Injectable injectable, final DependencyGraph graph, final InjectionContext injectionContext) { final List<Statement> createInstanceStmts = new ArrayList<Statement>(); final MetaClass binderClass = parameterizedAs(DataBinder.class, typeParametersOf(modelBean)); final String dataBinderVar = "dataBinder"; final String modelVar = "model"; createInstanceStmts.add(declareFinalVariable(dataBinderVar, binderClass, invokeStatic(DataBinder.class, "forType", modelBean))); createInstanceStmts .add(declareFinalVariable(modelVar, modelBean, loadVariable(dataBinderVar).invoke("getModel"))); createInstanceStmts.add(loadVariable("this").invoke("setReference", loadVariable(modelVar), DataBindingUtil.BINDER_VAR_NAME, loadVariable(dataBinderVar))); createInstanceStmts.add(loadVariable(modelVar).returnValue()); return createInstanceStmts; } }; provided = new DefaultCustomFactoryInjectable(handle.getType(), handle.getQualifier(), nameGenerator.generateFor(handle.getType(), handle.getQualifier(), InjectableType.ExtensionProvided), Dependent.class, Collections.singletonList(WiringElementType.DependentBean), generator); } return provided; } else { throw new IllegalStateException("The " + DataBindingIOCExtension.class.getSimpleName() + " was used to satisfy an injection site without the @" + Model.class.getName() + " annotation."); } } }); } } }