Author: vgritsenko Date: Wed Aug 22 17:40:57 2007 New Revision: 568786 URL: http://svn.apache.org/viewvc?rev=568786&view=rev Log: implemented support for read only symbol tables. refactor collection to take advantage of that. catch read only exception, propagate as appropriate. javadoc.
Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java xml/xindice/trunk/java/src/org/apache/xindice/core/SystemCollection.java xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java xml/xindice/trunk/java/src/org/apache/xindice/xml/SymbolTable.java xml/xindice/trunk/java/src/org/apache/xindice/xml/dom/DOMCompressor.java xml/xindice/trunk/java/tests/src/org/apache/xindice/xml/SymbolTableTest.java Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java?rev=568786&r1=568785&r2=568786&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java Wed Aug 22 17:40:57 2007 @@ -218,7 +218,6 @@ private String oidTemplate; private long documentId; - private boolean internalSymbols; private SymbolTable symbols; private File collectionRoot; @@ -296,6 +295,7 @@ * * @param config The Indexer's configuration * @return The newly created Indexer + * @throws DBException if operation failed */ public final Indexer createIndexer(Configuration config) throws DBException { checkFiler(FaultCodes.COL_NO_INDEXMANAGER); @@ -380,7 +380,7 @@ getCollectionRoot().delete(); // Drop symbols - if (!internalSymbols) { + if (!symbols.isReadOnly()) { getSystemCollection().dropSymbols(this); } @@ -389,7 +389,7 @@ } /** - * @see org.apache.xindice.core.CollectionManager#dropCollection(org.apache.xindice.core.Collection) + * @see CollectionManager#dropCollection(Collection) */ public final boolean dropCollection(Collection collection) throws DBException { boolean success = super.dropCollection(collection); @@ -403,6 +403,7 @@ * * @param index The Indexer to drop * @return Whether or not the Indexer was dropped + * @throws DBException if operation failed */ public final boolean dropIndexer(Indexer index) throws DBException { checkFiler(FaultCodes.COL_NO_INDEXMANAGER); @@ -425,10 +426,10 @@ } /** - * @throws DBException + * @throws DBException if operation failed */ public final void flushSymbolTable() throws DBException { - if (symbols.isDirty() && !internalSymbols) { + if (symbols.isDirty()) { getSystemCollection().saveSymbols(this, symbols); } } @@ -516,6 +517,7 @@ * returned will be null. * * @return MetaData this collection's metadata. + * @throws DBException if operation failed */ public MetaData getCollectionMeta() throws DBException { if (!isMetaEnabled()) { @@ -550,6 +552,7 @@ * * @param docKey The Document Key * @return The Container + * @throws DBException if operation failed */ public final Container getContainer(Object docKey) throws DBException { Key key = createNewKey(docKey); @@ -571,6 +574,7 @@ * * @param key The Document Key * @return The Document + * @throws DBException if operation failed */ public final Document getDocument(Object key) throws DBException { if (log.isDebugEnabled()) { @@ -596,6 +600,7 @@ * by this Collection. * * @return The Document count + * @throws DBException if operation failed */ public final long getDocumentCount() throws DBException { // a collection in which you are unable to file documents will have no filer @@ -606,9 +611,11 @@ /** * Return the MetaData object for a document within this collection. - * * If metadata is not enabled, the MetaData object returned will be null. + * * @param id the document whose metadata you want + * @return meta data for requested resource + * @throws DBException if operation failed */ public MetaData getDocumentMeta(String id) throws DBException { if (!isMetaEnabled()) { @@ -661,6 +668,7 @@ * by this Collection. * * @return The DocumentSet + * @throws DBException if operation failed */ public final DocumentSet getDocumentSet() throws DBException { // a collection in which you are unable to file documents will have no filer @@ -841,6 +849,7 @@ * * @param name The Indexer name * @return The Indexer (or null) + * @throws DBException if operation failed */ public final Indexer getIndexer(String name) throws DBException { checkFiler(FaultCodes.COL_NO_INDEXMANAGER); @@ -851,6 +860,7 @@ * return the IndexManager being used by this Collection. * * @return The IndexManager + * @throws DBException if operation failed */ public final IndexManager getIndexManager() throws DBException { checkFiler(FaultCodes.COL_NO_INDEXMANAGER); @@ -878,6 +888,7 @@ * * @param key The Document Key * @return an Castable XMLSerializable Instance + * @throws DBException if operation failed */ public final XMLSerializable getObject(Object key) throws DBException { if (log.isDebugEnabled()) { @@ -918,6 +929,7 @@ * Collection. * * @return The parent Collection (or null) + * @throws DBException if operation failed */ public final Collection getParentCollection() throws DBException { return parent; @@ -927,6 +939,7 @@ * getQueryEngine returns the Database's Query Engine * * @return The Query Engine + * @throws DBException if operation failed */ public QueryEngine getQueryEngine() throws DBException { return getDatabase().getQueryEngine(); @@ -972,6 +985,7 @@ * * @param docKey The document Key * @param bytes The document to insert + * @return key for the inserted binary * @throws DBException if inline-metadata is not enabled, the key is * already in the database, or an error occurs while saving. */ @@ -998,6 +1012,7 @@ * * @param document The Document * @return The new Object Identifier + * @throws DBException if operation failed */ public final Key insertDocument(Document document) throws DBException { return insertDocument(null, document); @@ -1008,6 +1023,8 @@ * * @param docKey The document Key * @param document The document to insert + * @return key for inserted document + * @throws DBException if operation failed */ public final Key insertDocument(Object docKey, Document document) throws DBException { Key key = createNewKey(docKey); @@ -1028,6 +1045,7 @@ * * @param obj The Object to insert * @return The newly generated Key + * @throws DBException if operation failed */ public final Key insertObject(XMLSerializable obj) throws DBException { return insertObject(null, obj); @@ -1040,6 +1058,8 @@ * * @param objKey The Key to use * @param obj The Object to insert + * @return key for the inserted object + * @throws DBException if operation failed */ public final Key insertObject(String objKey, XMLSerializable obj) throws DBException { Key key = createNewKey(objKey); @@ -1076,6 +1096,7 @@ * collection. * * @return the list of entry keys + * @throws DBException if operation failed */ public final String[] listDocuments() throws DBException { // a collection in which you are unable to file documents will have no filer @@ -1104,6 +1125,7 @@ * as an array of String. * * @return The Indexer list + * @throws DBException if operation failed */ public final String[] listIndexers() throws DBException { checkFiler(FaultCodes.COL_NO_INDEXMANAGER); @@ -1121,6 +1143,7 @@ * @param key The key to use when caching * @param xml The string to parse * @return A parsed DOM document or null if failure + * @throws DBException if operation failed */ private Document parseDocument(Key key, String xml) throws DBException { try { @@ -1350,6 +1373,7 @@ * @param query The query to execute * @param nsMap The namespace Map (if any) * @return The resulting NodeSet + * @throws DBException if operation failed */ public final NodeSet queryCollection(String style, String query, NamespaceMap nsMap) throws DBException { if (log.isDebugEnabled()) { @@ -1371,6 +1395,7 @@ * @param nsMap The namespace Map (if any) * @param key The Document to query * @return The resulting NodeSet + * @throws DBException if operation failed */ public final NodeSet queryDocument(String style, String query, NamespaceMap nsMap, Object key) throws DBException { if (log.isInfoEnabled()) { @@ -1392,6 +1417,7 @@ * regardless of it's type. * * @param key The Object's Key + * @throws DBException if operation failed */ public final void remove(Object key) throws DBException { if (log.isInfoEnabled()) { @@ -1445,7 +1471,9 @@ /** * Reset the metadata object for this collection. + * * @param meta the Metadata to use + * @throws DBException if operation failed */ public void setCollectionMeta(MetaData meta) throws DBException { if (!isMetaEnabled()) { @@ -1525,15 +1553,14 @@ // Symbol Table Setup Configuration symConfig = config.getChild(SYMBOLS); - internalSymbols = (symConfig != null); - if (internalSymbols) { + if (symConfig != null) { if (log.isTraceEnabled()) { log.trace(localDebugHeader + "Internal symbols=<" + TextWriter.toString(symConfig.getElement()) + ">"); } try { - symbols = new SymbolTable(symConfig.getElement()); + symbols = new SymbolTable(symConfig.getElement(), true); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn(localDebugHeader + "Error building symbol table from internal symbols", e); @@ -1600,6 +1627,7 @@ * * @param docKey The Document Key * @param document The Document + * @throws DBException if operation failed */ public final boolean setDocument(Object docKey, Document document) throws DBException { if (log.isInfoEnabled()) { @@ -1620,6 +1648,7 @@ * * @param docKey The document Key * @param bytes The document to insert + * @return true if new binary was created, false otherwise * @throws DBException if inline-metadata is not enabled, the key is * already in the database, or an error occurs while saving. */ @@ -1648,6 +1677,7 @@ * * @param id the document name * @param meta the metadata object to be used. + * @throws DBException if operation failed */ public void setDocumentMeta(String id, MetaData meta) throws DBException { if (!isMetaEnabled()) { @@ -1682,10 +1712,10 @@ } /** - * @param string + * @param name collection name */ - protected void setName(String string) { - name = string; + protected void setName(String name) { + this.name = name; } /** @@ -1695,6 +1725,7 @@ * * @param key The Key to use * @param obj The Object to set + * @throws DBException if operation failed */ public final void setObject(Object key, XMLSerializable obj) throws DBException { if (log.isInfoEnabled()) { @@ -1748,6 +1779,9 @@ /** * update the modified time of this document when appropriate + * + * @param record database record for which metadata should be updated + * @throws DBException if operation failed */ protected void updateDocumentMeta(Record record) throws DBException { // update the meta data if necessary Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/SystemCollection.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/SystemCollection.java?rev=568786&r1=568785&r2=568786&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/core/SystemCollection.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/core/SystemCollection.java Wed Aug 22 17:40:57 2007 @@ -126,7 +126,7 @@ if (symbols != null) { String name = getSymbolTableName(collection); getCollection(SYMBOLS).setObject(name, symbols); - symbols.setDirty(false); + symbols.resetDirty(); } } Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java?rev=568786&r1=568785&r2=568786&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java Wed Aug 22 17:40:57 2007 @@ -19,18 +19,21 @@ package org.apache.xindice.core.indexer; -import org.xml.sax.ContentHandler; -import org.xml.sax.Locator; -import org.xml.sax.Attributes; -import org.apache.xindice.xml.sax.CompressionHandler; -import org.apache.xindice.xml.sax.SAXEventGenerator; -import org.apache.xindice.xml.SymbolTable; -import org.apache.xindice.util.ObjectStack; -import org.apache.xindice.core.data.Key; -import org.apache.xindice.core.DBException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.xindice.core.DBException; +import org.apache.xindice.core.data.Key; +import org.apache.xindice.util.ObjectStack; +import org.apache.xindice.util.ReadOnlyException; +import org.apache.xindice.xml.SymbolTable; +import org.apache.xindice.xml.sax.CompressionHandler; +import org.apache.xindice.xml.sax.SAXEventGenerator; + import org.w3c.dom.Document; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; /** * DocumentHandler actually performs the work of adding and removing Indexer @@ -39,6 +42,9 @@ * @version $Revision$, $Date$ */ class DocumentHandler implements ContentHandler, CompressionHandler { + + private static final Log log = LogFactory.getLog(DocumentHandler.class); + static final int ACTION_CREATE = 0; static final int ACTION_DELETE = 1; @@ -53,8 +59,6 @@ public StackInfo info; // Current State - private static final Log log = LogFactory.getLog(DocumentHandler.class); - public DocumentHandler(SymbolTable symbols, Key key, Document doc, int action, Indexer[] list) { this.symbols = symbols; this.key = key; @@ -173,23 +177,27 @@ } } - public void startElement(String namespaceURI, String localName, String qName, Attributes atts) { - // Modify the stack info to normalize the symbolID - if (namespaceURI != null && namespaceURI.length() > 0) { - info.symbolID = symbols.getNormalizedSymbol(localName, namespaceURI, true); - } - - int size = atts.getLength(); - for (int i = 0; i < size; i++) { - String nsURI = atts.getURI(i); - short id; - if (nsURI != null && nsURI.length() > 0) { - id = symbols.getNormalizedSymbol(atts.getLocalName(i), nsURI, true); - } else { - id = symbols.getSymbol(atts.getQName(i), true); + public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { + try { +// Modify the stack info to normalize the symbolID + if (namespaceURI != null && namespaceURI.length() > 0) { + info.symbolID = symbols.getNormalizedSymbol(localName, namespaceURI, true); } - processEntry(new IndexPattern(symbols, info.symbolID, id), atts.getValue(i), info.pos, info.len); + int size = atts.getLength(); + for (int i = 0; i < size; i++) { + String nsURI = atts.getURI(i); + short id; + if (nsURI != null && nsURI.length() > 0) { + id = symbols.getNormalizedSymbol(atts.getLocalName(i), nsURI, true); + } else { + id = symbols.getSymbol(atts.getQName(i), true); + } + + processEntry(new IndexPattern(symbols, info.symbolID, id), atts.getValue(i), info.pos, info.len); + } + } catch (ReadOnlyException e) { + throw new SAXException(e); } } Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java?rev=568786&r1=568785&r2=568786&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java Wed Aug 22 17:40:57 2007 @@ -19,7 +19,9 @@ package org.apache.xindice.core.indexer; +import org.apache.xindice.core.FaultCodes; import org.apache.xindice.core.filer.Streamable; +import org.apache.xindice.util.ReadOnlyException; import org.apache.xindice.xml.NamespaceMap; import org.apache.xindice.xml.SymbolTable; @@ -53,24 +55,30 @@ private short attrID = PATTERN_NONE; - public IndexPattern(SymbolTable symbols, String pattern, NamespaceMap nsMap) { + public IndexPattern(SymbolTable symbols, String pattern, NamespaceMap nsMap) throws IndexerException { this.symbols = symbols; StringTokenizer st = new StringTokenizer(pattern.trim(), "@"); - elemName = st.nextToken(); - if (elemName.equals("*")) { - elemID = PATTERN_WILDCARD; - } else { - elemID = symbols.getNormalizedSymbol(elemName, nsMap, true); - } - - if (st.hasMoreTokens()) { - attrName = st.nextToken(); - if (attrName.equals("*")) { - attrID = PATTERN_WILDCARD; + + try { + elemName = st.nextToken(); + if (elemName.equals("*")) { + elemID = PATTERN_WILDCARD; } else { - attrID = elemID == PATTERN_WILDCARD ? PATTERN_NAME - : symbols.getNormalizedSymbol(attrName, nsMap, true); + elemID = symbols.getNormalizedSymbol(elemName, nsMap, true); + } + + if (st.hasMoreTokens()) { + attrName = st.nextToken(); + if (attrName.equals("*")) { + attrID = PATTERN_WILDCARD; + } else { + attrID = elemID == PATTERN_WILDCARD ? PATTERN_NAME + : symbols.getNormalizedSymbol(attrName, nsMap, true); + } } + } catch (ReadOnlyException e) { + throw new IndexerException(FaultCodes.IDX_NOT_SUPPORTED, + "Pattern '" + pattern + "' is not allowed in this collection.", e); } } Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java?rev=568786&r1=568785&r2=568786&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java Wed Aug 22 17:40:57 2007 @@ -919,7 +919,7 @@ return null; } - private Object funcStartsWith(String owner, List args) { + private Object funcStartsWith(String owner, List args) throws Exception { if (args.size() == 2) { Object o = args.get(0); Object s = args.get(1); @@ -1114,7 +1114,7 @@ * @param right The right Operand * @return The resulting Keys (if any) */ - private Object queryComparison(int op, String owner, Object left, Object right) { + private Object queryComparison(int op, String owner, Object left, Object right) throws Exception { op = OPMAP[op - OpCodes.OP_NOTEQUALS]; if (left instanceof XObject) { Modified: xml/xindice/trunk/java/src/org/apache/xindice/xml/SymbolTable.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/xml/SymbolTable.java?rev=568786&r1=568785&r2=568786&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/xml/SymbolTable.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/xml/SymbolTable.java Wed Aug 22 17:40:57 2007 @@ -19,6 +19,8 @@ package org.apache.xindice.xml; +import org.apache.xindice.util.ReadOnlyException; + import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -45,9 +47,10 @@ private transient boolean dirty; private transient long lastModified = System.currentTimeMillis(); + private short maxSymbol = -1; private final Map symbols = new HashMap(); // String to SymbolInfo private final Map names = new HashMap(); // Short to SymbolInfo - private short maxSymbol = -1; + private boolean readOnly; public static final class SymbolInfo implements Serializable { @@ -55,14 +58,14 @@ private final String qname; private final short symbol; - private SymbolInfo(String qname, String namespaceURI, short symbol) { - this.namespaceURI = namespaceURI; + private SymbolInfo(String qname, short symbol) { + this.namespaceURI = null; this.qname = qname; this.symbol = symbol; } - private SymbolInfo(String qname, short symbol) { - this.namespaceURI = null; + private SymbolInfo(String qname, String namespaceURI, short symbol) { + this.namespaceURI = namespaceURI; this.qname = qname; this.symbol = symbol; } @@ -87,23 +90,50 @@ public SymbolTable() { } - public SymbolTable(Element elem) { - streamFromXML(elem); + public SymbolTable(Element symbols) { + streamFromXML(symbols); + } + + public SymbolTable(Element symbols, boolean readOnly) { + this(symbols); + this.readOnly = readOnly; } + /** + * @return true if symbol table has been modified + */ public final boolean isDirty() { return dirty; } - public final void setDirty(boolean dirty) { - this.dirty = dirty; + /** + * Set dirty flag to true and update last modified + * time stamp. + */ + private void markDirty() { + this.dirty = true; this.lastModified = System.currentTimeMillis(); } + /** + * Reset dirty flag to false. Should be invoked + * once symbol table is successfully saved. + */ + public final void resetDirty() { + this.dirty = false; + } + public final long getLastModified() { return lastModified; } + /** + * @return true if symbol table is read only + */ + public final boolean isReadOnly() { + return readOnly; + } + // // Lookup by symbol id // @@ -127,26 +157,40 @@ // public final short getSymbol(String qname) { - return getSymbol(qname, false); + try { + return getSymbol(qname, false); + } catch (ReadOnlyException e) { + // Won't happen + throw new IllegalStateException(); + } } public final short getSymbol(String qname, String namespaceURI) { - return getSymbol(qname, namespaceURI, false); + try { + return getSymbol(qname, namespaceURI, false); + } catch (ReadOnlyException e) { + // Won't happen + throw new IllegalStateException(); + } } - public final short getSymbol(String qname, boolean create) { + public final short getSymbol(String qname, boolean create) throws ReadOnlyException { SymbolInfo info = (SymbolInfo) symbols.get(qname); if (info != null) { return info.symbol; } if (create) { + if (readOnly) { + throw new ReadOnlyException(); + } + synchronized (symbols) { short id = ++maxSymbol; info = new SymbolInfo(qname, id); symbols.put(qname, info); names.put(new Short(id), info); - setDirty(true); + markDirty(); return id; } } @@ -154,7 +198,7 @@ return -1; } - public final short getSymbol(String qname, String namespaceURI, boolean create) { + public final short getSymbol(String qname, String namespaceURI, boolean create) throws ReadOnlyException { String lookupName = getLookupName(qname, namespaceURI); SymbolInfo info = (SymbolInfo) symbols.get(lookupName); @@ -163,12 +207,16 @@ } if (create) { + if (readOnly) { + throw new ReadOnlyException(); + } + synchronized (symbols) { short id = ++maxSymbol; info = new SymbolInfo(qname, namespaceURI, id); symbols.put(lookupName, info); names.put(new Short(id), info); - setDirty(true); + markDirty(); return id; } } @@ -181,7 +229,12 @@ // public final short getNormalizedSymbol(String localName, String namespaceURI) { - return getNormalizedSymbol(localName, namespaceURI, false); + try { + return getNormalizedSymbol(localName, namespaceURI, false); + } catch (ReadOnlyException e) { + // Won't happen + throw new IllegalStateException(); + } } /** @@ -191,9 +244,10 @@ * @param namespaceURI element (attribute) namespace URI * @param create when true, creates symbol if it is missing * @return symbol id or -1 + * @throws ReadOnlyException if 'create' option specified and the symbol is missing */ - public final short getNormalizedSymbol(String localName, String namespaceURI, boolean create) { - String normalizedQName = SymbolTable.getNormalizedQName(localName, namespaceURI); + public final short getNormalizedSymbol(String localName, String namespaceURI, boolean create) throws ReadOnlyException { + String normalizedQName = getNormalizedQName(localName, namespaceURI); return getSymbol(normalizedQName, namespaceURI, create); } @@ -212,8 +266,9 @@ * @param nsMap namespace map * @param create when true, creates symbol if it is missing * @return symbol id or -1 + * @throws ReadOnlyException if 'create' option specified and the symbol is missing */ - public final short getNormalizedSymbol(String lookup, NamespaceMap nsMap, boolean create) { + public final short getNormalizedSymbol(String lookup, NamespaceMap nsMap, boolean create) throws ReadOnlyException { // Parse [<namespaceURI>]<nsPrefix>:<localName> with optional nsPrefix if (lookup.startsWith("[")) { int idx = lookup.indexOf(']'); @@ -300,7 +355,7 @@ // Implementation methods // - private static String getNormalizedQName(String localName, String namespaceURI) { + private String getNormalizedQName(String localName, String namespaceURI) { return "ns" + namespaceURI.hashCode() + ':' + localName; } Modified: xml/xindice/trunk/java/src/org/apache/xindice/xml/dom/DOMCompressor.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/xml/dom/DOMCompressor.java?rev=568786&r1=568785&r2=568786&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/xml/dom/DOMCompressor.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/xml/dom/DOMCompressor.java Wed Aug 22 17:40:57 2007 @@ -21,11 +21,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.xindice.util.ReadOnlyException; import org.apache.xindice.xml.Signatures; import org.apache.xindice.xml.SymbolTable; import org.apache.xindice.xml.XMLCompressedOutput; import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -56,6 +58,8 @@ * * @param node the node to write * @throws IOException if the write to underlying stream has failed + * @throws DOMException if used symbol table is read only and some of + * node's content can not be serialized. */ public void writeNode(Node node) throws IOException { // Check if it's node of ours @@ -85,9 +89,21 @@ String nsURI = node.getNamespaceURI(); short symbolID; if (nsURI != null) { - symbolID = st.getSymbol(node.getNodeName(), nsURI, true); + try { + symbolID = st.getSymbol(node.getNodeName(), nsURI, true); + } catch (ReadOnlyException e) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Element can not be serialized (read only symbol table). " + + "Name: '" + node.getNodeName() + "', namespace: " + nsURI); + } } else { - symbolID = st.getSymbol(node.getNodeName(), true); + try { + symbolID = st.getSymbol(node.getNodeName(), true); + } catch (ReadOnlyException e) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Element can not be serialized (read only symbol table). " + + "Name: '" + node.getNodeName() + "'"); + } } byte signature = Signatures.NODE_ELEM; @@ -118,9 +134,21 @@ String nsURI = attr.getNamespaceURI(); short symbolID; if (nsURI != null) { - symbolID = st.getSymbol(attr.getName(), nsURI, true); + try { + symbolID = st.getSymbol(attr.getName(), nsURI, true); + } catch (ReadOnlyException e) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Attribute can not be serialized (read only symbol table). " + + "Name: '" + attr.getName() + "', namespace: " + nsURI); + } } else { - symbolID = st.getSymbol(attr.getName(), true); + try { + symbolID = st.getSymbol(attr.getName(), true); + } catch (ReadOnlyException e) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Attribute can not be serialized (read only symbol table). " + + "Name: '" + attr.getName() + "'"); + } } writeShort(symbolID); @@ -178,7 +206,13 @@ // TODO symbol = } else { encoding = 2; - symbol = st.getSymbol(value, true); + try { + symbol = st.getSymbol(value, true); + } catch (ReadOnlyException e) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Entity reference can not be serialized (read only symbol table). " + + "Value: '" + value + "'"); + } signature |= (byte) (Signatures.ENT_DEFINED); } writeByte(signature); Modified: xml/xindice/trunk/java/tests/src/org/apache/xindice/xml/SymbolTableTest.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/xml/SymbolTableTest.java?rev=568786&r1=568785&r2=568786&view=diff ============================================================================== --- xml/xindice/trunk/java/tests/src/org/apache/xindice/xml/SymbolTableTest.java (original) +++ xml/xindice/trunk/java/tests/src/org/apache/xindice/xml/SymbolTableTest.java Wed Aug 22 17:40:57 2007 @@ -19,6 +19,7 @@ package org.apache.xindice.xml; +import org.apache.xindice.util.ReadOnlyException; import org.apache.xindice.xml.dom.DOMParser; import junit.framework.TestCase; @@ -44,7 +45,7 @@ } - public void testMissingSymbol() { + public void testMissingSymbol() throws Exception { assertNull(symbols.getSymbolInfo((short) 123)); assertEquals(-1, symbols.getSymbol("missing")); @@ -95,7 +96,7 @@ assertFalse(symbols.isDirty()); } - public void testAddSymbol() { + public void testAddSymbol() throws Exception { assertEquals(-1, symbols.getSymbol("missing")); assertTrue(symbols.getSymbol("missing", true) != -1); assertTrue(symbols.isDirty()); @@ -109,7 +110,7 @@ assertEquals(s, si.getSymbolID()); } - public void testAddNamespacedSymbol() { + public void testAddNamespacedSymbol() throws Exception { assertEquals(-1, symbols.getSymbol("missing", "urn:unknown")); assertTrue(symbols.getSymbol("missing", "urn:unknown", true) != -1); assertTrue(symbols.isDirty()); @@ -123,7 +124,7 @@ assertEquals(s, si.getSymbolID()); } - public void testGetNormalizedSymbol() { + public void testGetNormalizedSymbol() throws Exception { assertEquals(1, symbols.getNormalizedSymbol("simple", (NamespaceMap) null, false)); assertEquals(-1, symbols.getNormalizedSymbol("[http://www.w3.org/1999/xhtml]spaced", (NamespaceMap) null, false)); @@ -140,5 +141,16 @@ NamespaceMap m = new NamespaceMap(); m.setNamespace("z", "http://www.w3.org/1999/xhtml"); assertEquals(s, symbols.getNormalizedSymbol("z:spaced", m, false)); + } + + public void testReadOnly() throws Exception { + symbols = new SymbolTable(DOMParser.toDocument(SYMBOLS).getDocumentElement(), true); + + assertEquals(-1, symbols.getSymbol("foo")); + + try { + symbols.getSymbol("foo", true); + fail(); + } catch (ReadOnlyException e) { } } }