/* * This file is part of Alida, a Java library for * Advanced Library for Integrated Development of Data Analysis Applications. * * Copyright (C) 2010 - @YEAR@ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Fore more information on Alida, visit * * http://www.informatik.uni-halle.de/alida/ * */ /* * Most recent change(s): * * $Rev: 4370 $ * $Date: 2011/11/20 20:18:51 $ * $Author: posch $ * */ package de.unihalle.informatik.Alida.dataio; import de.unihalle.informatik.Alida.dataio.provider.ALDDataIO; import de.unihalle.informatik.Alida.dataio.provider.helpers.ALDParametrizedClassDummy; import de.unihalle.informatik.Alida.exceptions.ALDDataIOManagerException; import de.unihalle.informatik.Alida.exceptions.ALDDataIOManagerException.ALDDataIOManagerExceptionType; import de.unihalle.informatik.Alida.operator.ALDOperator; import de.unihalle.informatik.Alida.annotations.ALDAOperator; import de.unihalle.informatik.Alida.annotations.ALDDataIOProvider; import de.unihalle.informatik.Alida.annotations.ALDParametrizedClass; import de.unihalle.informatik.Alida.annotations.ALDDerivedClass; import de.unihalle.informatik.Alida.annotations.indexing.SezPozAdapter; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Collection; import java.util.Vector; import java.util.LinkedList; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Field; import java.lang.annotation.Annotation; import net.java.sezpoz.Index; import net.java.sezpoz.IndexItem; /** * Class to manage data input and output in Alida. * This is used, e.g., in Alida's mechanism to automaticaly generate user interfaces for * Alida operators. * This abstract class provides means to find a DataIO provider object for a given class. * DataIO provider classes need to be annotated with {@link ALDDataIOProvider} and are expected to * implement an interface which is derived from the interface {@link ALDDataIO}. * <p> * Each non-abstract class extending ALDDataIOManager will typically come in pair * with an interface which extends ALDDataIO. * The class extending ALDDataIOManager defines methods to read and write data * which are delegated to the corresponding corresponding classes defined in the pairing interface * and thus have to be defined there. * <p> * * @author moeller,posch * @see ALDDataIO * */ public abstract class ALDDataIOManager { /** * For internal debugging purposes */ protected static boolean debug = false; /** * Name of the method which returns all classes supported by a DataIO provider class. * This method is declared by the interface {@link ALDDataIO} and thus to be implemented * by each DataIO provider class. */ private static String providedClassesMethodName = "providedClasses"; /** * Hashtable containing mappings of datatypes to DataIO provider classes. * This is initialized using indices generated via the @ALDDataIOProvider annotation, * see <code>initMapTable()</code>. * The dataIO provider is specified with its full class name. */ protected HashMap<Class, String> mapTable = null; /** * Default constructor. */ protected ALDDataIOManager() { //nothing to do here to be overridden in extending classes } /** * Method to initialize the hashmap which registers DataIO providers. * Looking up DataIO providers is facilitated with annotions of type {@link ALDDataIO}, i.e. * a DataIO provider will only be found and registerd, if it is annotated with @ALDDataIO. * In addition it has to implement the interface <code>interfaceRequired</code>. * * @param interfaceRequired Interface which all providers registered are to implement. * Is has to be derived from <code>ALDDataIO</code>. */ protected static HashMap<Class, String> initMapTable( Class interfaceRequired ) { HashMap<Class, String> mapTable = new HashMap<Class, String>(); // this a parallel map to mapTable, which represents the priority of the provider class as define // by the annotation of the DataIO provider. // for use only during initialization of the mapTable HashMap<Class, Integer> priorityMap = new HashMap<Class, Integer>(); Index<ALDDataIOProvider,ALDDataIO> indexItems = SezPozAdapter.load(ALDDataIOProvider.class,ALDDataIO.class); for ( final IndexItem<ALDDataIOProvider,ALDDataIO> item : indexItems ) { // class name of DataIO provider String className = item.className(); // and its priority int priority = item.annotation().priority(); if ( debug ) System.out.println( "found: " + className); try { if ( ! interfaceRequired.isAssignableFrom( Class.forName( className)) ) { if ( debug ) System.out.println( " is not assignable from " + interfaceRequired); } else { Class params[] = {}; Method method = Class.forName( className).getDeclaredMethod( providedClassesMethodName, params); ALDDataIO provider = (ALDDataIO)(Class.forName( className).newInstance()); Object paramsObj[] = {}; Collection<Class<?>> supportedClasses = (Collection<Class<?>>)(method.invoke( provider, paramsObj)); for ( Class supportedClass : supportedClasses ) { if ( ! mapTable.containsKey( supportedClass) || priority > priorityMap.get( supportedClass) ) { if ( debug ) System.out.println( " supported class (priority = " + priority + "):" + supportedClass.getName()); mapTable.put( supportedClass, className); priorityMap.put( supportedClass, priority); } } } } catch (Exception e) { System.err.println( "ALDDataIOManager::initMapTable cannot create an instance for " + className); } } return mapTable; } /** * Method to return an instance of the DataIO provider class for the class <code>cl</code> * which implements the requested interface <code>interfaceRequired</code> * (which has itself to implement ALDDataIO). * <p> * There are the following extensions if no DataIO provider for class <code>cl</code> is found. * If <code>cl</code> is an enumeration class, a provider for Enum.class is returned (if found). * If <code>cl</code> is an ALDOperator class, a provider for ALDOperator.class is returned (if found). * If <code>cl</code> is an array, a provider for Array.class is returned (if found). * If <code>cl</code> is a Collection, a provider for Collection.class is returned (if found). * If <code>cl</code> is annotated as a parametrized class via {@link ALDParametrizedClass}, * a provider for {@link ALDParametrizedClassDummy} is returned (if found). * * @param cl class to get an provider for * @param interfaceRequired interface needed to be implemented by the provider * @return provider instance * @throws ALDDataIOManagerException */ public ALDDataIO getProvider( Class cl, Class interfaceRequired) throws ALDDataIOManagerException { if ( debug) { System.out.println("ALDDataIOManager::getProvider find provider for <" + cl.getName() + ">"); } // first look up a provider name String providerName; providerName = mapTable.get(cl); if ( providerName == null) { // try other means to find a provider // enum or ALDOperator or Collection or ALDParametrizedClass if ( ! ( ( cl.getEnumConstants() != null && (providerName = mapTable.get( Enum.class)) != null ) || ( ALDOperator.class.isAssignableFrom( cl) && (providerName = mapTable.get( ALDOperator.class)) != null ) || ( cl.isArray() && (providerName = mapTable.get( Array.class)) != null ) || ( Collection.class.isAssignableFrom( cl) && (providerName = mapTable.get( Collection.class)) != null ) || ( cl.getAnnotation( ALDParametrizedClass.class) != null && (providerName = mapTable.get( ALDParametrizedClassDummy.class)) != null ) ) ) { // nothing found throw new ALDDataIOManagerException( ALDDataIOManagerExceptionType.NO_PROVIDER_FOUND, "ALDDataIOManager::getProvider no provider found for class " + cl.getName()); } } if ( debug) { System.out.println("ALDDataIOManager::getProvider found <" + providerName + ">"); } // try to instantiate an instance of the provider Class<?> providerClass = null; try { providerClass = Class.forName( providerName); } catch (ClassNotFoundException e1) { throw new ALDDataIOManagerException( ALDDataIOManagerExceptionType.UNSPECIFIED_ERROR, "ALDDataIOManager::getProvider cannnot find a class for annotated provider <" + providerName + "> found for class " + cl.getName() +">"); } Object providerInstance = null; try { providerInstance = providerClass.newInstance(); } catch (Exception e) { throw new ALDDataIOManagerException( ALDDataIOManagerExceptionType.UNSPECIFIED_ERROR, "ALDDataIOManager::getProvider cannnot instantiate annotated provider <" + providerName + "> found for class " + cl.getName() +">"); } // check if provider is of correct type if ( ! interfaceRequired.isAssignableFrom( providerClass ) ) { throw new ALDDataIOManagerException( ALDDataIOManagerExceptionType.NO_PROVIDER_FOUND, "ALDDataIOManager::getProvider provider found for class " + cl.getName() + "does not implement <" + interfaceRequired.getName() +">"); } return (ALDDataIO)providerInstance; } /** * Method to return a clone of the mapping of classes to dataIO providers. * This method will typically used only be admin tools. * The dataIO provider is specified with its full class name. */ public HashMap<Class, String> getProviderMap() { return (HashMap<Class, String>)(mapTable.clone()); } }