/* * 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.bootstrapper; import static java.util.Arrays.stream; import static java.util.Collections.emptyList; import static org.jboss.errai.codegen.Parameter.of; import static org.jboss.errai.codegen.util.Stmt.invokeStatic; import static org.jboss.errai.codegen.util.Stmt.loadLiteral; import static org.jboss.errai.codegen.util.Stmt.nestedCall; import static org.jboss.errai.codegen.util.Stmt.newObject; import static org.jboss.errai.ioc.rebind.ioc.extension.builtin.JsTypeAntiInliningExtension.numberOfRequiredAntiInliningDummies; import static org.jboss.errai.ioc.rebind.ioc.extension.builtin.JsTypeAntiInliningExtension.requiresAntiInliningDummy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.jboss.errai.codegen.Statement; import org.jboss.errai.codegen.builder.AnonymousClassStructureBuilder; import org.jboss.errai.codegen.builder.ClassStructureBuilder; import org.jboss.errai.codegen.builder.impl.ObjectBuilder; import org.jboss.errai.codegen.meta.MetaClass; import org.jboss.errai.codegen.util.Stmt; import org.jboss.errai.ioc.client.WindowInjectionContextImpl; import org.jboss.errai.ioc.client.WindowInjectionContextStorage; import org.jboss.errai.ioc.client.api.ActivatedBy; import org.jboss.errai.ioc.client.api.builtin.DummyJsTypeProvider; import org.jboss.errai.ioc.client.container.BeanActivator; import org.jboss.errai.ioc.client.container.FactoryHandleImpl; import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraph; import org.jboss.errai.ioc.rebind.ioc.graph.api.Injectable; import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectionContext; /** * Generates factories that lookup types from the {@link WindowInjectionContextImpl} * , allowing the injection of types between dynamic runtime modules. * * @see FactoryBodyGenerator * @see AbstractBodyGenerator * @author Max Barkley <mbarkley@redhat.com> */ public class JsTypeFactoryBodyGenerator extends AbstractBodyGenerator { @Override protected List<Statement> generateFactoryInitStatements(final ClassStructureBuilder<?> bodyBlockBuilder, final Injectable injectable, final DependencyGraph graph, final InjectionContext injectionContext) { final MetaClass type = injectable.getInjectedType(); if (IOCProcessor.isJsInteropSupportEnabled() && requiresAntiInliningDummy(type)) { final int count = numberOfRequiredAntiInliningDummies(type); final List<Statement> stmts = new ArrayList<>(count); for (int i = 0; i < count; i++) { stmts.add(invokeStatic(WindowInjectionContextStorage.class, "createOrGet") .invoke("addBeanProvider", "$$_anti_inlining_dummy_$$", createJsTypeProvider(type))); } return stmts; } else { return emptyList(); } } private ObjectBuilder createJsTypeProvider(final MetaClass type) { return newObject(DummyJsTypeProvider.class) .extend() .publicOverridesMethod("getInstance") .append(nestedCall(createAnonymousImpl(type)).returnValue()) .finish() .publicOverridesMethod("getName") .append(loadLiteral("Anti-inlining impl for: " + type.getFullyQualifiedName()).returnValue()) .finish() .finish(); } private ObjectBuilder createAnonymousImpl(final MetaClass type) { final AnonymousClassStructureBuilder builder = newObject(type).extend(); stream(type.getMethods()) .filter(m -> m.isPublic() && m.isAbstract()) .forEach(m -> { builder .publicOverridesMethod(m.getName(), of(m.getParameters())) .append(Stmt.throw_(RuntimeException.class)) .finish(); }); return builder.finish(); } @Override protected List<Statement> generateCreateInstanceStatements(final ClassStructureBuilder<?> bodyBlockBuilder, final Injectable injectable, final DependencyGraph graph, final InjectionContext injectionContext) { return Collections.<Statement> singletonList( Stmt.castTo(injectable.getInjectedType(), invokeStatic(WindowInjectionContextStorage.class, "createOrGet") .invoke("getBean", injectable.getInjectedType().getFullyQualifiedName())).returnValue()); } @Override protected Statement generateFactoryHandleStatement(final Injectable injectable) { final Object[] args; if (injectable.getInjectedType().isAnnotationPresent(ActivatedBy.class)) { final Class<? extends BeanActivator> activatorType = injectable.getInjectedType().getAnnotation(ActivatedBy.class).value(); args = new Object[] { loadLiteral(injectable.getInjectedType()), injectable.getFactoryName(), injectable.getScope(), isEager(injectable.getInjectedType()), injectable.getBeanName(), loadLiteral(false), loadLiteral(activatorType) }; } else { args = new Object[] { loadLiteral(injectable.getInjectedType()), injectable.getFactoryName(), injectable.getScope(), isEager(injectable.getInjectedType()), injectable.getBeanName(), loadLiteral(false) }; } return newObject(FactoryHandleImpl.class, args); } }