/* * Copyright 2008-${YEAR} Zuse Institute Berlin (ZIB) * * 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 de.zib.gndms.infra.system; import de.zib.gndms.logic.model.gorfx.taskflow.TaskFlowFactory; import de.zib.gndms.logic.model.gorfx.taskflow.TaskFlowProviderImpl; import de.zib.gndms.neomodel.common.Session; import de.zib.gndms.stuff.GNDMSInjector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ReflectionUtils; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; /** * @author try ma ik jo rr a zib * @date 27.06.11 18:38 * @brief */ public class PluggableTaskFlowProvider extends TaskFlowProviderImpl { protected final Logger logger = LoggerFactory.getLogger( this.getClass() ); private String pluginDir; private boolean hasFactories = false; private GNDMSystem system; private ClassLoader cl; public void loadPlugins( boolean checkDeps ) { Map<String, TaskFlowFactory> plugins = new HashMap<String, TaskFlowFactory>( 10 ); ServiceLoader<TaskFlowFactory> sl; if( getCl() != null ) sl = ServiceLoader.load( TaskFlowFactory.class, getCl() ); else sl = ServiceLoader.load( TaskFlowFactory.class ); for( TaskFlowFactory bp : sl ) { try { register( bp, plugins ); } catch ( IllegalStateException e ) { logger.warn( e.getMessage() ); } } setFactories( plugins ); if( checkDeps ) checkDeps(); // call all PostConstruct methods for( TaskFlowFactory bp : sl ) { for( Method method : bp.getClass().getDeclaredMethods() ) { if (method.getAnnotation( PostConstruct.class ) != null) { ReflectionUtils.makeAccessible( method ); try { method.invoke( bp, ( Object[] )null ); } catch( IllegalAccessException e ) { throw new RuntimeException( "THIS IS NOT HAPPENING!!! Method had been made accessible but is not accessible anyway", e ); } catch( InvocationTargetException e ) { throw new RuntimeException( "Could not call PostConstruct method (" + method.toGenericString() + ")", e ); } } } } // todo this is just for development change this for releases: // if ( getFactories().size() == 0 ) // throw new IllegalStateException( "no plugs found" ); } @PostConstruct public void loadPlugins( ) { PluginLoader pl = new PluginLoader( pluginDir ); try { ClassLoader cl = pl.loadPlugins(); setCl( cl ); loadPlugins( true ); } catch ( Exception e ) { throw new RuntimeException( e ); } } @PreDestroy public void destroyPlugins( ) { final Map< String, TaskFlowFactory > factories = getFactories(); for( TaskFlowFactory factory: factories.values() ) { for( Method method : factory.getClass().getDeclaredMethods() ) { if (method.getAnnotation( PreDestroy.class ) != null) { ReflectionUtils.makeAccessible( method ); try { method.invoke( factory, ( Object[] )null ); } catch( IllegalAccessException e ) { throw new RuntimeException( "THIS IS NOT HAPPENING!!! Method had been made accessible but is not accessible anyway", e ); } catch( InvocationTargetException e ) { throw new RuntimeException( "Could not call PreDestroy method (" + method.toGenericString() + ")", e ); } } } } } public int pluginCount( ) { return getFactories().size(); } public void listPlugins( ) { Map<String, TaskFlowFactory> plugins = getFactories(); for ( String k : plugins.keySet() ){ logger.debug( k + ": " + plugins.get( k ).getVersion() + " class: " + plugins.get( k ).getClass().getName() ); } } public void register( TaskFlowFactory tff, Map<String, TaskFlowFactory> plugins ) { if( plugins.containsKey( tff.getTaskFlowKey() ) ) throw new IllegalStateException( "plugin " + tff.getTaskFlowKey() +" already exists" ); logger.debug( "registering factory: " + tff.getTaskFlowKey() ); plugins.put( tff.getTaskFlowKey(), tff ); final GNDMSInjector injector = system.getInstanceDir().getSystemAccessInjector(); injector.injectMembers( tff ); tff.setInjector( injector ); Session session = system.getDao().beginSession(); try { tff.registerType( session ); session.success(); } finally { session.finish(); } } public void checkDeps( ) { Map<String, TaskFlowFactory> plugins = getFactories(); List<String> missing = new ArrayList<String>(); for( String k : plugins.keySet() ) { TaskFlowFactory<?,?> tff = plugins.get( k ); for( String dep : tff.depends( ) ) { if(! plugins.containsKey( dep ) ) missing.add( dep ); } } if( missing.size() != 0 ) { StringBuilder mes = new StringBuilder(); mes.append( "Missing plugin dependencies detected:" ); for ( String k : missing ) { mes.append( '\n' ); mes.append( k ); } logger.warn( mes.toString() ); } } @Override public void setFactories( Map<String, TaskFlowFactory> factories ) { if ( hasFactories ) throw new IllegalStateException( "factories are already set" ); hasFactories = true; super.setFactories( factories ); // overriden method implementation } public GNDMSystem getSystem() { return system; } public void setSystem( final GNDMSystem system ) { this.system = system; } public ClassLoader getCl() { return cl; } public void setCl( final ClassLoader cl ) { this.cl = cl; } public String getPluginDir() { return pluginDir; } public void setPluginDir( final String pluginDir ) { this.pluginDir = pluginDir; } }