blob: 4d4e0ccb52ad576a25f23405bbb011bd9e0d2786 [file] [log] [blame]
/*
* Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
* Copyright (c) 2008, Sonny Gill. All Rights Reserved.
* Copyright (c) 2008, Niclas Hedhman. All Rights Reserved.
* Copyright (c) 2014-2015, Paul Merlin. All Rights Reserved.
*
* 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.qi4j.tools.model.descriptor;
import java.util.HashMap;
import java.util.Map;
import org.qi4j.api.activation.ActivatorDescriptor;
import org.qi4j.api.composite.ConstructorDescriptor;
import org.qi4j.api.composite.InjectedFieldDescriptor;
import org.qi4j.api.composite.InjectedMethodDescriptor;
import org.qi4j.api.composite.InjectedParametersDescriptor;
import org.qi4j.api.composite.MethodDescriptor;
import org.qi4j.api.composite.TransientDescriptor;
import org.qi4j.api.concern.ConcernDescriptor;
import org.qi4j.api.concern.ConcernsDescriptor;
import org.qi4j.api.constraint.ConstraintDescriptor;
import org.qi4j.api.constraint.ConstraintsDescriptor;
import org.qi4j.api.entity.EntityDescriptor;
import org.qi4j.api.mixin.MixinDescriptor;
import org.qi4j.api.object.ObjectDescriptor;
import org.qi4j.api.service.ImportedServiceDescriptor;
import org.qi4j.api.service.ServiceDescriptor;
import org.qi4j.api.sideeffect.SideEffectDescriptor;
import org.qi4j.api.sideeffect.SideEffectsDescriptor;
import org.qi4j.api.structure.ApplicationDescriptor;
import org.qi4j.api.structure.LayerDescriptor;
import org.qi4j.api.structure.ModuleDescriptor;
import org.qi4j.api.structure.UsedLayersDescriptor;
import org.qi4j.api.value.ValueDescriptor;
import org.qi4j.functional.HierarchicalVisitor;
public final class ApplicationDetailDescriptorBuilder
{
private ApplicationDetailDescriptorBuilder()
{
}
public static ApplicationDetailDescriptor createApplicationDetailDescriptor( ApplicationDescriptor anApplication )
{
ApplicationDescriptorVisitor visitor = new ApplicationDescriptorVisitor();
anApplication.accept( visitor );
return visitor.applicationDescriptor;
}
static final class ApplicationDescriptorVisitor
implements HierarchicalVisitor<Object, Object, RuntimeException>
{
// Temp: application
private ApplicationDetailDescriptor applicationDescriptor;
// Temp: Layer variables
private LayerDetailDescriptor currLayerDescriptor;
// Cache to lookup layer descriptor -> node
private final Map<LayerDescriptor, LayerDetailDescriptor> layerDescToDetail;
// Temp: current module
private ModuleDetailDescriptor currModuleDescriptor;
// Temp: current composite
private CompositeDetailDescriptor currCompositeDescriptor;
// Temp: curr activator
private ActivatorDetailDescriptor currActivatorDescriptor;
// Temp: curr mixin
private MixinDetailDescriptor currMixinDescriptor;
// Temp: current constructor
private ConstructorDetailDescriptor currConstructorDescriptor;
// Temp: current injected method
private InjectedMethodDetailDescriptor currInjectedMethodDescriptor;
// Temp: current composite method
private CompositeMethodDetailDescriptor currMethodDesciptor;
// Temp: current method constraints
private MethodConstraintsDetailDescriptor currMethodConstraintsDescriptor;
// Temp: current object
private ObjectDetailDescriptor currObjectDescriptor;
// Temp: current method concerns
private MethodConcernsDetailDescriptor currMethodConcernsDescriptor;
// Temp: current method concern
private MethodConcernDetailDescriptor currMethodConcernDescriptor;
// Temp: current method side effects
private MethodSideEffectsDetailDescriptor currMethodSideEffectsDescriptor;
// Temp: current side effect
private MethodSideEffectDetailDescriptor currMethodSideEffectDescriptor;
private ApplicationDescriptorVisitor()
{
layerDescToDetail = new HashMap<>();
}
@Override
public boolean visitEnter( Object visited )
throws RuntimeException
{
if( visited instanceof ApplicationDescriptor )
{
applicationDescriptor = new ApplicationDetailDescriptor( (ApplicationDescriptor) visited );
}
else if( visited instanceof LayerDescriptor )
{
LayerDescriptor layerDescriptor = (LayerDescriptor) visited;
currLayerDescriptor = getLayerDetailDescriptor( layerDescriptor );
applicationDescriptor.addLayer( currLayerDescriptor );
UsedLayersDescriptor usedLayesDescriptor = layerDescriptor.usedLayers();
Iterable<? extends LayerDescriptor> usedLayers = usedLayesDescriptor.layers();
for( LayerDescriptor usedLayer : usedLayers )
{
LayerDetailDescriptor usedLayerDetailDesc = getLayerDetailDescriptor( usedLayer );
currLayerDescriptor.addUsedLayer( usedLayerDetailDesc );
}
}
else if( visited instanceof ModuleDescriptor )
{
ModuleDescriptor moduleDescriptor = (ModuleDescriptor) visited;
currModuleDescriptor = new ModuleDetailDescriptor( moduleDescriptor );
currLayerDescriptor.addModule( currModuleDescriptor );
}
else if( visited instanceof ActivatorDescriptor )
{
ActivatorDescriptor activatorDescriptor = (ActivatorDescriptor) visited;
currActivatorDescriptor = new ActivatorDetailDescriptor( activatorDescriptor );
if( currCompositeDescriptor != null )
{
if( currCompositeDescriptor instanceof ServiceDetailDescriptor )
{
( (ServiceDetailDescriptor) currCompositeDescriptor ).addActivator( currActivatorDescriptor );
}
else if( currCompositeDescriptor instanceof ImportedServiceDetailDescriptor )
{
( (ImportedServiceDetailDescriptor) currCompositeDescriptor ).addActivator( currActivatorDescriptor );
}
else
{
throw new IllegalStateException( "ActivatorDescriptor is only valid for "
+ "services, modules, layers and application." );
}
}
else if( currModuleDescriptor != null )
{
currModuleDescriptor.addActivator( currActivatorDescriptor );
}
else if( currLayerDescriptor != null )
{
currLayerDescriptor.addActivator( currActivatorDescriptor );
}
else if( applicationDescriptor != null )
{
applicationDescriptor.addActivator( currActivatorDescriptor );
}
else
{
throw new IllegalStateException( "ActivatorDescriptor is only valid for "
+ "services, modules, layers and application." );
}
}
else if( visited instanceof ServiceDescriptor )
{
ServiceDetailDescriptor descriptor = new ServiceDetailDescriptor( (ServiceDescriptor) visited );
currModuleDescriptor.addService( descriptor );
currCompositeDescriptor = descriptor;
}
else if( visited instanceof ImportedServiceDescriptor )
{
ImportedServiceDetailDescriptor descriptor = new ImportedServiceDetailDescriptor( new ImportedServiceCompositeDescriptor( (ImportedServiceDescriptor) visited ) );
currModuleDescriptor.addImportedService( descriptor );
currCompositeDescriptor = descriptor;
}
else if( visited instanceof EntityDescriptor )
{
EntityDetailDescriptor descriptor = new EntityDetailDescriptor( (EntityDescriptor) visited );
currModuleDescriptor.addEntity( descriptor );
currCompositeDescriptor = descriptor;
}
else if( visited instanceof ValueDescriptor )
{
ValueDetailDescriptor descriptor = new ValueDetailDescriptor( (ValueDescriptor) visited );
currModuleDescriptor.addValue( descriptor );
currCompositeDescriptor = descriptor;
}
else if( visited instanceof TransientDescriptor )
{
TransientDetailDescriptor descriptor = new TransientDetailDescriptor( (TransientDescriptor) visited );
currModuleDescriptor.addTransient( descriptor );
currCompositeDescriptor = descriptor;
}
else if( visited instanceof MethodDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
currMethodDesciptor = new CompositeMethodDetailDescriptor( (MethodDescriptor) visited );
currCompositeDescriptor.addMethod( currMethodDesciptor );
}
else if( visited instanceof ConstraintsDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
currMethodConstraintsDescriptor = new MethodConstraintsDetailDescriptor( (ConstraintsDescriptor) visited );
currMethodDesciptor.setConstraints( currMethodConstraintsDescriptor );
}
else if( visited instanceof ConcernsDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
currMethodConcernsDescriptor = new MethodConcernsDetailDescriptor( (ConcernsDescriptor) visited );
currMethodDesciptor.setConcerns( currMethodConcernsDescriptor );
}
else if( visited instanceof ConcernDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
resetInjectableRelatedVariables();
currMethodConcernDescriptor = new MethodConcernDetailDescriptor( (ConcernDescriptor) visited );
currMethodConcernsDescriptor.addConcern( currMethodConcernDescriptor );
}
else if( visited instanceof SideEffectsDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
currMethodSideEffectsDescriptor = new MethodSideEffectsDetailDescriptor( (SideEffectsDescriptor) visited );
currMethodDesciptor.setSideEffects( currMethodSideEffectsDescriptor );
}
else if( visited instanceof SideEffectDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
resetInjectableRelatedVariables();
currMethodSideEffectDescriptor = new MethodSideEffectDetailDescriptor( (SideEffectDescriptor) visited );
currMethodSideEffectsDescriptor.addSideEffect( currMethodSideEffectDescriptor );
}
else if( visited instanceof MixinDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
resetInjectableRelatedVariables();
currMixinDescriptor = new MixinDetailDescriptor( (MixinDescriptor) visited );
currCompositeDescriptor.addMixin( currMixinDescriptor );
}
else if( visited instanceof ObjectDescriptor )
{
resetInjectableRelatedVariables();
currObjectDescriptor = new ObjectDetailDescriptor( (ObjectDescriptor) visited );
currModuleDescriptor.addObject( currObjectDescriptor );
}
else if( visited instanceof ConstructorDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
currConstructorDescriptor = new ConstructorDetailDescriptor( (ConstructorDescriptor) visited );
currInjectedMethodDescriptor = null;
// Invoked for mixin and object
if( currActivatorDescriptor != null )
{
currActivatorDescriptor.addConstructor( currConstructorDescriptor );
}
else if( currMixinDescriptor != null )
{
currMixinDescriptor.addConstructor( currConstructorDescriptor );
}
else if( currObjectDescriptor != null )
{
currObjectDescriptor.addConstructor( currConstructorDescriptor );
}
else if( currMethodConcernDescriptor != null )
{
currMethodConcernDescriptor.addConstructor( currConstructorDescriptor );
}
else if( currMethodSideEffectDescriptor != null )
{
currMethodSideEffectDescriptor.addConstructor( currConstructorDescriptor );
}
else
{
throw new IllegalStateException( "ConstructorDescriptor is only valid for "
+ "activator, mixin, object, concern and side-effect. "
+ "Visiting [" + visited + "]" );
}
}
else if( visited instanceof InjectedParametersDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
InjectedParametersDetailDescriptor detailDescriptor = new InjectedParametersDetailDescriptor( (InjectedParametersDescriptor) visited );
// Invoked for constructor and injected method
if( currConstructorDescriptor != null )
{
currConstructorDescriptor.setInjectedParameter( detailDescriptor );
}
else if( currInjectedMethodDescriptor != null )
{
currInjectedMethodDescriptor.setInjectedParameter( detailDescriptor );
}
else
{
throw new IllegalStateException( "InjectedParametersDescriptor is only valid for "
+ "constructor and injector method descriptor." );
}
}
else if( visited instanceof InjectedMethodDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
// Invoked for mixin and object
currInjectedMethodDescriptor = new InjectedMethodDetailDescriptor( (InjectedMethodDescriptor) visited );
currConstructorDescriptor = null;
// Invoked for mixin and object
if( currActivatorDescriptor != null )
{
currActivatorDescriptor.addInjectedMethod( currInjectedMethodDescriptor );
}
else if( currMixinDescriptor != null )
{
currMixinDescriptor.addInjectedMethod( currInjectedMethodDescriptor );
}
else if( currObjectDescriptor != null )
{
currObjectDescriptor.addInjectedMethod( currInjectedMethodDescriptor );
}
else if( currMethodConcernDescriptor != null )
{
currMethodConcernDescriptor.addInjectedMethod( currInjectedMethodDescriptor );
}
else if( currMethodSideEffectDescriptor != null )
{
currMethodSideEffectDescriptor.addInjectedMethod( currInjectedMethodDescriptor );
}
else
{
throw new IllegalStateException( "InjectedMethodDescriptor is only valid for "
+ "mixin, object, concern and side-effect." );
}
}
return true;
}
@Override
public boolean visitLeave( Object visited )
throws RuntimeException
{
return true;
}
@Override
public boolean visit( Object visited )
throws RuntimeException
{
if( visited instanceof ConstraintDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
MethodConstraintDetailDescriptor detailDescriptor = new MethodConstraintDetailDescriptor( (ConstraintDescriptor) visited );
currMethodConstraintsDescriptor.addConstraint( detailDescriptor );
}
else if( visited instanceof InjectedFieldDescriptor )
{
if( currCompositeDescriptor == null )
{
// Service via CompositeDescriptor in progress )
return false;
}
InjectedFieldDetailDescriptor detailDescriptor = new InjectedFieldDetailDescriptor( (InjectedFieldDescriptor) visited );
// Invoked for mixin and object
if( currActivatorDescriptor != null )
{
currActivatorDescriptor.addInjectedField( detailDescriptor );
}
else if( currMixinDescriptor != null )
{
currMixinDescriptor.addInjectedField( detailDescriptor );
}
else if( currObjectDescriptor != null )
{
currObjectDescriptor.addInjectedField( detailDescriptor );
}
else if( currMethodConcernDescriptor != null )
{
currMethodConcernDescriptor.addInjectedField( detailDescriptor );
}
else if( currMethodSideEffectDescriptor != null )
{
currMethodSideEffectDescriptor.addInjectedField( detailDescriptor );
}
else
{
throw new IllegalStateException( "InjectedFieldDescriptor is only valid for "
+ "mixin, object, concern and side-effect." );
}
}
return true;
}
private LayerDetailDescriptor getLayerDetailDescriptor( LayerDescriptor aDescriptor )
{
LayerDetailDescriptor detailDescriptor = layerDescToDetail.get( aDescriptor );
if( detailDescriptor == null )
{
detailDescriptor = new LayerDetailDescriptor( aDescriptor );
layerDescToDetail.put( aDescriptor, detailDescriptor );
}
return detailDescriptor;
}
private void resetInjectableRelatedVariables()
{
currMixinDescriptor = null;
currObjectDescriptor = null;
currMethodConcernDescriptor = null;
currMethodSideEffectDescriptor = null;
}
}
}