blob: d1eb738f18812ddf3bc83ea3001752fa3aab1149 [file] [log] [blame]
/*
* Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
* Copyright (c) 2012, Paul Merlin.
*
* 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.apache.zest.runtime.bootstrap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.zest.api.composite.ModelDescriptor;
import org.apache.zest.api.structure.Application;
import org.apache.zest.api.structure.ApplicationDescriptor;
import org.apache.zest.api.structure.Layer;
import org.apache.zest.bootstrap.ApplicationAssembly;
import org.apache.zest.bootstrap.ApplicationModelFactory;
import org.apache.zest.bootstrap.AssemblyException;
import org.apache.zest.bootstrap.BindingException;
import org.apache.zest.bootstrap.LayerAssembly;
import org.apache.zest.functional.HierarchicalVisitor;
import org.apache.zest.runtime.activation.ActivatorsModel;
import org.apache.zest.runtime.composite.CompositeMethodModel;
import org.apache.zest.runtime.injection.InjectedFieldModel;
import org.apache.zest.runtime.model.Binder;
import org.apache.zest.runtime.model.Resolution;
import org.apache.zest.runtime.structure.ApplicationModel;
import org.apache.zest.runtime.structure.LayerModel;
import org.apache.zest.runtime.structure.ModuleModel;
import org.apache.zest.runtime.structure.UsedLayersModel;
/**
* Factory for Applications.
*/
public final class ApplicationModelFactoryImpl
implements ApplicationModelFactory
{
@Override
public ApplicationDescriptor newApplicationModel( ApplicationAssembly assembly )
throws AssemblyException
{
AssemblyHelper helper = new AssemblyHelper();
ApplicationAssemblyImpl applicationAssembly = (ApplicationAssemblyImpl) assembly;
ActivatorsModel<Application> applicationActivators = new ActivatorsModel<>( applicationAssembly.activators() );
List<LayerModel> layerModels = new ArrayList<>();
final ApplicationModel applicationModel = new ApplicationModel( applicationAssembly.name(),
applicationAssembly.version(),
applicationAssembly.mode(),
applicationAssembly.metaInfo(),
applicationActivators,
layerModels );
Map<LayerAssembly, LayerModel> mapAssemblyModel = new HashMap<>();
Map<LayerAssembly, List<LayerModel>> mapUsedLayers = new HashMap<>();
// Build all layers
List<LayerAssemblyImpl> layerAssemblies = new ArrayList<>( applicationAssembly.layerAssemblies() );
for( LayerAssemblyImpl layerAssembly : layerAssemblies )
{
List<LayerModel> usedLayers = new ArrayList<>();
mapUsedLayers.put( layerAssembly, usedLayers );
UsedLayersModel usedLayersModel = new UsedLayersModel( usedLayers );
List<ModuleModel> moduleModels = new ArrayList<>();
String name = layerAssembly.name();
if( name == null )
{
throw new AssemblyException( "Layer must have name set" );
}
ActivatorsModel<Layer> layerActivators = new ActivatorsModel<>( layerAssembly.activators() );
LayerModel layerModel = new LayerModel( name, layerAssembly.metaInfo(), usedLayersModel, layerActivators, moduleModels );
for( ModuleAssemblyImpl moduleAssembly : layerAssembly.moduleAssemblies() )
{
moduleModels.add( moduleAssembly.assembleModule( helper ) );
}
mapAssemblyModel.put( layerAssembly, layerModel );
layerModels.add( layerModel );
}
// Populate used layer lists
for( LayerAssemblyImpl layerAssembly : layerAssemblies )
{
Set<LayerAssembly> usesLayers = layerAssembly.uses();
List<LayerModel> usedLayers = mapUsedLayers.get( layerAssembly );
for( LayerAssembly usesLayer : usesLayers )
{
LayerModel layerModel = mapAssemblyModel.get( usesLayer );
usedLayers.add( layerModel );
}
}
// Bind model
// This will resolve all dependencies
try
{
// applicationModel.bind();
applicationModel.accept( new BindingVisitor( applicationModel ) );
}
catch( BindingException e )
{
throw new AssemblyException( "Unable to bind: " + applicationModel, e );
}
return applicationModel;
}
private static class BindingVisitor
implements HierarchicalVisitor<Object, Object, BindingException>
{
private LayerModel layer;
private ModuleModel module;
private ModelDescriptor objectDescriptor;
private CompositeMethodModel compositeMethodModel;
private Resolution resolution;
private final ApplicationModel applicationModel;
private BindingVisitor( ApplicationModel applicationModel )
{
this.applicationModel = applicationModel;
}
@Override
public boolean visitEnter( Object visited )
throws BindingException
{
if( visited instanceof Binder )
{
Binder binder = (Binder) visited;
binder.bind( resolution );
return false;
}
else if( visited instanceof CompositeMethodModel )
{
compositeMethodModel = (CompositeMethodModel) visited;
resolution = new Resolution( applicationModel, layer, module, objectDescriptor, compositeMethodModel, null );
}
else if( visited instanceof ModelDescriptor )
{
objectDescriptor = (ModelDescriptor) visited;
resolution = new Resolution( applicationModel, layer, module, objectDescriptor, null, null );
}
else if( visited instanceof InjectedFieldModel )
{
InjectedFieldModel fieldModel = (InjectedFieldModel) visited;
fieldModel.bind( new Resolution( applicationModel, layer, module,
objectDescriptor, compositeMethodModel, fieldModel.field() ) );
}
else if( visited instanceof ModuleModel )
{
module = (ModuleModel) visited;
}
else if( visited instanceof LayerModel )
{
layer = (LayerModel) visited;
}
return true;
}
@Override
public boolean visitLeave( Object visited )
throws BindingException
{
return true;
}
@Override
public boolean visit( Object visited )
throws BindingException
{
if( visited instanceof Binder )
{
( (Binder) visited ).bind( resolution );
}
return true;
}
}
}