| /* |
| * 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.polygene.runtime.bootstrap; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.function.Predicate; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| import org.apache.polygene.api.activation.Activator; |
| import org.apache.polygene.api.common.MetaInfo; |
| import org.apache.polygene.api.common.Visibility; |
| import org.apache.polygene.api.composite.TransientComposite; |
| import org.apache.polygene.api.entity.EntityComposite; |
| import org.apache.polygene.api.identity.HasIdentity; |
| import org.apache.polygene.api.identity.Identity; |
| import org.apache.polygene.api.identity.IdentityGenerator; |
| import org.apache.polygene.api.identity.StringIdentity; |
| import org.apache.polygene.api.metrics.MetricsProvider; |
| import org.apache.polygene.api.serialization.Serialization; |
| import org.apache.polygene.api.service.DuplicateServiceIdentityException; |
| import org.apache.polygene.api.structure.Module; |
| import org.apache.polygene.api.type.HasEqualOrAssignableFromType; |
| import org.apache.polygene.api.type.HasTypes; |
| import org.apache.polygene.api.unitofwork.UnitOfWorkFactory; |
| import org.apache.polygene.api.value.ValueComposite; |
| import org.apache.polygene.bootstrap.Assembler; |
| import org.apache.polygene.bootstrap.AssemblyException; |
| import org.apache.polygene.bootstrap.AssemblyReportException; |
| import org.apache.polygene.bootstrap.AssemblySpecifications; |
| import org.apache.polygene.bootstrap.AssemblyVisitor; |
| import org.apache.polygene.bootstrap.ConfigurationDeclaration; |
| import org.apache.polygene.bootstrap.EntityAssembly; |
| import org.apache.polygene.bootstrap.EntityDeclaration; |
| import org.apache.polygene.bootstrap.ImportedServiceAssembly; |
| import org.apache.polygene.bootstrap.ImportedServiceDeclaration; |
| import org.apache.polygene.bootstrap.LayerAssembly; |
| import org.apache.polygene.bootstrap.MetaInfoDeclaration; |
| import org.apache.polygene.bootstrap.MixinDeclaration; |
| import org.apache.polygene.bootstrap.ModuleAssembly; |
| import org.apache.polygene.bootstrap.ObjectAssembly; |
| import org.apache.polygene.bootstrap.ObjectDeclaration; |
| import org.apache.polygene.bootstrap.ServiceAssembly; |
| import org.apache.polygene.bootstrap.ServiceDeclaration; |
| import org.apache.polygene.bootstrap.TransientAssembly; |
| import org.apache.polygene.bootstrap.TransientDeclaration; |
| import org.apache.polygene.bootstrap.ValueAssembly; |
| import org.apache.polygene.bootstrap.ValueDeclaration; |
| import org.apache.polygene.bootstrap.defaults.DefaultIdentityGeneratorAssembler; |
| import org.apache.polygene.bootstrap.defaults.DefaultMetricsProviderAssembler; |
| import org.apache.polygene.bootstrap.defaults.DefaultSerializationAssembler; |
| import org.apache.polygene.bootstrap.defaults.DefaultUnitOfWorkAssembler; |
| import org.apache.polygene.runtime.activation.ActivatorsModel; |
| import org.apache.polygene.runtime.composite.TransientModel; |
| import org.apache.polygene.runtime.composite.TransientsModel; |
| import org.apache.polygene.runtime.entity.EntitiesModel; |
| import org.apache.polygene.runtime.entity.EntityModel; |
| import org.apache.polygene.runtime.object.ObjectModel; |
| import org.apache.polygene.runtime.object.ObjectsModel; |
| import org.apache.polygene.runtime.service.ImportedServiceModel; |
| import org.apache.polygene.runtime.service.ImportedServicesModel; |
| import org.apache.polygene.runtime.service.ServiceModel; |
| import org.apache.polygene.runtime.service.ServicesModel; |
| import org.apache.polygene.runtime.structure.LayerModel; |
| import org.apache.polygene.runtime.structure.ModuleModel; |
| import org.apache.polygene.runtime.value.ValueModel; |
| import org.apache.polygene.runtime.value.ValuesModel; |
| |
| import static java.util.Arrays.asList; |
| import static java.util.Collections.singleton; |
| import static java.util.stream.Collectors.toList; |
| |
| /** |
| * Assembly of a Module. This is where you register all objects, Composites, |
| * Services. Each "add" method returns a declaration that you can use to add |
| * additional information and metadata. If you call an "add" method with many |
| * parameters then the declared metadata will apply to all types in the method |
| * call. |
| */ |
| final class ModuleAssemblyImpl |
| implements ModuleAssembly |
| { |
| /** |
| * Assemblers required on all modules, keyed by service type, assembled by {@link #addRequiredAssemblers()}. |
| */ |
| private static final Map<Class, Assembler> REQUIRED_ASSEMBLERS; |
| |
| /** |
| * Assemblers for default services, keyed by service type, assembled if {@link #defaultServices()} is called. |
| */ |
| private static final Map<Class, Assembler> DEFAULT_ASSEMBLERS; |
| |
| static |
| { |
| REQUIRED_ASSEMBLERS = new HashMap<>( 1 ); |
| REQUIRED_ASSEMBLERS.put( UnitOfWorkFactory.class, new DefaultUnitOfWorkAssembler() ); |
| |
| DEFAULT_ASSEMBLERS = new HashMap<>( 3 ); |
| DEFAULT_ASSEMBLERS.put( IdentityGenerator.class, new DefaultIdentityGeneratorAssembler() ); |
| DEFAULT_ASSEMBLERS.put( Serialization.class, new DefaultSerializationAssembler() ); |
| DEFAULT_ASSEMBLERS.put( MetricsProvider.class, new DefaultMetricsProviderAssembler() ); |
| } |
| |
| private final LayerAssembly layerAssembly; |
| private String name; |
| private final MetaInfo metaInfo = new MetaInfo(); |
| |
| private final List<Class<? extends Activator<Module>>> activators = new ArrayList<>(); |
| private final List<ServiceAssemblyImpl> serviceAssemblies = new ArrayList<>(); |
| private final Map<Class<?>, ImportedServiceAssemblyImpl> importedServiceAssemblies = new LinkedHashMap<>(); |
| private final Map<Class<? extends EntityComposite>, EntityAssemblyImpl> entityAssemblies = new LinkedHashMap<>(); |
| private final Map<Class<? extends ValueComposite>, ValueAssemblyImpl> valueAssemblies = new LinkedHashMap<>(); |
| private final Map<Class<? extends TransientComposite>, TransientAssemblyImpl> transientAssemblies = new LinkedHashMap<>(); |
| |
| private final Map<Class<?>, ObjectAssemblyImpl> objectAssemblies = new LinkedHashMap<>(); |
| |
| private final MetaInfoDeclaration metaInfoDeclaration = new MetaInfoDeclaration(); |
| |
| ModuleAssemblyImpl(LayerAssembly layerAssembly, String name) |
| { |
| this.layerAssembly = layerAssembly; |
| this.name = name; |
| } |
| |
| @Override |
| public LayerAssembly layer() |
| { |
| return layerAssembly; |
| } |
| |
| @Override |
| public ModuleAssembly module(String layerName, String moduleName) |
| { |
| return layerAssembly.application().module(layerName, moduleName); |
| } |
| |
| @Override |
| public ModuleAssembly setName(String name) |
| { |
| this.name = name; |
| return this; |
| } |
| |
| @Override |
| public String name() |
| { |
| return name; |
| } |
| |
| public ModuleAssembly setMetaInfo(Object info) |
| { |
| metaInfo.set(info); |
| return this; |
| } |
| |
| @Override |
| public ServiceDeclaration defaultServices() |
| { |
| Class[] assembledServicesTypes = DEFAULT_ASSEMBLERS |
| .entrySet() |
| .stream() |
| .filter( |
| entry -> serviceAssemblies.stream().noneMatch( |
| serviceAssembly -> serviceAssembly.hasType( entry.getKey() ) ) ) |
| .peek( entry -> entry.getValue().assemble( this ) ) |
| .map( Map.Entry::getKey ) |
| .toArray( Class[]::new ); |
| return services( assembledServicesTypes ); |
| } |
| |
| @Override |
| @SafeVarargs |
| public final ModuleAssembly withActivators(Class<? extends Activator<Module>>... activators) |
| { |
| this.activators.addAll( asList( activators ) ); |
| return this; |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public ValueDeclaration values(Class<?>... valueTypes) |
| { |
| List<ValueAssemblyImpl> assemblies = new ArrayList<>(); |
| |
| for (Class valueType : valueTypes) |
| { |
| if (valueAssemblies.containsKey(valueType)) |
| { |
| assemblies.add(valueAssemblies.get(valueType)); |
| } |
| else |
| { |
| ValueAssemblyImpl valueAssembly = new ValueAssemblyImpl(valueType); |
| valueAssemblies.put(valueType, valueAssembly); |
| assemblies.add(valueAssembly); |
| } |
| } |
| |
| return new ValueDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public ValueDeclaration values(Predicate<? super ValueAssembly> specification) |
| { |
| List<ValueAssemblyImpl> assemblies = valueAssemblies.values().stream() |
| .filter(specification::test) |
| .collect(toList()); |
| return new ValueDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| @SuppressWarnings({"raw", "unchecked"}) |
| public TransientDeclaration transients(Class<?>... transientTypes) |
| { |
| List<TransientAssemblyImpl> assemblies = new ArrayList<>(); |
| |
| for (Class valueType : transientTypes) |
| { |
| if (transientAssemblies.containsKey(valueType)) |
| { |
| assemblies.add(transientAssemblies.get(valueType)); |
| } |
| else |
| { |
| TransientAssemblyImpl transientAssembly = new TransientAssemblyImpl(valueType); |
| transientAssemblies.put(valueType, transientAssembly); |
| assemblies.add(transientAssembly); |
| } |
| } |
| |
| return new TransientDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public TransientDeclaration transients(Predicate<? super TransientAssembly> specification) |
| { |
| List<TransientAssemblyImpl> assemblies = transientAssemblies.values().stream() |
| .filter(specification::test) |
| .collect(toList()); |
| |
| return new TransientDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| @SuppressWarnings({"raw", "unchecked"}) |
| public EntityDeclaration entities(Class<?>... entityTypes) |
| { |
| List<EntityAssemblyImpl> assemblies = new ArrayList<>(); |
| |
| for (Class entityType : entityTypes) |
| { |
| if (entityAssemblies.containsKey(entityType)) |
| { |
| assemblies.add(entityAssemblies.get(entityType)); |
| } |
| else |
| { |
| EntityAssemblyImpl entityAssembly = new EntityAssemblyImpl(entityType); |
| entityAssemblies.put(entityType, entityAssembly); |
| assemblies.add(entityAssembly); |
| } |
| } |
| |
| return new EntityDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public EntityDeclaration entities(Predicate<? super EntityAssembly> specification) |
| { |
| List<EntityAssemblyImpl> assemblies = entityAssemblies.values().stream() |
| .filter(specification::test) |
| .collect(toList()); |
| |
| return new EntityDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public ConfigurationDeclaration configurations(Class<?>... configurationTypes) |
| { |
| List<EntityAssemblyImpl> entityAssemblyList = new ArrayList<>(); |
| |
| for (Class entityType : configurationTypes) |
| { |
| if (this.entityAssemblies.containsKey(entityType)) |
| { |
| entityAssemblyList.add(this.entityAssemblies.get(entityType)); |
| } |
| else |
| { |
| EntityAssemblyImpl entityAssembly = new EntityAssemblyImpl(entityType); |
| this.entityAssemblies.put(entityType, entityAssembly); |
| entityAssemblyList.add(entityAssembly); |
| } |
| } |
| |
| List<ValueAssemblyImpl> valueAssemblyList = new ArrayList<>(); |
| |
| for (Class valueType : configurationTypes) |
| { |
| if (valueAssemblies.containsKey(valueType)) |
| { |
| valueAssemblyList.add(valueAssemblies.get(valueType)); |
| } |
| else |
| { |
| ValueAssemblyImpl valueAssembly = new ValueAssemblyImpl(valueType); |
| valueAssemblies.put(valueType, valueAssembly); |
| valueAssemblyList.add(valueAssembly); |
| valueAssembly.types.add(HasIdentity.class); |
| } |
| } |
| |
| return new ConfigurationDeclarationImpl(entityAssemblyList, valueAssemblyList); |
| } |
| |
| @Override |
| public ConfigurationDeclaration configurations( Predicate<HasTypes> specification ) |
| { |
| Predicate<HasTypes> isConfigurationComposite = new HasEqualOrAssignableFromType<>( HasIdentity.class ); |
| specification = specification.and( isConfigurationComposite ); |
| List<EntityAssemblyImpl> entityAssemblyList = new ArrayList<>(); |
| for( EntityAssemblyImpl entityAssembly : entityAssemblies.values() ) |
| { |
| if( specification.test( entityAssembly ) ) |
| { |
| entityAssemblyList.add( entityAssembly ); |
| } |
| } |
| List<ValueAssemblyImpl> valueAssemblyList = new ArrayList<>(); |
| for( ValueAssemblyImpl transientAssembly : valueAssemblies.values() ) |
| { |
| if( specification.test( transientAssembly ) ) |
| { |
| valueAssemblyList.add( transientAssembly ); |
| } |
| } |
| return new ConfigurationDeclarationImpl( entityAssemblyList, valueAssemblyList ); |
| } |
| |
| @Override |
| public ObjectDeclaration objects(Class<?>... objectTypes) |
| { |
| List<ObjectAssemblyImpl> assemblies = new ArrayList<>(); |
| |
| for (Class<?> objectType : objectTypes) |
| { |
| if (objectType.isInterface()) |
| { |
| throw new AssemblyException("Interfaces can not be Polygene Objects."); |
| } |
| if (objectAssemblies.containsKey(objectType)) |
| { |
| assemblies.add(objectAssemblies.get(objectType)); |
| } |
| else |
| { |
| ObjectAssemblyImpl objectAssembly = new ObjectAssemblyImpl(objectType); |
| objectAssemblies.put(objectType, objectAssembly); |
| assemblies.add(objectAssembly); |
| } |
| } |
| |
| return new ObjectDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public ObjectDeclaration objects(Predicate<? super ObjectAssembly> specification) |
| { |
| List<ObjectAssemblyImpl> assemblies = objectAssemblies.values().stream() |
| .filter(specification::test) |
| .collect(toList()); |
| |
| return new ObjectDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public ServiceDeclaration addServices(Class<?>... serviceTypes) |
| { |
| List<ServiceAssemblyImpl> assemblies = new ArrayList<>(); |
| |
| for (Class<?> serviceType : serviceTypes) |
| { |
| ServiceAssemblyImpl serviceAssembly = new ServiceAssemblyImpl(serviceType); |
| serviceAssemblies.add(serviceAssembly); |
| assemblies.add(serviceAssembly); |
| } |
| |
| return new ServiceDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public ServiceDeclaration services(Class<?>... serviceTypes) |
| { |
| List<ServiceAssemblyImpl> assemblies = new ArrayList<>(); |
| |
| for (Class<?> serviceType : serviceTypes) |
| { |
| if( serviceAssemblies.stream().anyMatch( AssemblySpecifications.ofAnyType( serviceType ) ) ) |
| { |
| serviceAssemblies.stream().filter( AssemblySpecifications.ofAnyType( serviceType ) ) |
| .forEach( assemblies::add ); |
| } |
| else |
| { |
| ServiceAssemblyImpl serviceAssembly = new ServiceAssemblyImpl(serviceType); |
| serviceAssemblies.add(serviceAssembly); |
| assemblies.add(serviceAssembly); |
| } |
| } |
| |
| return new ServiceDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public ServiceDeclaration services(Predicate<? super ServiceAssembly> specification) |
| { |
| List<ServiceAssemblyImpl> assemblies = serviceAssemblies.stream() |
| .filter(specification::test) |
| .collect(toList()); |
| return new ServiceDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public ImportedServiceDeclaration importedServices(Class<?>... serviceTypes) |
| { |
| List<ImportedServiceAssemblyImpl> assemblies = new ArrayList<>(); |
| |
| for (Class<?> serviceType : serviceTypes) |
| { |
| if (importedServiceAssemblies.containsKey(serviceType)) |
| { |
| assemblies.add(importedServiceAssemblies.get(serviceType)); |
| } |
| else |
| { |
| ImportedServiceAssemblyImpl serviceAssembly = new ImportedServiceAssemblyImpl(serviceType, this); |
| importedServiceAssemblies.put(serviceType, serviceAssembly); |
| assemblies.add(serviceAssembly); |
| } |
| } |
| |
| return new ImportedServiceDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public ImportedServiceDeclaration importedServices(Predicate<? super ImportedServiceAssembly> specification) |
| { |
| List<ImportedServiceAssemblyImpl> assemblies = importedServiceAssemblies.values().stream() |
| .filter(specification::test) |
| .collect(toList()); |
| |
| return new ImportedServiceDeclarationImpl(assemblies); |
| } |
| |
| @Override |
| public <T> MixinDeclaration<T> forMixin(Class<T> mixinType) |
| { |
| return metaInfoDeclaration.on(mixinType); |
| } |
| |
| @Override |
| public <ThrowableType extends Throwable> void visit(AssemblyVisitor<ThrowableType> visitor) |
| throws ThrowableType |
| { |
| visitor.visitModule( this ); |
| |
| for( TransientAssemblyImpl compositeDeclaration : transientAssemblies.values() ) |
| { |
| visitor.visitComposite( new TransientDeclarationImpl( singleton( compositeDeclaration ) ) ); |
| } |
| |
| for( EntityAssemblyImpl entityDeclaration : entityAssemblies.values() ) |
| { |
| visitor.visitEntity( new EntityDeclarationImpl( singleton( entityDeclaration ) ) ); |
| } |
| |
| for( ObjectAssemblyImpl objectDeclaration : objectAssemblies.values() ) |
| { |
| visitor.visitObject( new ObjectDeclarationImpl( singleton( objectDeclaration ) ) ); |
| } |
| |
| for( ServiceAssemblyImpl serviceDeclaration : serviceAssemblies ) |
| { |
| visitor.visitService( new ServiceDeclarationImpl( singleton( serviceDeclaration ) ) ); |
| } |
| |
| for( ImportedServiceAssemblyImpl importedServiceDeclaration : importedServiceAssemblies.values() ) |
| { |
| visitor.visitImportedService( new ImportedServiceDeclarationImpl( singleton( importedServiceDeclaration ) ) ); |
| } |
| |
| for( ValueAssemblyImpl valueDeclaration : valueAssemblies.values() ) |
| { |
| visitor.visitValue( new ValueDeclarationImpl( singleton( valueDeclaration ) ) ); |
| } |
| } |
| |
| @SuppressWarnings("OptionalGetWithoutIsPresent") |
| ModuleModel assembleModule(LayerModel layerModel, AssemblyHelper helper) |
| throws AssemblyException |
| { |
| addRequiredAssemblers(); |
| Set<Throwable> exceptions = new HashSet<>(); |
| List<TransientModel> transientModels = new ArrayList<>(); |
| List<ObjectModel> objectModels = new ArrayList<>(); |
| List<ValueModel> valueModels = new ArrayList<>(); |
| List<ServiceModel> serviceModels = new ArrayList<>(); |
| List<ImportedServiceModel> importedServiceModels = new ArrayList<>(); |
| List<EntityModel> entityModels = new ArrayList<>(); |
| ModuleModel moduleModel = new ModuleModel(name, |
| metaInfo, |
| layerModel, |
| new ActivatorsModel<>(activators), |
| new TransientsModel(transientModels), |
| new EntitiesModel(entityModels), |
| new ObjectsModel(objectModels), |
| new ValuesModel(valueModels), |
| new ServicesModel(serviceModels), |
| new ImportedServicesModel(importedServiceModels)); |
| |
| if (name == null) |
| { |
| throw new AssemblyException("Module must have name set"); |
| } |
| |
| transientModels.addAll(transientAssemblies.values().stream() |
| .map( composite -> |
| { |
| try |
| { |
| return composite.newTransientModel( moduleModel, metaInfoDeclaration, helper ); |
| } |
| catch( Exception e ) |
| { |
| exceptions.add( e ); |
| return null; |
| } |
| } ) |
| .filter( Objects::nonNull ) |
| .collect(toList())); |
| |
| valueModels.addAll(valueAssemblies.values().stream() |
| .map( value -> |
| { |
| try |
| { |
| return value.newValueModel( moduleModel, metaInfoDeclaration, helper ); |
| } |
| catch( Exception e ) |
| { |
| exceptions.add( e ); |
| return null; |
| } |
| } ) |
| .filter( Objects::nonNull ) |
| .collect(toList())); |
| |
| entityModels.addAll(entityAssemblies.values().stream() |
| .map( entityDeclaration -> |
| { |
| try |
| { |
| return entityDeclaration.newEntityModel( moduleModel, |
| metaInfoDeclaration, |
| metaInfoDeclaration, |
| metaInfoDeclaration, |
| metaInfoDeclaration, |
| helper ); |
| } |
| catch( Exception e ) |
| { |
| exceptions.add( e ); |
| return null; |
| } |
| } ) |
| .filter( Objects::nonNull ) |
| .collect(Collectors.toList())); |
| |
| for (ObjectAssemblyImpl objectDeclaration : objectAssemblies.values()) |
| { |
| objectDeclaration.addObjectModel(moduleModel, objectModels); |
| } |
| |
| serviceModels.addAll( |
| serviceAssemblies |
| .stream() |
| .map( serviceDeclaration -> |
| { |
| try |
| { |
| if( serviceDeclaration.identity == null ) |
| { |
| serviceDeclaration.identity = generateId( serviceDeclaration.types() ); |
| } |
| return ( serviceDeclaration.newServiceModel( moduleModel, metaInfoDeclaration, helper ) ); |
| } |
| catch( Exception e ) |
| { |
| exceptions.add( e ); |
| return null; |
| } |
| } ) |
| .filter( Objects::nonNull ) |
| .collect( Collectors.toList() ) ); |
| |
| for (ImportedServiceAssemblyImpl importedServiceDeclaration : importedServiceAssemblies.values()) |
| { |
| importedServiceDeclaration.addImportedServiceModel(moduleModel, importedServiceModels); |
| } |
| |
| // Check for duplicate service identities |
| Set<String> identities = new HashSet<>(); |
| for (ServiceModel serviceModel : serviceModels) |
| { |
| String identity = serviceModel.identity().toString(); |
| if (identities.contains(identity)) |
| { |
| DuplicateServiceIdentityException exception = new DuplicateServiceIdentityException( |
| "Duplicated service reference: " + identity + " in module " + moduleModel.name() |
| ); |
| exceptions.add( exception.fillInStackTrace() ); |
| } else |
| { |
| identities.add( identity ); |
| } |
| } |
| for (ImportedServiceModel serviceModel : importedServiceModels) |
| { |
| String identity = serviceModel.identity().toString(); |
| if (identities.contains(identity)) |
| { |
| DuplicateServiceIdentityException exception = new DuplicateServiceIdentityException( |
| "Duplicated service reference: " + identity + " in module " + moduleModel.name() |
| ); |
| exceptions.add( exception.fillInStackTrace() ); |
| } |
| else |
| { |
| identities.add( identity ); |
| } |
| } |
| |
| importedServiceModels |
| .stream() |
| .filter( |
| importedServiceModel -> |
| objectModels.stream().noneMatch( model -> model.types().findFirst().get() |
| .equals( importedServiceModel.serviceImporter() ) ) ) |
| .forEach( |
| importedServiceModel -> |
| { |
| try |
| { |
| objectModels.add( new ObjectModel( moduleModel, importedServiceModel.serviceImporter(), |
| Visibility.module, new MetaInfo() ) ); |
| } |
| catch( Exception e ) |
| { |
| exceptions.add( e ); |
| } |
| } ); |
| if( exceptions.size() == 0 ) |
| { |
| return moduleModel; |
| } |
| throw new AssemblyReportException( exceptions ); |
| } |
| |
| private void addRequiredAssemblers() |
| { |
| REQUIRED_ASSEMBLERS |
| .entrySet() |
| .stream() |
| .filter( |
| entry -> serviceAssemblies.stream().noneMatch( |
| serviceAssembly -> serviceAssembly.hasType( entry.getKey() ) ) ) |
| .forEach( entry -> entry.getValue().assemble( this ) ); |
| } |
| |
| private Identity generateId(Stream<Class<?>> serviceTypes) |
| { |
| // Find service reference that is not yet used |
| Class<?> serviceType = serviceTypes.findFirst() |
| .orElse(null); // Use the first, which *SHOULD* be the main serviceType |
| int idx = 0; |
| Identity id = StringIdentity.identityOf( serviceType.getSimpleName() ); |
| boolean invalid; |
| do |
| { |
| invalid = false; |
| for (ServiceAssemblyImpl serviceAssembly : serviceAssemblies) |
| { |
| if (serviceAssembly.identity() != null && serviceAssembly.identity().equals(id)) |
| { |
| idx++; |
| id = StringIdentity.identityOf( serviceType.getSimpleName() + "_" + idx ); |
| invalid = true; |
| break; |
| } |
| } |
| } |
| while (invalid); |
| return id; |
| } |
| } |