Package org.codeartisans.playqi

Source Code of org.codeartisans.playqi.PlayQiPlugin

/*
* Copyright 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.codeartisans.playqi;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.qi4j.api.Qi4j;
import org.qi4j.api.composite.TransientBuilderFactory;
import org.qi4j.api.injection.scope.Service;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.service.ServiceFinder;
import org.qi4j.api.service.ServiceReference;
import org.qi4j.api.structure.Application;
import org.qi4j.api.structure.Application.Mode;
import org.qi4j.api.structure.ApplicationDescriptor;
import org.qi4j.api.structure.Layer;
import org.qi4j.api.structure.Module;
import org.qi4j.api.unitofwork.UnitOfWorkFactory;
import org.qi4j.bootstrap.ApplicationAssembler;
import org.qi4j.bootstrap.ApplicationAssembly;
import org.qi4j.bootstrap.AssemblyException;
import org.qi4j.bootstrap.Qi4jRuntime;
import org.qi4j.bootstrap.RuntimeFactory;
import org.qi4j.bootstrap.SingletonAssembler;
import org.qi4j.envisage.Envisage;
import org.qi4j.library.swing.entityviewer.EntityViewer;
import org.qi4j.spi.Qi4jSPI;

public class PlayQiPlugin
        extends play.Plugin
{

    private static final String ENABLED = "enabled";
    private static final String CONFIG_APP_ASSEMBLER = "qi4j.app-assembler";
    private static final String CONFIG_ENVISAGE = "qi4j.envisage";
    private static final String CONFIG_ENTITY_VIEWER = "qi4j.entity-viewer";
    private static final String CONFIG_CONTROLLERS_LAYER = "qi4j.controllers-layer";
    private static final String CONFIG_CONTROLLERS_MODULE = "qi4j.controllers-module";
    private static final String CONFIG_CONTROLLERS_PACKAGES = "qi4j.controllers-packages";
    private final play.Application play2app;
    private Qi4jRuntime qi4j;
    private Application application;
    private Envisage envisageInstance;
    private EntityViewer entityViewerInstance;

    public PlayQiPlugin( play.Application play2app )
    {
        this.play2app = play2app;
    }

    public Application application()
    {
        return application;
    }

    public Qi4j api()
    {
        return qi4j.api();
    }

    public Qi4jSPI spi()
    {
        return qi4j.spi();
    }

    public Layer controllersLayer()
    {
        play.Configuration configuration = play2app.configuration();
        String controllersLayerName = configuration.getString( CONFIG_CONTROLLERS_LAYER );
        return application.findLayer( controllersLayerName );
    }

    public Module controllersModule()
    {
        play.Configuration configuration = play2app.configuration();
        String controllersLayerName = configuration.getString( CONFIG_CONTROLLERS_LAYER );
        String controllersModuleName = configuration.getString( CONFIG_CONTROLLERS_MODULE );
        return application.findModule( controllersLayerName, controllersModuleName );
    }

    @Override
    public void onStart()
    {
        super.onStart();

        ClassLoader classloader = play2app.classloader();
        play.Configuration configuration = play2app.configuration();

        ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader( classloader );


        String appAssClassName = configuration.getString( CONFIG_APP_ASSEMBLER );
        boolean envisage = ENABLED.equals( configuration.getString( CONFIG_ENVISAGE ) );
        boolean entityViewer = ENABLED.equals( configuration.getString( CONFIG_ENTITY_VIEWER ) );
        String controllersLayerName = configuration.getString( CONFIG_CONTROLLERS_LAYER );
        String controllersModuleName = configuration.getString( CONFIG_CONTROLLERS_MODULE );
        String controllersPackages = configuration.getString( CONFIG_CONTROLLERS_PACKAGES );
        controllersPackages = controllersPackages == null ? "controllers" : controllersPackages;

        Mode mode = play2app.isProd() ? Mode.production : play2app.isDev() ? Mode.development : Mode.test;

        try
        {

            Class<ApplicationAssembler> appAssClass = ( Class<ApplicationAssembler> ) classloader.loadClass( appAssClassName );
            ApplicationAssembler assembler = appAssClass.newInstance();

            if( assembler instanceof SingletonAssembler )
            {
                controllersLayerName = PlayQiSingle.LAYER;
                controllersModuleName = PlayQiSingle.MODULE;
            }

            RuntimeFactory runtimeFactory = ( RuntimeFactory ) classloader.loadClass(
                    RuntimeFactory.StandaloneApplicationRuntimeFactory.class.getName() ).newInstance();
            qi4j = runtimeFactory.createRuntime();
            if( qi4j == null )
            {
                throw new PlayQiException( "Can not create Qi4j without a Qi4j Runtime." );
            }

            ApplicationAssembly assembly = assembler.assemble( qi4j.applicationAssemblyFactory() );
            if( assembly == null )
            {
                throw new PlayQiException( "Application assembler did not return any ApplicationAssembly" );
            }

            // Set Play mode to Qi4j mode
            assembly.setMode( mode );

            ApplicationDescriptor model = qi4j.applicationModelFactory().newApplicationModel( assembly );
            application = model.newInstance( qi4j.api() );
            application.activate();

            // Development tools
            if( mode == Mode.development )
            {
                if( envisage )
                {
                    envisageInstance = ( Envisage ) classloader.loadClass( Envisage.class.getName() ).newInstance();
                    envisageInstance.run( model );
                }
                if( entityViewer )
                {
                    entityViewerInstance = ( EntityViewer ) classloader.loadClass( EntityViewer.class.getName() ).newInstance();
                    entityViewerInstance.show( qi4j.spi(), model, application );
                }
            }

            if( controllersLayerName != null && controllersModuleName != null )
            {
                for( String pkg : controllersPackages.split( ":" ) )
                {
                    Class[] classes = Helper.getClasses( pkg, classloader );
                    for( Class clazz : classes )
                    {
                        eventuallyInjectStatic( clazz, controllersLayerName, controllersModuleName );
                    }
                }
            }

            play.Logger.debug( "Qi4jPlugin started!" );

        }
        catch( ClassNotFoundException ex )
        {
            throw new PlayQiException( "Unable to find Qi4j ApplicationAssembler: " + ex.getMessage(), ex );
        }
        catch( ClassCastException ex )
        {
            throw new PlayQiException( appAssClassName + " is not a Qi4j ApplicationAssembler: " + ex.getMessage(), ex );
        }
        catch( InstantiationException ex )
        {
            throw new PlayQiException( "Unable to instanciate " + appAssClassName + ": " + ex.getMessage(), ex );
        }
        catch( IllegalAccessException ex )
        {
            throw new PlayQiException( "Unable to instanciate " + appAssClassName + ": " + ex.getMessage(), ex );
        }
        catch( AssemblyException ex )
        {
            throw new PlayQiException( "Unable to assemble Qi4j Application: " + ex.getMessage(), ex );
        }
        catch( Exception ex )
        {
            throw new PlayQiException( "Unable to activate Qi4j Application: " + ex.getMessage(), ex );
        }
        finally
        {
            Thread.currentThread().setContextClassLoader( originalClassloader );
        }
    }

    private void eventuallyInjectStatic( Class clazz, String controllersLayerName, String controllersModuleName )
    {
        // QUID What about Scala support?
        Layer controllersLayer = application.findLayer( controllersLayerName );
        Module controllersModule = application.findModule( controllersLayerName, controllersModuleName );
        try
        {
            for( Field field : clazz.getDeclaredFields() )
            {
                if( Modifier.isStatic( field.getModifiers() ) )
                {
                    if( field.isAnnotationPresent( Structure.class ) )
                    {
                        if( field.getType().isAssignableFrom( Qi4jSPI.class )
                            || field.getType().isAssignableFrom( Qi4j.class ) )
                        {
                            inject( field, qi4j );
                        }
                        else
                        {
                            if( field.getType().isAssignableFrom( Application.class ) )
                            {
                                inject( field, application );
                            }
                            else
                            {
                                if( field.getType().isAssignableFrom( Layer.class ) )
                                {
                                    inject( field, controllersLayer );
                                }
                                else
                                {
                                    if( field.getType().isAssignableFrom( Module.class )
                                        || field.getType().isAssignableFrom( TransientBuilderFactory.class )
                                        || field.getType().isAssignableFrom( UnitOfWorkFactory.class )
                                        || field.getType().isAssignableFrom( ServiceFinder.class ) )
                                    {
                                        inject( field, controllersModule );
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if( field.isAnnotationPresent( Service.class ) )
                        {
                            if( field.getType().isAssignableFrom( Iterable.class ) )
                            {
                                inject( field, controllersModule.findServices( field.getType() ) );
                            }
                            else
                            {
                                if( field.getType().isAssignableFrom( ServiceReference.class ) )
                                {
                                    inject( field, controllersModule.findService( field.getType() ) );
                                }
                                else
                                {
                                    inject( field, controllersModule.findService( field.getType() ).get() );
                                }
                            }
                        }
                    }
                }
            }
        }
        catch( Exception ex )
        {
            throw new PlayQiException( "Unable to inject from '" + controllersLayerName + "/" + controllersModuleName
                                       + "' to '" + clazz.getName() + "': " + ex.getMessage(), ex );
        }
    }

    private void inject( Field field, Object value )
            throws IllegalArgumentException, IllegalAccessException
    {
        field.setAccessible( true );
        field.set( null, value );
    }

    @Override
    public void onStop()
    {
        super.onStop();
        if( envisageInstance != null )
        {
            envisageInstance.stop();
        }
        if( entityViewerInstance != null )
        {
            entityViewerInstance.stop();
        }
        try
        {
            if( application != null )
            {
                application.passivate();
            }
        }
        catch( Exception ex )
        {
            play.Logger.warn( "An exception occured during Qi4j Application passivation: " + ex.getMessage(), ex );
        }
        finally
        {
            application = null;
            qi4j = null;
        }
        play.Logger.debug( "Qi4jPlugin stopped!" );
    }

    @Override
    public boolean enabled()
    {
        return play2app.configuration().getString( CONFIG_APP_ASSEMBLER ) != null;
    }

}
TOP

Related Classes of org.codeartisans.playqi.PlayQiPlugin

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.