/* * #%L * Bio-Formats autogen package for programmatically generating source code. * %% * Copyright (C) 2007 - 2015 Open Microscopy Environment: * - Board of Regents of the University of Wisconsin-Madison * - Glencoe Software, Inc. * - University of Dundee * %% * 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, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.StringTokenizer; import loci.common.IniList; import loci.common.IniParser; import loci.common.IniTable; import loci.common.ReflectException; import loci.common.ReflectedUniverse; import loci.formats.IFormatHandler; /** * An ugly data structure for organizing the status of each metadata property * for each format handler (readers and writers). * * @author Curtis Rueden ctrueden at wisc.edu */ public class MetaSupportList { // -- Constants -- /** Path to metadata groups definition file. */ public static final String GROUPS_SRC = "meta-groups.txt"; /** Path to supported metadata properties definition file. */ public static final String SUPPORT_SRC = "meta-support.txt"; public static final String YES = "Yes"; public static final String NO = "No"; public static final String PARTIAL = "Partial"; public static final String MISSING = "Missing"; // -- Fields -- /** List of all metadata properties. */ protected MetaEntityList entityList; /** List of groups. Key is group name, value is list of properties. */ protected HashMap<String, List<String>> groups = new HashMap<String, List<String>>(); /** * List of supported properties. Key is handler name (e.g., AVIReader), * value is a table mapping from properties to support tags * (YES, NO, PARTIAL or MISSING). */ protected HashMap<String, HashMap<String, String>> supported = new HashMap<String, HashMap<String, String>>(); protected HashMap<String, String> pagenames = new HashMap<String, String>(); /** Version of OME-XML (e.g., 2008-02). */ protected String version; /** Current handler (e.g., AVIReader). */ protected String handlerName; // -- Constructors -- /** Constructs an entity list. */ public MetaSupportList(String version) throws IOException { this(version, GROUPS_SRC, SUPPORT_SRC); } /** Constructs an entity list. */ public MetaSupportList(String version, String groupsPath, String supportPath) throws IOException { this.version = version; // parse metadata properties entityList = new MetaEntityList(); entityList.setVersion(version); // parse INI data IniParser parser = new IniParser(); IniList groupsList = parser.parseINI(groupsPath, MetaSupportList.class); IniList supportList = parser.parseINI(supportPath, MetaSupportList.class); // convert unprocessed INI-style config data into data structures // process list of groups HashMap<String, String> groupHash = groupsList.get(0); for (String groupName : groupHash.keySet()) { String propString = groupHash.get(groupName); StringTokenizer st = new StringTokenizer(propString, " "); List<String> propList = new ArrayList<String>(); while (st.hasMoreTokens()) { String prop = st.nextToken(); propList.add(prop); } Collections.sort(propList); groups.put(groupName, propList); } // process list of supported metadata properties for (HashMap<String, String> propHash : supportList) { String handler = propHash.get(IniTable.HEADER_KEY); propHash.remove(IniTable.HEADER_KEY); supported.put(handler, propHash); } } // -- MetaSupportList API methods -- /** Gets the list of entities associated with the data structure. */ public MetaEntityList entityList() { return entityList; } /** Gets the version of OME-XML to which entities should be linked. */ public String version() { return version; } /** Gets a list of all known handlers. */ public List<String> handlers() { List<String> handlers = new ArrayList<String>(); for (String handler : supported.keySet()) handlers.add(handler); Collections.sort(handlers); return handlers; } /** Sets the current handler (e.g., AVIReader). */ public void setHandler(String name) { handlerName = name; } /** Gets the current handler. */ public String handler() { return handlerName; } /** Gets the name of the format for the current handler. */ public String format() { ReflectedUniverse r = new ReflectedUniverse(); IFormatHandler handler; try { r.exec("import loci.formats.in." + handlerName); } catch (ReflectException exc) { } try { r.exec("import loci.formats.out." + handlerName); } catch (ReflectException exc) { } try { handler = (IFormatHandler) r.exec("new " + handlerName + "()"); return handler.getFormat(); } catch (ReflectException exc) { } return null; } /** Gets the type (reader or writer) for the current handler. */ public String handlerType() { ReflectedUniverse r = new ReflectedUniverse(); try { r.exec("import loci.formats.in." + handlerName); return "reader"; } catch (ReflectException exc) { } try { r.exec("import loci.formats.out." + handlerName); return "writer"; } catch (ReflectException exc) { } return "handler"; } /** Gets the documentation page name corresponding to this handler. */ public String getPageName() { return pagenames.get(handlerName); } /** Sets the documentation page name corresponding to this handler. */ public void setPageName(String pagename) { pagenames.put(handlerName, pagename); } /** Gets a list of all known groups. */ public List<String> groups() { List<String> groupList = new ArrayList<String>(); for (String group : groups.keySet()) groupList.add(group); Collections.sort(groupList); return groupList; } /** Gets the list of properties belonging to the given group. */ public List<String> groupMembers(String group) { return groups.get(group); } /** Gets all supported properties for the current handler. */ public List<String> yes() { return getSupportValue(YES); } /** Gets all unsupported properties for the current handler. */ public List<String> no() { return getSupportValue(NO); } /** Gets all partially supported properties for the current handler. */ public List<String> partial() { return getSupportValue(PARTIAL); } /** Gets all inapplicable properties for the current handler. */ public List<String> missing() { return getSupportValue(MISSING); } /** Gets the number of handlers that support the given property. */ public int yesHandlerCount(String entity, String prop) { return getHandlerCount(entity, prop, YES); } /** Gets the number of handlers that do not support the given property. */ public int noHandlerCount(String entity, String prop) { return getHandlerCount(entity, prop, NO); } /** Gets the number of handlers that partially support the given property. */ public int partialHandlerCount(String entity, String prop) { return getHandlerCount(entity, prop, PARTIAL); } /** * Gets the number of handlers for which the given property is inapplicable. */ public int missingHandlerCount(String entity, String prop) { return getHandlerCount(entity, prop, MISSING); } /** Extracts entity from a string of the form "Entity.Property comment". */ public String entity(String s) { int dot = s.indexOf("."); return s.substring(0, dot); } /** Extracts property from a string of the form "Entity.Property comment". */ public String prop(String s) { int dot = s.indexOf("."); int space = s.indexOf(" "); return space < 0 ? s.substring(dot + 1) : s.substring(dot + 1, space); } /** Extracts comment from a string of the form "Entity.Property comment". */ public String comment(String s) { int space = s.indexOf(" "); if (space < 0) return ""; return s.substring(space + 1).trim(); } /** Looks up the node type corresponding to the given entity. */ public String node(String entity) { entityList.setEntity(entity); return entityList.last(); } // -- Helper methods -- /** Gets properties with the given support value for the current handler. */ protected List<String> getSupportValue(String supportValue) { List<String> props = new ArrayList<String>(); // for this handler, get table mapping properties to support tags HashMap<String, String> supportProps = supported.get(handlerName); // flag whether we are looking for missing entries boolean missing = MISSING.equals(supportValue); // check every property against the table mapping for (String entity : entityList.entities()) { entityList.setEntity(entity); // check if this entity is set to this support value; // if so, this is a shortcut for all properties of that entity String entitySupportValue = supportProps.get(entity); String entitySince = null; int space = entitySupportValue == null ? -1 : entitySupportValue.indexOf(" "); if (space >= 0) { entitySince = entitySupportValue.substring(space).trim(); entitySupportValue = entitySupportValue.substring(0, space).trim(); } boolean all = supportValue.equals(entitySupportValue); // if we are looking for missing entries, mark if entity is missing boolean entityMissing = missing && entitySupportValue == null; for (String prop : entityList.props()) { // properties are listed with the convention "Entity.Property" String fqProp = entity + "." + prop; String propSupportValue = supportProps.get(fqProp); String comment = null; if (propSupportValue == null || // is there no property support value? // do entity and property support values match? (entitySupportValue != null && entitySupportValue.equals(propSupportValue))) { // set the property's default comment text to match the entity comment = entitySince; } space = propSupportValue == null ? -1 : propSupportValue.indexOf(" "); if (space >= 0) { comment = propSupportValue.substring(space).trim(); propSupportValue = propSupportValue.substring(0, space).trim(); } // property matches support value if it either matches directly, // or its parent entity matches globally and no override exists if (supportValue.equals(propSupportValue) || // direct match? // does parent entity match globally with no override? (all && propSupportValue == null) || // are we are looking for missing entries with a missing property? (entityMissing && propSupportValue == null)) { props.add(comment == null ? fqProp : fqProp + " " + comment); } } } Collections.sort(props); return props; } /** * Gets the number of handlers that match the * given support value for the specified property. */ protected int getHandlerCount(String entity, String prop, String supportValue) { // properties are listed with the convention "Entity.Property" String fqProp = entity + "." + prop; boolean missing = MISSING.equals(supportValue); int handlerCount = 0; for (String handler : supported.keySet()) { HashMap<String, String> supportProps = supported.get(handler); String propSupportValue = supportProps.get(fqProp); if (propSupportValue != null) { int space = propSupportValue.indexOf(" "); if (space >= 0) propSupportValue = propSupportValue.substring(0, space); if (propSupportValue.equals(supportValue)) { // specific property matches desired support value handlerCount++; continue; } } // check if the entity is set to this support value; // if so, this is a shortcut for all properties of that entity String entitySupportValue = supportProps.get(entity); if (entitySupportValue != null) { int space = entitySupportValue.indexOf(" "); if (space >= 0) { entitySupportValue = entitySupportValue.substring(0, space); } if (entitySupportValue.equals(supportValue)) { // parent entity matches desired support value handlerCount++; continue; } } // check if property is missing and we are looking for missing entries if (propSupportValue == null && entitySupportValue == null && missing) { handlerCount++; continue; } } return handlerCount; } }