/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.isis.core.runtime.systemusinginstallers; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; import javax.jdo.annotations.PersistenceCapable; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.reflections.Reflections; import org.reflections.vfs.Vfs; import org.apache.isis.applib.AppManifest; import org.apache.isis.applib.annotation.DomainObject; import org.apache.isis.applib.annotation.DomainService; import org.apache.isis.applib.annotation.Mixin; import org.apache.isis.applib.annotation.Nature; import org.apache.isis.applib.fixturescripts.FixtureScript; import org.apache.isis.applib.services.classdiscovery.ClassDiscoveryServiceUsingReflections; import org.apache.isis.core.commons.config.IsisConfiguration; import org.apache.isis.core.commons.config.IsisConfigurationDefault; import org.apache.isis.core.commons.factory.InstanceUtil; import org.apache.isis.core.commons.lang.ClassUtil; import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner; import org.apache.isis.core.metamodel.layoutmetadata.LayoutMetadataReader; import org.apache.isis.core.metamodel.progmodel.ProgrammingModel; import org.apache.isis.core.metamodel.services.ServicesInjector; import org.apache.isis.core.metamodel.specloader.ReflectorConstants; import org.apache.isis.core.metamodel.specloader.SpecificationLoader; import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator; import org.apache.isis.core.runtime.authentication.AuthenticationManager; import org.apache.isis.core.runtime.authorization.AuthorizationManager; import org.apache.isis.core.runtime.fixtures.FixturesInstallerFromConfiguration; import org.apache.isis.core.runtime.services.ServicesInstallerFromAnnotation; import org.apache.isis.core.runtime.services.ServicesInstallerFromConfiguration; import org.apache.isis.core.runtime.services.ServicesInstallerFromConfigurationAndAnnotation; import org.apache.isis.core.runtime.system.IsisSystemException; import org.apache.isis.core.runtime.system.SystemConstants; import org.apache.isis.objectstore.jdo.service.RegisterEntities; import org.apache.isis.progmodels.dflt.JavaReflectorHelper; import org.apache.isis.progmodels.dflt.ProgrammingModelFacetsJava5; /** * */ public abstract class IsisComponentProvider { //region > constructor, fields private final AppManifest appManifest; private final IsisConfigurationDefault configuration; protected final List<Object> services; protected final AuthenticationManager authenticationManager; protected final AuthorizationManager authorizationManager; public IsisComponentProvider( final AppManifest appManifest, final IsisConfiguration configuration, final AuthenticationManager authenticationManager, final AuthorizationManager authorizationManager){ if(appManifest == null) { throw new IllegalArgumentException("AppManifest is required"); } this.appManifest = appManifest; this.configuration = (IsisConfigurationDefault) configuration; // REVIEW: HACKY putAppManifestKey(appManifest); findAndRegisterTypes(appManifest); specifyServicesAndRegisteredEntitiesUsing(appManifest); overrideConfigurationUsing(appManifest); this.services = new ServicesInstallerFromConfigurationAndAnnotation(getConfiguration()).getServices(); final String fixtureClassNamesCsv = classNamesFrom(getAppManifest().getFixtures()); putConfigurationProperty(FixturesInstallerFromConfiguration.FIXTURES, fixtureClassNamesCsv); this.authenticationManager = authenticationManager; this.authorizationManager = authorizationManager; } public AppManifest getAppManifest() { return appManifest; } public IsisConfigurationDefault getConfiguration() { return configuration; } //endregion //region > helpers (appManifest) private void putAppManifestKey(final AppManifest appManifest) { // required to prevent RegisterEntities validation from complaining // if it can't find any @PersistenceCapable entities in a module // that contains only services. putConfigurationProperty( SystemConstants.APP_MANIFEST_KEY, appManifest.getClass().getName() ); } private void findAndRegisterTypes(final AppManifest appManifest) { final Iterable<String> packageNameList = modulePackageNamesFrom(appManifest); final AppManifest.Registry registry = AppManifest.Registry.instance(); final List<String> packages = Lists.newArrayList(); packages.addAll(AppManifest.Registry.FRAMEWORK_PROVIDED_SERVICES); Iterables.addAll(packages, packageNameList); Vfs.setDefaultURLTypes(ClassDiscoveryServiceUsingReflections.getUrlTypes()); final Reflections reflections = new Reflections(packages); final Set<Class<?>> domainServiceTypes = reflections.getTypesAnnotatedWith(DomainService.class); final Set<Class<?>> persistenceCapableTypes = reflections.getTypesAnnotatedWith(PersistenceCapable.class); final Set<Class<? extends FixtureScript>> fixtureScriptTypes = reflections.getSubTypesOf(FixtureScript.class); final Set<Class<?>> mixinTypes = Sets.newHashSet(); mixinTypes.addAll(reflections.getTypesAnnotatedWith(Mixin.class)); final Set<Class<?>> domainObjectTypes = reflections.getTypesAnnotatedWith(DomainObject.class); mixinTypes.addAll( Lists.newArrayList(Iterables.filter(domainObjectTypes, new Predicate<Class<?>>() { @Override public boolean apply(@Nullable final Class<?> input) { if(input == null) { return false; } final DomainObject annotation = input.getAnnotation(DomainObject.class); return annotation.nature() == Nature.MIXIN; } })) ); registry.setDomainServiceTypes(domainServiceTypes); registry.setPersistenceCapableTypes(persistenceCapableTypes); registry.setFixtureScriptTypes(fixtureScriptTypes); registry.setMixinTypes(mixinTypes); } private void specifyServicesAndRegisteredEntitiesUsing(final AppManifest appManifest) { final Iterable<String> packageNames = modulePackageNamesFrom(appManifest); final String packageNamesCsv = Joiner.on(',').join(packageNames); putConfigurationProperty(ServicesInstallerFromAnnotation.PACKAGE_PREFIX_KEY, packageNamesCsv); putConfigurationProperty(RegisterEntities.PACKAGE_PREFIX_KEY, packageNamesCsv); final List<Class<?>> additionalServices = appManifest.getAdditionalServices(); if(additionalServices != null) { putConfigurationProperty( ServicesInstallerFromConfiguration.SERVICES_KEY, classNamesFrom(additionalServices)); } } private Iterable<String> modulePackageNamesFrom(final AppManifest appManifest) { List<Class<?>> modules = appManifest.getModules(); if (modules == null || modules.isEmpty()) { throw new IllegalArgumentException( "If an appManifest is provided then it must return a non-empty set of modules"); } return Iterables.transform(modules, ClassUtil.Functions.packageNameOf()); } protected String classNamesFrom(final List<?> objectsOrClasses) { if (objectsOrClasses == null) { return null; } final Iterable<String> fixtureClassNames = Iterables.transform(objectsOrClasses, classNameOf()); return Joiner.on(',').join(fixtureClassNames); } private static Function<Object, String> classNameOf() { return new Function<Object, String>() { @Nullable @Override public String apply(final Object input) { Class<?> aClass = input instanceof Class ? (Class<?>) input : input.getClass(); return aClass.getName(); } }; } private void overrideConfigurationUsing(final AppManifest appManifest) { final Map<String, String> configurationProperties = appManifest.getConfigurationProperties(); if (configurationProperties != null) { for (Map.Entry<String, String> configProp : configurationProperties.entrySet()) { putConfigurationProperty(configProp.getKey(), configProp.getValue()); } } } /** * TODO: hacky, {@link IsisConfiguration} is meant to be immutable... */ void putConfigurationProperty(final String key, final String value) { if(value == null) { return; } this.configuration.put(key, value); } //endregion //region > provideAuth* public AuthenticationManager provideAuthenticationManager() { return authenticationManager; } public AuthorizationManager provideAuthorizationManager() { return authorizationManager; } //endregion //region > provideServiceInjector public ServicesInjector provideServiceInjector(final IsisConfiguration configuration) { return new ServicesInjector(services, configuration); } //endregion //region > provideSpecificationLoader public SpecificationLoader provideSpecificationLoader( final ServicesInjector servicesInjector, final Collection<MetaModelRefiner> metaModelRefiners) throws IsisSystemException { final ProgrammingModel programmingModel = createProgrammingModel(); final MetaModelValidator mmv = createMetaModelValidator(); final List<LayoutMetadataReader> layoutMetadataReaders = createLayoutMetadataReaders(); return JavaReflectorHelper.createObjectReflector( configuration, programmingModel, metaModelRefiners, layoutMetadataReaders, mmv, servicesInjector); } protected MetaModelValidator createMetaModelValidator() { final String metaModelValidatorClassName = configuration.getString( ReflectorConstants.META_MODEL_VALIDATOR_CLASS_NAME, ReflectorConstants.META_MODEL_VALIDATOR_CLASS_NAME_DEFAULT); return InstanceUtil.createInstance(metaModelValidatorClassName, MetaModelValidator.class); } protected ProgrammingModel createProgrammingModel() { final ProgrammingModel programmingModel = new ProgrammingModelFacetsJava5(configuration); ProgrammingModel.Util.includeFacetFactories(configuration, programmingModel); ProgrammingModel.Util.excludeFacetFactories(configuration, programmingModel); return programmingModel; } protected List<LayoutMetadataReader> createLayoutMetadataReaders() { final List<LayoutMetadataReader> layoutMetadataReaders = Lists.newArrayList(); final String[] layoutMetadataReaderClassNames = configuration.getList( ReflectorConstants.LAYOUT_METADATA_READER_LIST, ReflectorConstants.LAYOUT_METADATA_READER_LIST_DEFAULT); if (layoutMetadataReaderClassNames != null) { for (final String layoutMetadataReaderClassName : layoutMetadataReaderClassNames) { final LayoutMetadataReader layoutMetadataReader = InstanceUtil.createInstance(layoutMetadataReaderClassName, LayoutMetadataReader.class); layoutMetadataReaders.add(layoutMetadataReader); } } return layoutMetadataReaders; } //endregion }