blob: 3ed2e9f7214c37cc0eeccecce52887a234175539 [file] [log] [blame]
/*
* 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.bootstrap.layered;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import org.apache.polygene.api.activation.ActivationException;
import org.apache.polygene.api.activation.PassivationException;
import org.apache.polygene.api.structure.Application;
import org.apache.polygene.api.structure.ApplicationDescriptor;
import org.apache.polygene.bootstrap.ApplicationAssembler;
import org.apache.polygene.bootstrap.ApplicationAssembly;
import org.apache.polygene.bootstrap.ApplicationAssemblyFactory;
import org.apache.polygene.bootstrap.AssemblyException;
import org.apache.polygene.bootstrap.Energy4Java;
import org.apache.polygene.bootstrap.LayerAssembly;
import static org.apache.polygene.api.util.AccessibleObjects.accessible;
public abstract class LayeredApplicationAssembler
implements ApplicationAssembler
{
protected final Energy4Java polygene;
protected final String name;
protected final String version;
private final Application.Mode mode;
private final HashMap<Class<? extends LayerAssembler>, LayerAssembler> assemblers = new HashMap<>();
private ApplicationAssembly assembly;
protected ApplicationDescriptor model;
protected Application application;
public LayeredApplicationAssembler( String name, String version, Application.Mode mode )
throws AssemblyException
{
this.name = name;
this.version = version;
this.mode = mode;
polygene = new Energy4Java();
}
public void initialize()
throws AssemblyException
{
model = polygene.newApplicationModel( this );
onModelCreated( model );
instantiateApplication( polygene, model );
}
public ApplicationAssembly assembly()
{
return assembly;
}
/**
* This method is called from the <code>initialize</code> method to instantiate the Polygene application from the
* application model.
*
* <p>
* The default implementation simply calls;
* </p>
* <pre><code>
* application = model.newInstance( polygene.spi() );
* </code></pre>
*
* @param polygene The Polygene runtime engine.
* @param model The application model descriptor.
*/
protected void instantiateApplication( Energy4Java polygene, ApplicationDescriptor model )
{
application = model.newInstance( polygene.spi() );
}
/**
* This method is called after the Application Model has been created, before the instantiation of the Polygene
* application.
*
* <p>
* The default implementation does nothing. Applications may have advanced features to inspect or
* modify the model prior to instantiation, and this is the place where such advanced manipulation is
* expected to take place.
* </p>
*
* @param model The model that has just been created.
*/
protected void onModelCreated( ApplicationDescriptor model )
{
}
public ApplicationDescriptor model()
{
return model;
}
public Application application()
{
return application;
}
public void start()
throws ActivationException
{
application.activate();
}
public void stop()
throws PassivationException
{
application.passivate();
}
@Override
public ApplicationAssembly assemble( ApplicationAssemblyFactory applicationFactory )
{
assembly = applicationFactory.newApplicationAssembly();
assembleApplication();
return assembly;
}
protected void assembleApplication()
{
assembly.setName( name );
assembly.setVersion( version );
assembly.setMode( mode );
assembleLayers( assembly );
}
protected LayerAssembly createLayer( Class<? extends LayerAssembler> layerAssemblerClass )
throws IllegalArgumentException
{
try
{
String classname = layerAssemblerClass.getSimpleName();
if( classname.endsWith( "Layer" ) )
{
classname = classname.substring( 0, classname.length() - 5 ) + " Layer";
}
setNameIfPresent( layerAssemblerClass, classname );
LayerAssembly layer = assembly.layer( classname );
LayerAssembler layerAssembler = instantiateLayerAssembler( layerAssemblerClass, layer );
assemblers.put( layerAssemblerClass, layerAssembler );
assembleLayer( layerAssembler, layer );
return layer;
}
catch( Exception e )
{
throw new IllegalArgumentException( "Unable to instantiate layer with " + layerAssemblerClass.getSimpleName(), e );
}
}
protected void assembleLayer( LayerAssembler layerAssembler, LayerAssembly layer )
throws AssemblyException
{
layerAssembler.assemble( layer );
}
protected <T extends LayerAssembler> LayerAssembler instantiateLayerAssembler( Class<T> layerAssemblerClass,
LayerAssembly layer
)
throws InstantiationException, IllegalAccessException, InvocationTargetException, IllegalLayerAssemblerException
{
LayerAssembler assembler = createWithFactoryMethod( layerAssemblerClass, layer );
if( assembler != null )
{
return assembler;
}
assembler = createWithConstructor( layerAssemblerClass, layer );
if( assembler != null )
{
return assembler;
}
throw new IllegalLayerAssemblerException( "No matching factory method nor constructor found in " + layerAssemblerClass );
}
private LayerAssembler createWithFactoryMethod( Class<? extends LayerAssembler> layerAssemblerClass,
LayerAssembly layer
)
throws InvocationTargetException, IllegalAccessException
{
try
{
Method factoryMethod = accessible( layerAssemblerClass.getDeclaredMethod( "create", LayerAssembly.class ) );
int modifiers = factoryMethod.getModifiers();
if( Modifier.isStatic( modifiers ) && LayerAssembler.class.isAssignableFrom( factoryMethod.getReturnType() ) )
{
return (LayerAssembler) factoryMethod.invoke( null, layer );
}
}
catch( NoSuchMethodException e )
{
try
{
Method factoryMethod = accessible( layerAssemblerClass.getDeclaredMethod( "create" ) );
int modifiers = factoryMethod.getModifiers();
if( Modifier.isStatic( modifiers ) && LayerAssembler.class.isAssignableFrom( factoryMethod.getReturnType() ) )
{
return (LayerAssembler) factoryMethod.invoke( null );
}
}
catch( NoSuchMethodException e1 )
{
}
}
return null;
}
private LayerAssembler createWithConstructor( Class<? extends LayerAssembler> layerAssemblerClass,
LayerAssembly assembly
)
throws IllegalAccessException, InvocationTargetException, InstantiationException
{
try
{
Constructor<? extends LayerAssembler> constructor = layerAssemblerClass.getConstructor( LayerAssembly.class );
if( constructor != null )
{
return accessible( constructor ).newInstance( assembly );
}
}
catch( NoSuchMethodException e )
{
try
{
Constructor<? extends LayerAssembler> constructor = layerAssemblerClass.getDeclaredConstructor();
if( constructor != null )
{
return accessible( constructor ).newInstance();
}
}
catch( NoSuchMethodException e1 )
{
return null;
}
}
return null;
}
static void setNameIfPresent( Class<?> clazz, String classname )
throws IllegalAccessException
{
try
{
Field field = clazz.getDeclaredField( "NAME" );
if( Modifier.isStatic( field.getModifiers() ) )
{
accessible( field ).set( null, classname );
}
}
catch( Exception e )
{
// Ignore and consider normal.
}
}
@SuppressWarnings( "unchecked" )
protected <T extends LayerAssembler> T assemblerOf( Class<T> layerAssemblerClass )
{
return (T) assemblers.get( layerAssemblerClass );
}
/**
* Called from the <code>assemble</code> method to assemble the layers in the application.
*
* <p>
* This method must be implemented, and is typically a list of LayerAssembler instantiations, followed
* by {@link LayerAssembly#uses(LayerAssembly...)} declarations.
* </p>
*
* @param assembly Application assembly
* @throws AssemblyException on invalid assembly
*/
protected abstract void assembleLayers( ApplicationAssembly assembly )
throws AssemblyException;
}