From: <wol...@us...> - 2009-01-20 08:57:34
|
Revision: 8508 http://exist.svn.sourceforge.net/exist/?rev=8508&view=rev Author: wolfgang_m Date: 2009-01-20 08:57:29 +0000 (Tue, 20 Jan 2009) Log Message: ----------- [feature] allow serialization filters to be plugged into the output stream generated by the serializer. This is currently used by the versioning extension to inject versioning metadata into the XML document. Modified Paths: -------------- trunk/eXist/src/org/exist/atom/http/WebDAVServlet.java trunk/eXist/src/org/exist/atom/modules/AtomProtocol.java trunk/eXist/src/org/exist/collections/CollectionConfiguration.java trunk/eXist/src/org/exist/collections/triggers/TriggerException.java trunk/eXist/src/org/exist/http/RESTServer.java trunk/eXist/src/org/exist/indexing/AbstractMatchListener.java trunk/eXist/src/org/exist/security/XMLSecurityManager.java trunk/eXist/src/org/exist/storage/serializers/Serializer.java trunk/eXist/src/org/exist/util/Configuration.java Added Paths: ----------- trunk/eXist/src/org/exist/storage/serializers/CustomMatchListener.java trunk/eXist/src/org/exist/storage/serializers/CustomMatchListenerFactory.java Modified: trunk/eXist/src/org/exist/atom/http/WebDAVServlet.java =================================================================== --- trunk/eXist/src/org/exist/atom/http/WebDAVServlet.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/atom/http/WebDAVServlet.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -363,12 +363,12 @@ } catch (ParserConfigurationException ex) { transact.abort(transaction); throw new ServletException("SAX error: "+ex.getMessage(),ex); + } catch (TriggerException ex) { + transact.abort(transaction); + throw new ServletException("Trigger failed: "+ex.getMessage(),ex); } catch (SAXException ex) { transact.abort(transaction); throw new ServletException("SAX error: "+ex.getMessage(),ex); - } catch (TriggerException ex) { - transact.abort(transaction); - throw new ServletException("Trigger failed: "+ex.getMessage(),ex); } catch (LockException ex) { transact.abort(transaction); throw new ServletException("Cannot acquire write lock.",ex); Modified: trunk/eXist/src/org/exist/atom/modules/AtomProtocol.java =================================================================== --- trunk/eXist/src/org/exist/atom/modules/AtomProtocol.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/atom/modules/AtomProtocol.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -297,12 +297,12 @@ } catch (IOException ex) { transact.abort(transaction); throw new EXistException("IO error: "+ex.getMessage(),ex); + } catch (TriggerException ex) { + transact.abort(transaction); + throw new EXistException("Trigger failed: "+ex.getMessage(),ex); } catch (SAXException ex) { transact.abort(transaction); throw new EXistException("SAX error: "+ex.getMessage(),ex); - } catch (TriggerException ex) { - transact.abort(transaction); - throw new EXistException("Trigger failed: "+ex.getMessage(),ex); } catch (LockException ex) { transact.abort(transaction); throw new EXistException("Cannot acquire write lock.",ex); @@ -400,6 +400,9 @@ throw new BadRequestException("Parsing exception at " + e.getLineNumber() + "/" + e.getColumnNumber() + ": " + e.toString()); + } catch (TriggerException e) { + transact.abort(transaction); + throw new PermissionDeniedException(e.getMessage()); } catch (SAXException e) { transact.abort(transaction); Exception o = e.getException(); @@ -407,9 +410,6 @@ o = e; throw new BadRequestException("Parsing exception: " + o.getMessage()); - } catch (TriggerException e) { - transact.abort(transaction); - throw new PermissionDeniedException(e.getMessage()); } catch (LockException e) { transact.abort(transaction); throw new PermissionDeniedException(e.getMessage()); @@ -620,6 +620,9 @@ throw new BadRequestException("Parsing exception at " + e.getLineNumber() + "/" + e.getColumnNumber() + ": " + e.toString()); + } catch (TriggerException e) { + transact.abort(transaction); + throw new PermissionDeniedException(e.getMessage()); } catch (SAXException e) { transact.abort(transaction); Exception o = e.getException(); @@ -627,9 +630,6 @@ o = e; throw new BadRequestException("Parsing exception: " + o.getMessage()); - } catch (TriggerException e) { - transact.abort(transaction); - throw new PermissionDeniedException(e.getMessage()); } catch (LockException e) { transact.abort(transaction); throw new PermissionDeniedException(e.getMessage()); Modified: trunk/eXist/src/org/exist/collections/CollectionConfiguration.java =================================================================== --- trunk/eXist/src/org/exist/collections/CollectionConfiguration.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/collections/CollectionConfiguration.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -249,7 +249,15 @@ public TriggerConfig getTriggerConfiguration(int eventType) { return triggers[eventType]; } - + + public boolean triggerRegistered(Class triggerClass) { + for (int i = 0; i < triggers.length; i++) { + if (triggers[i] != null && triggers[i].getTriggerClass() == triggerClass) + return true; + } + return false; + } + private void createTrigger(DBBroker broker, Element node, boolean testConfig) throws CollectionConfigurationException { Modified: trunk/eXist/src/org/exist/collections/triggers/TriggerException.java =================================================================== --- trunk/eXist/src/org/exist/collections/triggers/TriggerException.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/collections/triggers/TriggerException.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -23,10 +23,12 @@ */ package org.exist.collections.triggers; +import org.xml.sax.SAXException; + /** * @author wolf */ -public class TriggerException extends Exception { +public class TriggerException extends SAXException { /** * @@ -45,7 +47,7 @@ /** * @param cause */ - public TriggerException(Throwable cause) { + public TriggerException(Exception cause) { super(cause); } @@ -53,7 +55,7 @@ * @param message * @param cause */ - public TriggerException(String message, Throwable cause) { + public TriggerException(String message, Exception cause) { super(message, cause); } Modified: trunk/eXist/src/org/exist/http/RESTServer.java =================================================================== --- trunk/eXist/src/org/exist/http/RESTServer.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/http/RESTServer.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -937,6 +937,9 @@ throw new BadRequestException("Parsing exception at " + e.getLineNumber() + "/" + e.getColumnNumber() + ": " + e.toString()); + } catch (TriggerException e) { + transact.abort(transaction); + throw new PermissionDeniedException(e.getMessage()); } catch (SAXException e) { transact.abort(transaction); Exception o = e.getException(); @@ -947,9 +950,6 @@ } catch (EXistException e) { transact.abort(transaction); throw new BadRequestException("Internal error: " + e.getMessage()); - } catch (TriggerException e) { - transact.abort(transaction); - throw new PermissionDeniedException(e.getMessage()); } catch (LockException e) { transact.abort(transaction); throw new PermissionDeniedException(e.getMessage()); Modified: trunk/eXist/src/org/exist/indexing/AbstractMatchListener.java =================================================================== --- trunk/eXist/src/org/exist/indexing/AbstractMatchListener.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/indexing/AbstractMatchListener.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -37,7 +37,8 @@ public void setCurrentNode(StoredNode node) { this.currentNode = node; - getNextInChain().setCurrentNode(node); + if (nextListener != null) + getNextInChain().setCurrentNode(node); } protected StoredNode getCurrentNode() { Modified: trunk/eXist/src/org/exist/security/XMLSecurityManager.java =================================================================== --- trunk/eXist/src/org/exist/security/XMLSecurityManager.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/security/XMLSecurityManager.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -383,12 +383,12 @@ broker.saveCollection(transaction, doc.getCollection()); } catch (IOException e) { throw new EXistException(e.getMessage()); + } catch (TriggerException e) { + throw new EXistException(e.getMessage()); } catch (SAXException e) { throw new EXistException(e.getMessage()); } catch (PermissionDeniedException e) { throw new EXistException(e.getMessage()); - } catch (TriggerException e) { - throw new EXistException(e.getMessage()); } catch (LockException e) { throw new EXistException(e.getMessage()); } Added: trunk/eXist/src/org/exist/storage/serializers/CustomMatchListener.java =================================================================== --- trunk/eXist/src/org/exist/storage/serializers/CustomMatchListener.java (rev 0) +++ trunk/eXist/src/org/exist/storage/serializers/CustomMatchListener.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -0,0 +1,29 @@ +package org.exist.storage.serializers; + +import org.exist.indexing.AbstractMatchListener; +import org.exist.storage.DBBroker; + +/** + * Base class for custom filters which can be applied to the serialization + * stream generated by the {@link org.exist.storage.serializers.Serializer}. + * Custom filters can be registered in conf.xml. + * + * TODO: MatchListener should probably be renamed into SerializationFilter + * or similar. + */ +public abstract class CustomMatchListener extends AbstractMatchListener { + + private DBBroker broker; + + protected void reset() { + setCurrentNode(null); + } + + protected void setBroker(DBBroker broker) { + this.broker = broker; + } + + protected DBBroker getBroker() { + return broker; + } +} \ No newline at end of file Added: trunk/eXist/src/org/exist/storage/serializers/CustomMatchListenerFactory.java =================================================================== --- trunk/eXist/src/org/exist/storage/serializers/CustomMatchListenerFactory.java (rev 0) +++ trunk/eXist/src/org/exist/storage/serializers/CustomMatchListenerFactory.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -0,0 +1,63 @@ +package org.exist.storage.serializers; + +import org.apache.log4j.Logger; +import org.exist.indexing.MatchListener; +import org.exist.storage.DBBroker; +import org.exist.util.Configuration; + +import java.util.List; + +/** + * Configures and maintains a list of {@link org.exist.storage.serializers.CustomMatchListener}. + * There will be one CustomMatchListenerFactory for every {@link org.exist.storage.serializers.Serializer} + * instance. + */ +public class CustomMatchListenerFactory { + + private final static Logger LOG = Logger.getLogger(CustomMatchListenerFactory.class); + + public final static String CONFIGURATION_ELEMENT = "custom-filter"; + public final static String CONFIGURATION_ATTR_CLASS = "class"; + public final static String CONFIG_MATCH_LISTENERS = "serialization.custom-match-listeners"; + + private CustomMatchListener first = null; + private CustomMatchListener last = null; + + public CustomMatchListenerFactory(DBBroker broker, Configuration config) { + List classes = (List) config.getProperty(CONFIG_MATCH_LISTENERS); + if (classes == null) + return; + CustomMatchListener listener; + for (int i = 0; i < classes.size(); i++) { + try { + Class listenerClass = Class.forName(classes.get(i).toString()); + if (CustomMatchListener.class.isAssignableFrom(listenerClass)) { + listener = (CustomMatchListener) listenerClass.newInstance(); + listener.setBroker(broker); + if (first == null) { + first = listener; + last = listener; + } else { + last.setNextInChain(listener); + last = listener; + } + } else + LOG.error("Failed to instantiate class " + listenerClass.getName() + + ": it is not a subclass of CustomMatchListener"); + } catch (Exception e) { + LOG.error("An exception was caught while trying to instantiate a custom MatchListener: " + + e.getMessage(), e); + } + } + } + + public MatchListener getFirst() { + if (first != null) + first.reset(); + return first; + } + + public MatchListener getLast() { + return last; + } +} \ No newline at end of file Modified: trunk/eXist/src/org/exist/storage/serializers/Serializer.java =================================================================== --- trunk/eXist/src/org/exist/storage/serializers/Serializer.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/storage/serializers/Serializer.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -164,6 +164,7 @@ protected Templates templates = null; protected TransformerHandler xslHandler = null; protected XIncludeFilter xinclude; + protected CustomMatchListenerFactory customMatchListeners; protected Receiver receiver = null; protected SAXSerializer xmlout = null; protected LexicalHandler lexicalHandler = null; @@ -173,6 +174,7 @@ this.broker = broker; factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); xinclude = new XIncludeFilter(this); + customMatchListeners = new CustomMatchListenerFactory(broker, config); receiver = xinclude; String option = (String) config.getProperty(PROPERTY_ENABLE_XSL); @@ -415,7 +417,8 @@ if (templates != null) applyXSLHandler(writer); else - setPrettyPrinter(writer, outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION, "yes").equals("no"), null); //setPrettyPrinter(writer, false); + setPrettyPrinter(writer, outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION, "yes").equals("no"), + null, true); //setPrettyPrinter(writer, false); serializeToReceiver(doc, true); releasePrettyPrinter(); @@ -432,7 +435,7 @@ applyXSLHandler(out); else setPrettyPrinter(out, outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION, "yes").equals("no"), - n.getImplementationType() == NodeValue.PERSISTENT_NODE ? (NodeProxy)n : null); //setPrettyPrinter(out, false); + n.getImplementationType() == NodeValue.PERSISTENT_NODE ? (NodeProxy)n : null, false); //setPrettyPrinter(out, false); serializeToReceiver(n, true); releasePrettyPrinter(); return out.toString(); @@ -455,7 +458,8 @@ if (templates != null) applyXSLHandler(out); else - setPrettyPrinter(out, outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION, "yes").equals("no"), p); //setPrettyPrinter(out, false); + setPrettyPrinter(out, outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION, "yes").equals("no"), + p, false); //setPrettyPrinter(out, false); serializeToReceiver(p, false); releasePrettyPrinter(); return out.toString(); @@ -540,7 +544,7 @@ throw new SAXNotRecognizedException(name); } - protected void setPrettyPrinter(Writer writer, boolean xmlDecl, NodeProxy root) { + protected void setPrettyPrinter(Writer writer, boolean xmlDecl, NodeProxy root, boolean applyFilters) { outputProperties.setProperty( OutputKeys.OMIT_XML_DECLARATION, xmlDecl ? "no" : "yes"); @@ -561,6 +565,10 @@ receiver = listener; } } + if (root == null && applyFilters && customMatchListeners.getFirst() != null) { + customMatchListeners.getLast().setNextInChain(receiver); + receiver = customMatchListeners.getFirst(); + } } protected Receiver setupMatchListeners(NodeProxy p) { @@ -700,7 +708,7 @@ xslHandler.getTransformer().setParameter(param, value); } - protected void setXSLHandler(NodeProxy root) { + protected void setXSLHandler(NodeProxy root, boolean applyFilters) { if (templates != null && xslHandler != null) { SAXResult result = new SAXResult(); boolean processXInclude = @@ -734,6 +742,10 @@ receiver = listener; } } + if (applyFilters && root == null && customMatchListeners.getFirst() != null) { + customMatchListeners.getLast().setNextInChain(receiver); + receiver = customMatchListeners.getFirst(); + } } public void toSAX(DocumentImpl doc) throws SAXException { @@ -751,7 +763,7 @@ } catch (TransformerConfigurationException e) { throw new SAXException(e.getMessage(), e); } - setXSLHandler(null); + setXSLHandler(null, true); serializeToReceiver( doc, getProperty(GENERATE_DOC_EVENTS, "false").equals("true")); @@ -763,7 +775,7 @@ } catch (TransformerConfigurationException e) { throw new SAXException(e.getMessage(), e); } - setXSLHandler(n.getImplementationType() == NodeValue.PERSISTENT_NODE ? (NodeProxy)n : null); + setXSLHandler(n.getImplementationType() == NodeValue.PERSISTENT_NODE ? (NodeProxy)n : null, false); serializeToReceiver( n, getProperty(GENERATE_DOC_EVENTS, "false").equals("true")); @@ -775,7 +787,7 @@ } catch (TransformerConfigurationException e) { throw new SAXException(e.getMessage(), e); } - setXSLHandler(p); + setXSLHandler(p, false); if (p.getNodeId() == NodeId.DOCUMENT_NODE) { serializeToReceiver(p.getDocument(), getProperty(GENERATE_DOC_EVENTS, "false").equals("true")); } else { @@ -802,7 +814,7 @@ } catch (TransformerConfigurationException e) { throw new SAXException(e.getMessage(), e); } - setXSLHandler(null); + setXSLHandler(null, false); AttrList attrs = new AttrList(); attrs.addAttribute(ATTR_HITS_QNAME, Integer.toString(seq.getItemCount())); attrs.addAttribute(ATTR_START_QNAME, Integer.toString(start)); Modified: trunk/eXist/src/org/exist/util/Configuration.java =================================================================== --- trunk/eXist/src/org/exist/util/Configuration.java 2009-01-19 18:01:25 UTC (rev 8507) +++ trunk/eXist/src/org/exist/util/Configuration.java 2009-01-20 08:57:29 UTC (rev 8508) @@ -45,6 +45,7 @@ import org.exist.storage.XQueryPool; import org.exist.storage.journal.Journal; import org.exist.storage.serializers.Serializer; +import org.exist.storage.serializers.CustomMatchListenerFactory; import org.exist.storage.txn.TransactionManager; import org.exist.validation.GrammarPool; import org.exist.validation.resolver.eXistXMLCatalogResolver; @@ -549,8 +550,26 @@ config.put(Serializer.PROPERTY_TAG_MATCHING_ATTRIBUTES, tagAttributeMatches); LOG.debug(Serializer.PROPERTY_TAG_MATCHING_ATTRIBUTES + ": " + config.get(Serializer.PROPERTY_TAG_MATCHING_ATTRIBUTES)); } + + NodeList nlFilters = serializer.getElementsByTagName(CustomMatchListenerFactory.CONFIGURATION_ELEMENT); + if (nlFilters == null) + return; + + List filters = new ArrayList(nlFilters.getLength()); + for (int i = 0; i < nlFilters.getLength(); i++) { + Element filterElem = (Element) nlFilters.item(i); + String filterClass = filterElem.getAttribute(CustomMatchListenerFactory.CONFIGURATION_ATTR_CLASS); + if (filterClass != null) { + filters.add(filterClass); + LOG.debug(CustomMatchListenerFactory.CONFIG_MATCH_LISTENERS + ": " + filterClass); + } else { + LOG.warn("Configuration element " + CustomMatchListenerFactory.CONFIGURATION_ELEMENT + + " needs an attribute 'class'"); + } + } + config.put(CustomMatchListenerFactory.CONFIG_MATCH_LISTENERS, filters); } - + /** * Reads the scheduler configuration */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |