📄 loaderimpl.java
字号:
package org.xbrlapi.loader;import java.io.File;import java.io.IOException;import java.io.StringReader;import java.net.MalformedURLException;import java.net.URI;import java.net.URISyntaxException;import java.net.URL;import java.util.EmptyStackException;import java.util.HashMap;import java.util.LinkedList;import java.util.List;import java.util.Stack;import java.util.Vector;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.apache.log4j.Logger;import org.xbrlapi.Fragment;import org.xbrlapi.SAXHandlers.ContentHandlerImpl;import org.xbrlapi.SAXHandlers.ElementState;import org.xbrlapi.cache.CacheImpl;import org.xbrlapi.data.Store;import org.xbrlapi.utilities.Constants;import org.xbrlapi.utilities.XBRLException;import org.xbrlapi.xlink.XLinkProcessor;import org.xbrlapi.xpointer.resolver.PointerResolver;import org.xbrlapi.xpointer.resolver.PointerResolverImpl;import org.xml.sax.ContentHandler;import org.xml.sax.EntityResolver;import org.xml.sax.ErrorHandler;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import org.xml.sax.SAXNotRecognizedException;import org.xml.sax.SAXNotSupportedException;import org.xml.sax.XMLReader;/** * Implementation of the XBRL API Loader interface. The loader is responsible * for managing the DTS discovery process. It manages the queue of documents to * be explored; it provides the XLink Processor that is used to process the * links within the documents being explored; and it directs the DTS information * to the supplied data store. The loader is also responsible for triggering * creation of the XBRL fragments that get placed into the data store. * * @author Geoffrey Shuetrim (geoff@galexy.net) */public class LoaderImpl implements Loader { // Create the logger static Logger logger = Logger.getLogger(Loader.class); /** * The data store to be used to hold the DTS. */ private Store store; /** * The stack of fragments that are being built */ private Stack<Fragment> fragments = new Stack<Fragment>(); /** * The stack of fragment depths used to decide when a fragment has been * fully built. Each time a new fragment is created, record the depth of its * root element in the stack of depths maintained by the loader. */ private Stack<Long> depths = new Stack<Long>(); /** * The cache to use when discovering XML materials specified as a String * rather than just via a URL that resolves to the required XML. */ private CacheImpl cache = null; /** * @see org.xbrlapi.loader.Loader#setCache(CacheImpl) */ public void setCache(CacheImpl cache) { this.cache = cache; } /** * @see org.xbrlapi.loader.Loader#getCache() */ public CacheImpl getCache() throws XBRLException { if (this.cache == null) throw new XBRLException( "The loader cache is null and so cannot be used."); return this.cache; } /** * The absolute URL of the document currently being parsed. Used to record * this metadata in each fragment. */ private String documentURL = null; /** * The document Id (including the document hash and its counter) */ private String documentId = null; /** * Stack of vectors used to track children. */ private Stack<Vector<Long>> childrenStack = new Stack<Vector<Long>>(); /** * Boolean to flag if the element that has just been found by the parser has * triggered the creation of a fragment. */ private boolean newFragmentAdded = false; /** * The Xlink processor */ private XLinkProcessor xlinkProcessor; /** * The entity resolver to use for resolution of entities (URLs etc) during * the loading/discovery process */ private EntityResolver entityResolver; /** * The XPointer resolver */ private PointerResolver pointerResolver; /** * The map of documents awaiting loading into the DTS. This queue is * implemented as a hash map to ensure that the keys (URLS in string form) * eliminate multiple discoveries of the same document. The value for each * URL is set to false initially and is changed to true when the document * has been loaded. */ private HashMap<String, Integer> documentQueue = new HashMap<String, Integer>(); /** * The unique fragment ID, that will be one for the first fragment. This is * incremented just before as it is retrieved for use with a new fragment * created during the loading process. */ private int fragmentId = 0; /** * discovering equals false if the loader is not presently doing document * discovery and true otherwise. */ private boolean discovering = false; private void setDiscovering(boolean value) { if (value) logger.debug(Thread.currentThread().getName() + " starting discovery."); else logger.debug(Thread.currentThread().getName() + " stopping discovery."); discovering = value; } private boolean isDiscovering() { return discovering; } private boolean interrupt = false; /** * Interrupts the loading process once the current * document discovery has been completed. * This can be useful when the loader is shared among * several threads. */ public void requestInterrupt() { logger.info("An interrupt has been requested."); interrupt = true; } /** * @return true if an interrupt to the loading process * has been requested and false otherwise. */ private boolean interruptRequested() { List<String> documents = this.getDocumentsStillToAnalyse(); return interrupt; } /** * @see org.xbrlapi.loader.Loader#cancelInterrupt() */ public void cancelInterrupt() { interrupt = false; logger.info("Cancelled the discovery interrupt."); } /** * Contruct the loader passing in the data store and the XLink processor to * be used. * * @param store * The data store to hold the DTS * @param xlinkProcessor * The XLink processor to use for link resolution * @throws XBRLException * if the loader cannot be instantiated. */ public LoaderImpl(Store store, XLinkProcessor xlinkProcessor) throws XBRLException { super(); if (store == null) { throw new XBRLException("The data store must not be null."); } this.store = store; if (xlinkProcessor == null) { throw new XBRLException("The XLink processor must not be null."); } this.xlinkProcessor = xlinkProcessor; // Set the XPointer resolver for this document this.setPointerResolver(new PointerResolverImpl(this.getStore())); try { this.stashURL(new URL(Constants.ROLES_URL)); } catch (MalformedURLException e) { throw new XBRLException("The XBRL 2.1 roles URL is malformed: " + Constants.ROLES_URL, e); } } /** * Create a loader with a set of URLs of starting points to seed the * discovery process. * * @param store * The data store to hold the DTS * @param xlinkProcessor * The XLink processor to use for link resolution * @param urls * The array of URLs for loading * @throws XBRLException * if the loader cannot be instantiated. */ public LoaderImpl(Store store, XLinkProcessor xlinkProcessor, List<URL> urls) throws XBRLException { this(store, xlinkProcessor); setStartingURLs(urls); } /** * Create a loader supplying a file location of a serialised set of * documents to seed the discovery process. TODO Move the loader constructor * that uses a serialised set of documents to a separate class * * @param store * The data store to hold the DTS * @param xlinkProcessor * The XLink processor to use for link resolution * @param file * The file location of the serialised DTS to load * @throws XBRLException * if the loader cannot be instantiated. */ public LoaderImpl(Store store, XLinkProcessor xlinkProcessor, File file) throws XBRLException { this(store, xlinkProcessor); throw new XBRLException( "Still to implement loading a serialised data set."); } /** * Set the data store to be used by the loader TODO Decide if the loader * setStore method should be private or public */ private void setStore(Store store) { this.store = store; } /** * Get the data store used by a loader TODO should the loader getStore * method be public or private */ public Store getStore() { return store; } /** * Set the URL of the document now being parsed. * * @param url * The URL of the document now being parsed. * @throws XBRLException. */ private void setDocumentURL(String url) throws XBRLException { this.documentURL = url; this.documentId = getStore().getDocumentId(url.toString()); } /** * @return the document ID for the document being analysed or * null if no document is being analysed. */ private String getDocumentId() { return documentId; } /** * Get the URL for the document being parsed. * * @return The original (non-cache) URL of the document being parsed. */ public String getDocumentURL() { return this.documentURL; } /** * Set the XLink processor used by the loader. TODO Should the setter for * the loader Xlink Processor be public? */ private void setXlinkProcessor(XLinkProcessor xlinkProcessor) { this.xlinkProcessor = xlinkProcessor; } /** * Get the Xlink processor used by the loader. TODO Should the getter for * the loader Xlink Processor be public? */ public XLinkProcessor getXlinkProcessor() { return xlinkProcessor; } /** * Set the XPointer resolver. * * @param pointerResolver * The XPointer resolver implementation. */ private void setPointerResolver(PointerResolver pointerResolver) { this.pointerResolver = pointerResolver; } /** * Get the XPointer resolver. * * @return The XPointer resolver used by the loader. */ private PointerResolver getPointerResolver() { return pointerResolver; } /** * We need to track the number of children for all of the elements being * built for all of the fragments being built. This is required to enable us * to build an XPath expression identifying the element of a parent fragment * that is to contain the root of a child fragment. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -