package org.openbel.framework.common.index; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.Reader; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.Attribute; import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.openbel.framework.common.InvalidArgument; /** * ResourceIndex defines a singleton instance to hold an {@link Index}. * * <p> * An {@link Index} must first be loaded by calling {@link #loadIndex(Index)} * before trying to access it. Accessing an index before it has been loaded * or trying to load a subsequent index will trigger a * {@link IllegalStateException}. * </p> * * @author Anthony Bargnesi <abargnesi@selventa.com> */ public enum ResourceIndex { INSTANCE; private final String ANNOTATION_DEFINITION_ELEMENT = "annotationdefinition"; private final String NAMESPACE_ELEMENT = "namespace"; private final String EQUIVALENCE_ELEMENT = "equivalence"; private final String RESOURCE_LOCATION_ATTR = "resourceLocation"; private final String NAMESPACE_REF = "namespace-ref"; private final String PROTEIN_FAMILIES = "protein-families"; private final String NAMED_COMPLEXES = "named-complexes"; private final String GENE_SCAFFOLDING = "gene-scaffolding"; private final String ORTHOLOGY = "orthology"; /** * The resource {@link Index} instance which will be assigned only once. */ private Index index; /** * Private constructor to prevent direct instantiation. */ private ResourceIndex() { } /** * Loads a default {@link Index} with empty resources. * * <p> * See {@link #loadIndex(File)} in order to load the {@link Index} from an * index file. * </p> * * @throws IllegalStateException Thrown if the <tt>index</tt> has already * been loaded */ public synchronized void loadIndex() { if(this.index != null) { throw new IllegalStateException("index already initialized"); } this.index = new Index(new ArrayList<ResourceLocation>(), new ArrayList<ResourceLocation>(), new ArrayList<Equivalence>(), null, null, null, null); } /** * Loads the {@link Index} instance once. * * <p> * Subsequent attempts to load an index will trigger an * {@link IllegalStateException}. * </p> * * @param indexFile {@link File}, the index xml file to load which cannot * be null * @throws XMLStreamException Thrown if there was an xml processing error * when parsing the index file * @throws FileNotFoundException Thrown if the indexFile {@link File} * resource could not be found for reading * @throws IllegalStateException Thrown if the <tt>index</tt> has already * been loaded * @throws InvalidArgument Thrown if the <tt>indexFile</tt> to load the * index from is null. */ public synchronized void loadIndex(File indexFile) throws FileNotFoundException, XMLStreamException { if(this.index != null) { throw new IllegalStateException("index already initialized"); } if(indexFile == null) { throw new InvalidArgument("indexFile", indexFile); } this.index = load(indexFile); } /** * Returns the loaded {@link Index}. * * <p> * If the index has not be loaded then an {@link IllegalStateException} * will be thrown. * </p> * * @return {@link Index} the loaded index * @throws IllegalStateException Thrown if the index has not been loaded * by calling {@link #loadIndex(File)} */ public synchronized Index getIndex() { if (index == null) { throw new IllegalStateException( "ResourceIndex must be loaded first"); } return index; } /** * Determines if the {@link Index} has been loaded. * * @return the load status of {@link Index} */ public synchronized boolean isLoaded() { return index != null; } /** * Internal method to parse the index xml {@link File} to an {@link Index}. * * TODO We should validate the index file before the parsing. * * @param indexFile {@link File}, the index xml file * @return {@link Index} the index parsed from <tt>indexFile</tt> * @throws XMLStreamException Thrown if there was an xml processing error * when parsing the index file * @throws FileNotFoundException Thrown if the indexFile {@link File} * resource could not be found for reading */ private Index load(File indexFile) throws XMLStreamException, FileNotFoundException { XMLInputFactory factory = XMLInputFactory.newInstance(); Reader fileReader = new FileReader(indexFile); XMLEventReader reader = factory.createXMLEventReader(fileReader); final List<ResourceLocation> adResources = new ArrayList<ResourceLocation>(); final List<ResourceLocation> nsResources = new ArrayList<ResourceLocation>(); final List<Equivalence> eqResources = new ArrayList<Equivalence>(); ResourceLocation pfResource = null; ResourceLocation ncResource = null; ResourceLocation gsResource = null; Set<ResourceLocation> orthoResources = new LinkedHashSet<ResourceLocation>(); String eqResourceLocation = null; ResourceLocation namespaceRef = null; while(reader.hasNext()) { XMLEvent xev = reader.nextEvent(); if (xev.isStartElement()) { StartElement sel = (StartElement) xev; String elname = sel.getName().getLocalPart(); if (ANNOTATION_DEFINITION_ELEMENT.equals(elname)) { String rloc = findAttributeValue(RESOURCE_LOCATION_ATTR, sel); adResources.add(new ResourceLocation(rloc)); } else if (NAMESPACE_ELEMENT.equals(elname)) { String rloc = findAttributeValue(RESOURCE_LOCATION_ATTR, sel); nsResources.add(new ResourceLocation(rloc)); } else if (EQUIVALENCE_ELEMENT.equals(elname)) { eqResourceLocation = findAttributeValue(RESOURCE_LOCATION_ATTR, sel); } else if (NAMESPACE_REF.equals(elname)) { String rloc = findAttributeValue(RESOURCE_LOCATION_ATTR, sel); namespaceRef = new ResourceLocation(rloc); } else if (PROTEIN_FAMILIES.equals(elname)) { String rloc = findAttributeValue(RESOURCE_LOCATION_ATTR, sel); pfResource = new ResourceLocation(rloc); } else if (NAMED_COMPLEXES.equals(elname)) { String rloc = findAttributeValue(RESOURCE_LOCATION_ATTR, sel); ncResource = new ResourceLocation(rloc); } else if (GENE_SCAFFOLDING.equals(elname)) { String rloc = findAttributeValue(RESOURCE_LOCATION_ATTR, sel); gsResource = new ResourceLocation(rloc); } else if (ORTHOLOGY.equals(elname)) { String rloc = findAttributeValue(RESOURCE_LOCATION_ATTR, sel); orthoResources.add(new ResourceLocation(rloc)); } } else if (xev.isEndElement()) { EndElement eel = (EndElement) xev; String elname = eel.getName().getLocalPart(); if (EQUIVALENCE_ELEMENT.equals(elname)) { eqResources.add(new Equivalence(eqResourceLocation, namespaceRef)); } } } return new Index(adResources, nsResources, eqResources, pfResource, ncResource, gsResource, orthoResources); } private String findAttributeValue(String name, StartElement el) { if(name == null) { return null; } @SuppressWarnings("unchecked") Iterator<Attribute> attrIt = el.getAttributes(); while (attrIt.hasNext()) { Attribute attr = attrIt.next(); if(name.equals(attr.getName().getLocalPart())) { return attr.getValue(); } } return null; } }