You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by pi...@apache.org on 2004/11/08 01:35:39 UTC
svn commit: rev 56886 - in cocoon/whiteboard/kernel/sources/contracts/repository: . src src/org src/org/apache src/org/apache/cocoon src/org/apache/cocoon/components src/org/apache/cocoon/components/repository
Author: pier
Date: Sun Nov 7 16:35:38 2004
New Revision: 56886
Added:
cocoon/whiteboard/kernel/sources/contracts/repository/
cocoon/whiteboard/kernel/sources/contracts/repository/cocoon.xml
cocoon/whiteboard/kernel/sources/contracts/repository/src/
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/AbstractRepository.java
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/BufferedDocument.java
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/Document.java
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/Repository.java
cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/RepositoryListener.java
Log:
Adding sample "repository" block
Added: cocoon/whiteboard/kernel/sources/contracts/repository/cocoon.xml
==============================================================================
--- (empty file)
+++ cocoon/whiteboard/kernel/sources/contracts/repository/cocoon.xml Sun Nov 7 16:35:38 2004
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<contract xmlns="http://apache.org/cocoon/kernel/descriptor/1.0"
+ id="http://cocoon.apache.org/kernel/contracts/repository/1.0">
+
+ <exposes interface="org.apache.cocoon.contracts.repository.Repository"/>
+
+</contract>
\ No newline at end of file
Added: cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/AbstractRepository.java
==============================================================================
--- (empty file)
+++ cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/AbstractRepository.java Sun Nov 7 16:35:38 2004
@@ -0,0 +1,256 @@
+/* =============================================================================== *
+ * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use *
+ * this file except in compliance with the License. You may obtain a copy of the *
+ * License at <http://www.apache.org/licenses/LICENSE-2.0>. *
+ * *
+ * Unless required by applicable law or agreed to in writing, software distributed *
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR *
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations under the License. *
+ * =============================================================================== */
+package org.apache.cocoon.components.repository;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * <p>A basic implementation of the {@link Repository} interface.</p>
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache
+ * Software Foundation</a>. All rights reserved.
+ */
+public abstract class AbstractRepository implements Repository {
+
+ private Set listeners = null;
+ private Log logger = null;
+
+ /**
+ * <p>Create a new {@link AbstractRepository} instance.</p>
+ */
+ protected AbstractRepository() {
+ this.listeners = Collections.synchronizedSet(new HashSet());
+ this.logger = LogFactory.getLog(this.getClass());
+ }
+
+ /* =========================================================================== */
+ /* ABSTRACT METHODS */
+ /* =========================================================================== */
+
+ public abstract Document retrieve(String identifier)
+ throws IOException;
+
+ public abstract Iterator documents();
+
+ /* =========================================================================== */
+ /* OVERRIDABLE METHODS */
+ /* =========================================================================== */
+
+ /**
+ * <p>Store the specified {@link Document} in this {@link Repository}
+ * associating it with the specified unique identifier.</p>
+ *
+ * <p>The default {@link AbstractRepository} implementation of this method
+ * always throws an {@link UnsupportedOperationException}.</p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @param document the {@link Document} to store.
+ * @throws UnsupportedOperationException if this {@link Repository} is immutable.
+ * @throws IOException if an I/O error occurred retrieving the {@link Document}.
+ */
+ protected void doStore(String identifier, Document document)
+ throws UnsupportedOperationException, IOException {
+ throw new UnsupportedOperationException("Store operation not supported");
+ }
+
+ /**
+ * <p>Delete the specified {@link Document} from this {@link Repository}.</p>
+ *
+ * <p>The default {@link AbstractRepository} implementation of this method
+ * always throws an {@link UnsupportedOperationException}.</p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @throws UnsupportedOperationException if this {@link Repository} is immutable.
+ * @throws IOException if an I/O error occurred removing the {@link Document}.
+ */
+ protected void doDelete(String identifier)
+ throws UnsupportedOperationException, IOException {
+ throw new UnsupportedOperationException("Delete operation not supported");
+ }
+
+ /* =========================================================================== */
+ /* PROTECTED METHODS */
+ /* =========================================================================== */
+
+ /**
+ * <p>Return the currently configured {@link Log} instance.</p>
+ *
+ * @return a <b>non null</b> {@link Log} instance.
+ */
+ protected Log getLogger() {
+ return this.logger;
+ }
+
+ /**
+ * <p>Return an {@link Iterator} over all known {@link RepositoryListener}s.</p>
+ *
+ * @return a <b>non null</b> {@link Iterator} instance.
+ */
+ protected Iterator getRepositoryListeners() {
+ return this.listeners.iterator();
+ }
+
+ /* =========================================================================== */
+ /* IMPLEMENTED METHODS */
+ /* =========================================================================== */
+
+ /**
+ * <p>Check if a {@link Document} is contained in this {@link Repository}.</p>
+ *
+ * <p>The default {@link AbstractRepository} implementation of this method
+ * is equivalent to:</p>
+ *
+ * <p><code>return (this.retrieve(identifier) != null)</code></p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @return <b>true</b> if this {@link Repository} contains a {@link Document}
+ * associated with the specified identifier.
+ */
+ public boolean contains(String identifier) {
+ if (identifier == null) return false;
+ try {
+ return (this.retrieve(identifier) != null);
+ } catch (IOException exception) {
+ return (false);
+ }
+ }
+
+ /**
+ * <p>Store the specified {@link Document} in this {@link Repository}
+ * associating it with the specified unique identifier.</p>
+ *
+ * <p>If another {@link Document} existed with the same identifier, their
+ * contents will be compared and the {@link #doStore(String, Document)} method
+ * (and consequently all {@link RepositoryListener} notification) will be
+ * invoked <b>only</b> if the old and new contents differ.</p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @param document the {@link Document} to store.
+ * @return a copy of the previously stored {@link Document} or <b>null</b> if
+ * the {@link Document} did not exist in this {@link Repository}.
+ * @throws NullPointerException if one of the parameters was <b>null</b>.
+ * @throws UnsupportedOperationException if this {@link Repository} is immutable.
+ * @throws IOException if an I/O error occurred retrieving the {@link Document}.
+ * @throws SAXException if a SAX error occurred processing the content.
+ */
+ public Document store(String identifier, Document document)
+ throws UnsupportedOperationException, IOException, SAXException {
+ if (identifier == null) throw new NullPointerException("Null identifier");
+ if (document == null) throw new NullPointerException("Null document");
+ Log log = this.getLogger();
+
+ /* Create an in-memory representation of the old version for checks */
+ Document previous = this.retrieve(identifier);
+ if (previous != null) {
+ Date lastmodified = previous.getLastModified();
+ BufferedDocument buffered = new BufferedDocument(lastmodified);
+ previous.process(buffered.read());
+ previous = buffered;
+
+ /* If no modifications were introduced, well, forget about it */
+ if (buffered.compare(document)) {
+ log.debug("Not storing unmodified document \"" + identifier + "\"");
+ return document;
+ }
+ }
+
+ /* Store locally this document */
+ String message = (previous == null ? "new" : "modified");
+ log.debug("Storing " + message + " document \"" + identifier + "\"");
+ this.doStore(identifier, document);
+
+ /* Notify all listeners */
+ RepositoryListener list[] = new RepositoryListener[this.listeners.size()];
+ list = (RepositoryListener[]) this.listeners.toArray(list);
+ for (int x = 0; x < list.length; x ++) try {
+ list[x].documentModified(this, identifier, previous);
+ } catch (Throwable throwable) {
+ log.error("Exception thrown notifying listener", throwable);
+ }
+
+ /* All done */
+ return previous;
+ }
+
+ /**
+ * <p>Delete the specified {@link Document} from this {@link Repository}.</p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @return a copy of the deleted {@link Document} or <b>null</b> if
+ * the {@link Document} did not exist in this {@link Repository}.
+ * @throws NullPointerException if one of the parameters was <b>null</b>.
+ * @throws UnsupportedOperationException if this {@link Repository} is immutable.
+ * @throws IOException if an I/O error occurred removing the {@link Document}.
+ * @throws SAXException if a SAX error occurred processing the content.
+ */
+ public Document delete(String identifier)
+ throws UnsupportedOperationException, IOException, SAXException {
+ if (identifier == null) throw new NullPointerException("Null identifier");
+ Log log = this.getLogger();
+
+ /* Create an in-memory representation of the old version */
+ Document previous = this.retrieve(identifier);
+ if (previous == null) return null;
+
+ Date lastmodified = previous.getLastModified();
+ BufferedDocument buffered = new BufferedDocument(lastmodified);
+ previous.process(buffered.read());
+ previous = buffered;
+
+ /* Delete locally the document */
+ log.debug("Deleting document \"" + identifier + "\"");
+ this.doDelete(identifier);
+
+ /* Notify all listeners */
+ RepositoryListener list[] = new RepositoryListener[this.listeners.size()];
+ list = (RepositoryListener[]) this.listeners.toArray(list);
+ for (int x = 0; x < list.length; x ++) try {
+ list[x].documentDeleted(this, identifier, previous);
+ } catch (Throwable throwable) {
+ log.error("Exception thrown notifying listener", throwable);
+ }
+
+ /* All done */
+ return previous;
+ }
+
+ /**
+ * <p>Register a new {@link RepositoryListener} listening to events generated
+ * by this {@link Repository}.</p>
+ *
+ * @param listener the {@link RepositoryListener} to be added.
+ */
+ public synchronized void addRepositoryListener(RepositoryListener listener) {
+ this.listeners.add(listener);
+ }
+
+ /**
+ * <p>De-register a previously registered {@link RepositoryListener}.</p>
+ *
+ * @param listener the {@link RepositoryListener} to be removed.
+ */
+ public synchronized void removeRepositoryListener(RepositoryListener listener) {
+ this.listeners.remove(listener);
+ }
+
+}
Added: cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/BufferedDocument.java
==============================================================================
--- (empty file)
+++ cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/BufferedDocument.java Sun Nov 7 16:35:38 2004
@@ -0,0 +1,539 @@
+/* =============================================================================== *
+ * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use *
+ * this file except in compliance with the License. You may obtain a copy of the *
+ * License at <http://www.apache.org/licenses/LICENSE-2.0>. *
+ * *
+ * Unless required by applicable law or agreed to in writing, software distributed *
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR *
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations under the License. *
+ * =============================================================================== */
+package org.apache.cocoon.components.repository;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.LocatorImpl;
+
+/**
+ * <p>A simple implementation of the {@link Document} interface backed by an
+ * in-memory SAX events buffer.</p>
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache
+ * Software Foundation</a>. All rights reserved.
+ */
+public class BufferedDocument implements Document {
+
+ /** <p>The last modified date of this document (if known).</p> */
+ private Date lastmodified = null;
+ /** <p>The DOM node containing the full XML {@link Document}.</p> */
+ private Buffer buffer = null;
+
+ /**
+ * <p>Create a new {@link BufferedDocument} instance.</p>
+ */
+ public BufferedDocument(Date lastmodified) {
+ this.lastmodified = lastmodified;
+ this.buffer = new Buffer();
+ }
+
+ /**
+ * <p>Return the {@link Date} when this {@link Document} was last modified.</p>
+ *
+ * @return a {@link Date} instance or <b>null</b> if the last modified date was
+ * not known.
+ */
+ public Date getLastModified() {
+ return this.lastmodified;
+ }
+
+ /**
+ * <p>Process the contents of this {@link Document} by triggering SAX events
+ * into the specified {@link ContentHandler}.</p>
+ *
+ * @throws IOException if an I/O error occurred processing the content.
+ * @throws SAXException if a SAX error occurred processing the content.
+ * @throws IllegalStateException if {@link #read()} was never called or its
+ * returned {@link ContentHandler} did not
+ * process the document entirely.
+ */
+ public void process(ContentHandler handler)
+ throws IOException, SAXException {
+ if (! this.buffer.isSealed()) {
+ throw new IllegalStateException("No content available");
+ }
+ if (handler == null) return;
+ this.buffer.replay(handler);
+ }
+
+ /**
+ * <p>Return a {@link ContentHandler} which can be used to build the XML
+ * content of this {@link BufferedDocument} instance.</p>
+ *
+ * @throws IOException if an I/O error occurred processing the content.
+ * @throws SAXException if a SAX error occurred processing the content.
+ * @throws IllegalStateException if {@link #read()} was alread called and the
+ * returned {@link ContentHandler} already
+ * processed the document entirely.
+ */
+ public ContentHandler read()
+ throws SAXException {
+ if (this.buffer.isSealed()) {
+ throw new IllegalStateException("Content already read");
+ }
+ return this.buffer;
+ }
+
+ /**
+ * <p>Compare the contents of this {@link BufferedDocument} with the contents
+ * of another {@link Document} instance.</p>
+ *
+ * @param document a {@link Document} instance whose content must be compared.
+ * @return <b>true</b> if the two {@link Document} instances have the same
+ * content, <b>false</b> otherwise.
+ */
+ public boolean compare(Document document) {
+ if (document == this) return true;
+ if (document == null) return false;
+
+ /* Check if we can already have access to the SAX buffer */
+ if (document instanceof BufferedDocument) {
+ return this.buffer.equals(((BufferedDocument)document).buffer);
+ }
+
+ /* Create a new buffer and compare */
+ try {
+ Buffer buffer = new Buffer();
+ document.process(buffer);
+ return this.buffer.equals(buffer);
+ } catch (Exception exception) {
+ return false;
+ }
+ }
+
+ /* =========================================================================== */
+ /* SAX BUFFER IMPLEMENTATION */
+ /* =========================================================================== */
+
+ private class Buffer implements ContentHandler {
+
+ private Locator locator = null;
+ private List tokens = null;
+ private boolean sealed = false;
+
+ /**
+ * <p>Create a new {@link Buffer} instance.</p>
+ */
+ public Buffer() {
+ this.tokens = new ArrayList();
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ if (! this.sealed) throw new IllegalStateException("Buffer not sealed");
+
+ TokenLocator locator = new TokenLocator();
+ handler.setDocumentLocator(locator);
+
+ Iterator iterator = this.tokens.iterator();
+ while (iterator.hasNext()) {
+ Token token = (Token) iterator.next();
+ locator.setToken(token);
+ token.replay(handler);
+ }
+ }
+
+ public boolean isSealed() {
+ return this.sealed;
+ }
+
+ public boolean equals(Object object) {
+ if (! this.sealed) throw new IllegalStateException("Buffer not sealed");
+ if (object == this) return true;
+ if (object == null) return false;
+ if (!(object instanceof Buffer)) return false;
+
+ /* Check the buffer status */
+ Buffer buffer = (Buffer) object;
+ if (!buffer.isSealed()) return(false);
+
+ /* Create copies of the two tokens arrays */
+ ArrayList list1 = new ArrayList(this.tokens);
+ ArrayList list2 = new ArrayList(buffer.tokens);
+
+ /* Strip out ignorable whitespace (well, it's ignorable) */
+ Iterator iterator = list1.iterator();
+ while (iterator.hasNext()) {
+ Token token = (Token) iterator.next();
+ if (token instanceof IgnorableWhitespace) iterator.remove();
+ }
+ iterator = list2.iterator();
+ while (iterator.hasNext()) {
+ Token token = (Token) iterator.next();
+ if (token instanceof IgnorableWhitespace) iterator.remove();
+ }
+
+ /* Default list comparation */
+ return(list1.equals(list2));
+ }
+
+ public int hashCode() {
+ if (! this.sealed) throw new IllegalStateException("Buffer not sealed");
+ return (this.tokens.hashCode());
+ }
+
+ /* ======================================================================= */
+ /* CONTENTHANDLER METHODS */
+ /* ======================================================================= */
+
+ public void setDocumentLocator(Locator locator) {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.locator = locator;
+ }
+
+ public void startDocument()
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.tokens.add(new StartDocument(this.locator));
+ }
+
+ public void endDocument()
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.tokens.add(new EndDocument(this.locator));
+ this.sealed = true;
+ }
+
+ public void startPrefixMapping(String prefix, String uri)
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.tokens.add(new StartPrefixMapping(this.locator, prefix, uri));
+ }
+
+ public void endPrefixMapping(String prefix)
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.tokens.add(new EndPrefixMapping(this.locator, prefix));
+ }
+
+ public void startElement(String uri, String loc, String qlf, Attributes att)
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.tokens.add(new StartElement(this.locator, uri, loc, qlf, att));
+ }
+
+ public void endElement(String uri, String loc, String qlf)
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.tokens.add(new EndElement(this.locator, uri, loc, qlf));
+ }
+
+ public void characters(char buf[], int off, int len)
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ String value = new String(buf, off, len);
+ int last = this.tokens.size() - 1;
+ Token token = (Token)this.tokens.get(last);
+ if (token instanceof Characters) {
+ value = token.values[0] + value;
+ this.tokens.remove(last);
+ }
+ this.tokens.add(new Characters(this.locator, value));
+ }
+
+ public void ignorableWhitespace(char buf[], int off, int len)
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+
+ String value = new String(buf, off, len);
+ int last = this.tokens.size() - 1;
+ Token token = (Token)this.tokens.get(last);
+ if (token instanceof IgnorableWhitespace) {
+ value = token.values[0] + value;
+ this.tokens.remove(last);
+ }
+ this.tokens.add(new IgnorableWhitespace(this.locator, value));
+ }
+
+ public void processingInstruction(String target, String data)
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.tokens.add(new ProcessingInstruction(this.locator, target, data));
+ }
+
+ public void skippedEntity(String name)
+ throws SAXException {
+ if (this.sealed) throw new IllegalStateException("Buffer sealed");
+ this.tokens.add(new SkippedEntity(this.locator, name));
+ }
+ }
+
+ /* =========================================================================== */
+ /* SAX TOKENS IMPLEMENTATION */
+ /* =========================================================================== */
+
+ private static abstract class Token extends LocatorImpl {
+
+ protected String values[] = null;
+ private int hash = 0;
+
+ private Token(Locator locator, String values[]) {
+ if (locator != null) {
+ this.setPublicId(locator.getPublicId());
+ this.setSystemId(locator.getSystemId());
+ this.setLineNumber(locator.getLineNumber());
+ this.setColumnNumber(locator.getColumnNumber());
+ }
+
+ this.values = (values == null ? new String[0] : values);
+ this.hash = 31 + this.getClass().hashCode();
+ for (int x = 0; x < this.values.length; x ++) {
+ String val = this.values[x];
+ this.hash = 31 * this.hash + (val == null ? 0 : val.hashCode());
+ }
+ }
+
+ public int hashCode() {
+ return(this.hash);
+ }
+
+ public boolean equals(Object object) {
+ if (object == this) return true;
+ if (object == null) return false;
+ if (! this.getClass().equals(object.getClass())) return false;
+
+ Token token = (Token) object;
+ if (this.values.length != token.values.length) return false;
+ for (int x = 0; x < this.values.length; x ++) {
+ String v1 = this.values[x];
+ String v2 = token.values[x];
+ if (v1 == null ? v2 == null : v1.equals(v2)) continue;
+ return(false);
+ }
+ return(true);
+ }
+
+ public abstract void replay(ContentHandler handler)
+ throws SAXException;
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class StartDocument extends Token {
+
+ private StartDocument(Locator locator) {
+ super(locator, null);
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ handler.startDocument();
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class EndDocument extends Token {
+
+ private EndDocument(Locator locator) {
+ super(locator, null);
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ handler.endDocument();
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class StartPrefixMapping extends Token {
+
+ private StartPrefixMapping(Locator locator, String prefix, String uri) {
+ super(locator, new String [] { prefix, uri });
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ handler.startPrefixMapping(this.values[0], this.values[1]);
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class EndPrefixMapping extends Token {
+
+ private EndPrefixMapping(Locator locator, String prefix) {
+ super(locator, new String [] { prefix });
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ handler.endPrefixMapping(this.values[0]);
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class StartElement extends Token {
+
+ private Attributes att = null;
+
+ private StartElement(Locator locator, String uri, String loc, String qlf, Attributes att) {
+ super(locator, new String [] { uri, loc, qlf });
+ this.att = (att == null ? new AttributesImpl() : new AttributesImpl(att));
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ handler.startElement(this.values[0], this.values[1], this.values[2], this.att);
+ }
+
+ public boolean equals(Object object) {
+ if (! super.equals(object)) return false;
+
+ StartElement k = (StartElement) object;
+ Attributes a = k.att;
+ if (a.getLength() != this.att.getLength()) return false;
+ for (int x = 0; x < a.getLength(); x++) {
+ String u = a.getURI(x);
+ String l = a.getLocalName(x);
+ String q = a.getQName(x);
+ String t1 = a.getType(x);
+ String v1 = a.getValue(x);
+ int z = this.att.getIndex(q);
+ if (z < 0) z = this.att.getIndex(u, l);
+ if (z < 0) return (false);
+ String t2 = this.att.getType(z);
+ String v2 = this.att.getValue(z);
+ boolean t = (t1 == null ? t2 == null : t1.equals(t2));
+ boolean v = (v1 == null ? v2 == null : v1.equals(v2));
+ if (t && v) continue;
+ return(false);
+ }
+ return(true);
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class EndElement extends Token {
+
+ private EndElement(Locator locator, String uri, String loc, String qlf) {
+ super(locator, new String [] { uri, loc, qlf } );
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ handler.endElement(this.values[0], this.values[1], this.values[2]);
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class Characters extends Token {
+
+ private Characters(Locator locator, String value) {
+ super(locator, new String [] { value });
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ if (this.values[0] == null) return;
+ char data[] = this.values[0].toCharArray();
+ handler.characters(data, 0, data.length);
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class IgnorableWhitespace extends Token {
+
+ private IgnorableWhitespace(Locator locator, String value) {
+ super(locator, new String [] { value });
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ if (this.values[0] == null) return;
+ char data[] = this.values[0].toCharArray();
+ handler.ignorableWhitespace(data, 0, data.length);
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class ProcessingInstruction extends Token {
+
+ private ProcessingInstruction(Locator locator, String target, String data) {
+ super(locator, new String [] { target, data });
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ handler.processingInstruction(this.values[0], this.values[1]);
+ }
+ }
+
+ /* --------------------------------------------------------------------------- */
+
+ private static final class SkippedEntity extends Token {
+
+ private SkippedEntity(Locator locator, String name) {
+ super(locator, new String [] { name });
+ }
+
+ public void replay(ContentHandler handler)
+ throws SAXException {
+ handler.skippedEntity(this.values[0]);
+ }
+ }
+
+ /* =========================================================================== */
+ /* LOCATOR IMPLEMENTATION */
+ /* =========================================================================== */
+
+ private static class TokenLocator implements Locator {
+
+ private Token token = null;
+
+ private TokenLocator() {
+ super();
+ }
+
+ public String getPublicId() {
+ if (this.token == null) return null;
+ return this.token.getPublicId();
+ }
+
+ public String getSystemId() {
+ if (this.token == null) return null;
+ return this.token.getSystemId();
+ }
+
+ public int getLineNumber() {
+ if (this.token == null) return -1;
+ return this.token.getLineNumber();
+ }
+
+ public int getColumnNumber() {
+ if (this.token == null) return -1;
+ return this.token.getColumnNumber();
+ }
+
+ protected void setToken(Token token) {
+ this.token = token;
+ }
+ }
+}
Added: cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/Document.java
==============================================================================
--- (empty file)
+++ cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/Document.java Sun Nov 7 16:35:38 2004
@@ -0,0 +1,49 @@
+/* =============================================================================== *
+ * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use *
+ * this file except in compliance with the License. You may obtain a copy of the *
+ * License at <http://www.apache.org/licenses/LICENSE-2.0>. *
+ * *
+ * Unless required by applicable law or agreed to in writing, software distributed *
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR *
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations under the License. *
+ * =============================================================================== */
+package org.apache.cocoon.components.repository;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * <p>The {@link Document} interface abstracts the concept of a simple XML document
+ * contained in a {@link Repository}.</p>
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache
+ * Software Foundation</a>. All rights reserved.
+ */
+public interface Document {
+
+ /**
+ * <p>Return the {@link Date} when this {@link Document} was last modified.</p>
+ *
+ * @return a {@link Date} instance or <b>null</b> if the last modified date was
+ * not known.
+ */
+ public Date getLastModified();
+
+ /**
+ * <p>Process the contents of this {@link Document} by triggering SAX events
+ * into the specified {@link ContentHandler}.</p>
+ *
+ * @throws IOException if an I/O error occurred processing the content.
+ * @throws SAXException if a SAX error occurred processing the content.
+ */
+ public void process(ContentHandler handler)
+ throws IOException, SAXException;
+
+}
Added: cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/Repository.java
==============================================================================
--- (empty file)
+++ cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/Repository.java Sun Nov 7 16:35:38 2004
@@ -0,0 +1,99 @@
+/* =============================================================================== *
+ * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use *
+ * this file except in compliance with the License. You may obtain a copy of the *
+ * License at <http://www.apache.org/licenses/LICENSE-2.0>. *
+ * *
+ * Unless required by applicable law or agreed to in writing, software distributed *
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR *
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations under the License. *
+ * =============================================================================== */
+package org.apache.cocoon.components.repository;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.xml.sax.SAXException;
+
+/**
+ * <p>The {@link Repository} interface describes a simple object providing access to
+ * a collection of {@link Document}s.</p>
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache
+ * Software Foundation</a>. All rights reserved.
+ */
+public interface Repository {
+
+ /**
+ * <p>Check if a {@link Document} is contained in this {@link Repository}.</p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @return <b>true</b> if this {@link Repository} contains a {@link Document}
+ * associated with the specified identifier.
+ */
+ public boolean contains(String identifier);
+
+ /**
+ * <p>Retrieve the specified {@link Document}.</p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @return a {@link Document} instance or <b>null</b> if not found.
+ * @throws IOException if an I/O error occurred retrieving the {@link Document}.
+ */
+ public Document retrieve(String identifier)
+ throws IOException;
+
+ /**
+ * <p>Store the specified {@link Document} in this {@link Repository}
+ * associating it with the specified unique identifier.</p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @param document the {@link Document} to store.
+ * @return a copy of the previously stored {@link Document} or <b>null</b> if
+ * the {@link Document} did not exist in this {@link Repository}.
+ * @throws UnsupportedOperationException if this {@link Repository} is immutable.
+ * @throws IOException if an I/O error occurred retrieving the {@link Document}.
+ * @throws SAXException if a SAX error occurred processing the content.
+ */
+ public Document store(String identifier, Document document)
+ throws UnsupportedOperationException, IOException, SAXException;
+
+ /**
+ * <p>Delete the specified {@link Document} from this {@link Repository}.</p>
+ *
+ * @param identifier the unique identifier of the document.
+ * @return a copy of the deleted {@link Document} or <b>null</b> if
+ * the {@link Document} did not exist in this {@link Repository}.
+ * @throws UnsupportedOperationException if this {@link Repository} is immutable.
+ * @throws IOException if an I/O error occurred removing the {@link Document}.
+ * @throws SAXException if a SAX error occurred processing the content.
+ */
+ public Document delete(String identifier)
+ throws UnsupportedOperationException, IOException, SAXException;
+
+ /**
+ * <p>Retrieve an {@link Iterator} over all {@link Document} identifiers
+ * contained in this {@link Repository}.</p>
+ *
+ * @return a <b>non-null</b> {@link Iterator} instance.
+ */
+ public Iterator documents();
+
+ /**
+ * <p>Register a new {@link RepositoryListener} listening to events generated
+ * by this {@link Repository}.</p>
+ *
+ * @param listener the {@link RepositoryListener} to be added.
+ */
+ public void addRepositoryListener(RepositoryListener listener);
+
+ /**
+ * <p>De-register a previously registered {@link RepositoryListener}.</p>
+ *
+ * @param listener the {@link RepositoryListener} to be removed.
+ */
+ public void removeRepositoryListener(RepositoryListener listener);
+}
Added: cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/RepositoryListener.java
==============================================================================
--- (empty file)
+++ cocoon/whiteboard/kernel/sources/contracts/repository/src/org/apache/cocoon/components/repository/RepositoryListener.java Sun Nov 7 16:35:38 2004
@@ -0,0 +1,52 @@
+/* =============================================================================== *
+ * Copyright (C) 1999-2004, The Apache Software Foundation. All rights reserved. *
+ * *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use *
+ * this file except in compliance with the License. You may obtain a copy of the *
+ * License at <http://www.apache.org/licenses/LICENSE-2.0>. *
+ * *
+ * Unless required by applicable law or agreed to in writing, software distributed *
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR *
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations under the License. *
+ * =============================================================================== */
+package org.apache.cocoon.components.repository;
+
+import java.util.EventListener;
+
+/**
+ * <p>The {@link RepositoryListener} interface describes a simple object that,
+ * once registered in the {@link Repository}, will be notified of events.</p>
+ *
+ * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>
+ * @author Copyright © 2000-2004 <a href="http://www.apache.org/">The Apache
+ * Software Foundation</a>. All rights reserved.
+ */
+public interface RepositoryListener extends EventListener {
+
+ /**
+ * <p>Receive notification of the addition or modification of a {@link Document}
+ * in a {@link Repository}.</p>
+ *
+ * <p>If a {@link Document} was added to the repository, then the third
+ * parameter <code>previous</code> will be set to <b>null</b> otherwise it
+ * will contain an in-memory copy of the previous (overwritten) document.</p>
+ *
+ * @param repository the {@link Repository} instance of the {@link Document}.
+ * @param identifier the unique identifier of the modified {@link Document}.
+ * @param previous an in-memory copy of the previous {@link Document} version.
+ */
+ public void documentModified(Repository repository, String identifier,
+ Document previous);
+
+ /**
+ * <p>Receive notification of the deletion of a {@link Document} from a
+ * {@link Repository}.</p>
+ *
+ * @param repository the {@link Repository} instance of the {@link Document}.
+ * @param identifier the unique identifier of the deleted {@link Document}.
+ * @param previous an in-memory copy of the deleted {@link Document}.
+ */
+ public void documentDeleted(Repository repository, String identifier,
+ Document previous);
+}