/* * ome.formats.enums.IQueryEnumProvider * *------------------------------------------------------------------------------ * Copyright (C) 2006-2008 University of Dundee. All rights reserved. * * * 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 2 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package ome.formats.enums; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import omero.RLong; import omero.RString; import omero.ServerError; import omero.api.IQueryPrx; import ome.formats.enums.handler.EnumHandlerFactory; import ome.formats.enums.handler.EnumerationHandler; import omero.model.IObject; /** * An enumeration provider which uses IQuery and a cache to fulfill the * contract of an EnumerationProvider. * * @author Chris Allan <callan at blackcat dot ca> * */ public class IQueryEnumProvider implements EnumerationProvider { /** Logger for this class. */ private static Logger log = LoggerFactory.getLogger(IQueryEnumProvider.class); /** Enumeration cache. */ private Map<Class<? extends IObject>, HashMap<String, IObject>> enumCache = new HashMap<Class<? extends IObject>, HashMap<String, IObject>>(); /** Query service. */ private IQueryPrx iQuery; /** Enumeration handler factory. */ private EnumHandlerFactory enumHandlerFactory = new EnumHandlerFactory(); /** * Default IQuery based enumeration provider constructor. * @param iQuery OMERO query service to use for enumeration lookups. */ public IQueryEnumProvider(IQueryPrx iQuery) { this.iQuery = iQuery; } /** * Creates an unloaded copy of an enumeration object. * @param enumeration Enumeration to copy. * @return See above. */ private IObject copyEnumeration(IObject enumeration) { Class<? extends IObject> klass = enumeration.getClass(); try { Constructor<? extends IObject> constructor = klass.getDeclaredConstructor( new Class[] { RLong.class, boolean.class }); return (IObject) constructor.newInstance( new Object[] { enumeration.getId(), false }); } catch (Exception e) { String m = "Unable to copy enumeration: " + enumeration; log.error(m, e); throw new EnumerationException(m, klass, getValue(enumeration)); } } private String getValue(IObject enumeration) { Class<? extends IObject> klass = enumeration.getClass(); try { Method method = klass.getMethod("getValue"); RString value = (RString) method.invoke(enumeration); return value.getValue(); } catch (Exception e) { String m = "Unable to get value of enumeration: " + enumeration; log.error(m, e); throw new EnumerationException(m, klass, ""); } } /* (non-Javadoc) * @see ome.formats.enums.EnumerationProvider#getEnumeration(java.lang.Class, java.lang.String, boolean) */ public <T extends IObject> T getEnumeration(Class<T> klass, String value, boolean loaded) { if (klass == null) throw new NullPointerException("Expecting not-null klass."); if (value == null) { log.warn("Enumeration " + klass + " with value of null."); } else if (value.length() == 0) { log.warn("Enumeration " + klass + " with value of zero length."); } HashMap<String, T> enumerations = getEnumerations(klass); EnumerationHandler handler = enumHandlerFactory.getHandler(klass); IObject otherEnumeration = enumerations.get("Other"); // Step 1, check if we've got an exact match for our enumeration value. if (enumerations.containsKey(value)) { log.debug(String.format("Returning %s exact match for: %s", klass.toString(), value)); if (!loaded) { return (T) copyEnumeration(enumerations.get(value)); } return enumerations.get(value); } // Step 2, check if our enumeration handler can find a match. IObject enumeration = handler.findEnumeration((HashMap<String, IObject>) enumerations, value); if (enumeration != null) { log.debug(String.format("Handler found %s match for: %s", klass.toString(), value)); if (!loaded) { return (T) copyEnumeration(enumeration); } return (T) enumeration; } // Step 3, fall through to an "Other" enumeration if we have one. if (otherEnumeration != null) { log.warn("Enumeration '" + value + "' does not exist in '" + klass + "' setting to 'Other'"); return (T) otherEnumeration; } // Step 4, warn we have no enumeration to return. log.warn("Enumeration '" + value + "' does not exist in '" + klass + "' returning 'null'"); return (T) enumeration; } /* (non-Javadoc) * @see ome.formats.enums.EnumerationProvider#getEnumerations(java.lang.Class) */ public <T extends IObject> HashMap<String, T> getEnumerations(Class<T> klass) { if (!enumCache.containsKey(klass)) { List<IObject> enumerationList; try { enumerationList = (List<IObject>) iQuery.findAll(klass.getName(), null); } catch (ServerError e) { throw new RuntimeException(e); } if (enumerationList == null) throw new EnumerationException("Problem finding enumeration: ", klass, null); HashMap<String, IObject> enumerations = new HashMap<String, IObject>(); for (IObject enumeration : enumerationList) { enumerations.put(getValue(enumeration), enumeration); } enumCache.put(klass, enumerations); } return (HashMap<String, T>) enumCache.get(klass); } }