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 [EMAIL PROTECTED] Repository} interface.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">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 [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Document} in this [EMAIL PROTECTED] Repository} + * associating it with the specified unique identifier.</p> + * + * <p>The default [EMAIL PROTECTED] AbstractRepository} implementation of this method + * always throws an [EMAIL PROTECTED] UnsupportedOperationException}.</p> + * + * @param identifier the unique identifier of the document. + * @param document the [EMAIL PROTECTED] Document} to store. + * @throws UnsupportedOperationException if this [EMAIL PROTECTED] Repository} is immutable. + * @throws IOException if an I/O error occurred retrieving the [EMAIL PROTECTED] Document}. + */ + protected void doStore(String identifier, Document document) + throws UnsupportedOperationException, IOException { + throw new UnsupportedOperationException("Store operation not supported"); + } + + /** + * <p>Delete the specified [EMAIL PROTECTED] Document} from this [EMAIL PROTECTED] Repository}.</p> + * + * <p>The default [EMAIL PROTECTED] AbstractRepository} implementation of this method + * always throws an [EMAIL PROTECTED] UnsupportedOperationException}.</p> + * + * @param identifier the unique identifier of the document. + * @throws UnsupportedOperationException if this [EMAIL PROTECTED] Repository} is immutable. + * @throws IOException if an I/O error occurred removing the [EMAIL PROTECTED] Document}. + */ + protected void doDelete(String identifier) + throws UnsupportedOperationException, IOException { + throw new UnsupportedOperationException("Delete operation not supported"); + } + + /* =========================================================================== */ + /* PROTECTED METHODS */ + /* =========================================================================== */ + + /** + * <p>Return the currently configured [EMAIL PROTECTED] Log} instance.</p> + * + * @return a <b>non null</b> [EMAIL PROTECTED] Log} instance. + */ + protected Log getLogger() { + return this.logger; + } + + /** + * <p>Return an [EMAIL PROTECTED] Iterator} over all known [EMAIL PROTECTED] RepositoryListener}s.</p> + * + * @return a <b>non null</b> [EMAIL PROTECTED] Iterator} instance. + */ + protected Iterator getRepositoryListeners() { + return this.listeners.iterator(); + } + + /* =========================================================================== */ + /* IMPLEMENTED METHODS */ + /* =========================================================================== */ + + /** + * <p>Check if a [EMAIL PROTECTED] Document} is contained in this [EMAIL PROTECTED] Repository}.</p> + * + * <p>The default [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Repository} contains a [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Document} in this [EMAIL PROTECTED] Repository} + * associating it with the specified unique identifier.</p> + * + * <p>If another [EMAIL PROTECTED] Document} existed with the same identifier, their + * contents will be compared and the [EMAIL PROTECTED] #doStore(String, Document)} method + * (and consequently all [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Document} to store. + * @return a copy of the previously stored [EMAIL PROTECTED] Document} or <b>null</b> if + * the [EMAIL PROTECTED] Document} did not exist in this [EMAIL PROTECTED] Repository}. + * @throws NullPointerException if one of the parameters was <b>null</b>. + * @throws UnsupportedOperationException if this [EMAIL PROTECTED] Repository} is immutable. + * @throws IOException if an I/O error occurred retrieving the [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Document} from this [EMAIL PROTECTED] Repository}.</p> + * + * @param identifier the unique identifier of the document. + * @return a copy of the deleted [EMAIL PROTECTED] Document} or <b>null</b> if + * the [EMAIL PROTECTED] Document} did not exist in this [EMAIL PROTECTED] Repository}. + * @throws NullPointerException if one of the parameters was <b>null</b>. + * @throws UnsupportedOperationException if this [EMAIL PROTECTED] Repository} is immutable. + * @throws IOException if an I/O error occurred removing the [EMAIL PROTECTED] 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 [EMAIL PROTECTED] RepositoryListener} listening to events generated + * by this [EMAIL PROTECTED] Repository}.</p> + * + * @param listener the [EMAIL PROTECTED] RepositoryListener} to be added. + */ + public synchronized void addRepositoryListener(RepositoryListener listener) { + this.listeners.add(listener); + } + + /** + * <p>De-register a previously registered [EMAIL PROTECTED] RepositoryListener}.</p> + * + * @param listener the [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Document} interface backed by an + * in-memory SAX events buffer.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">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 [EMAIL PROTECTED] Document}.</p> */ + private Buffer buffer = null; + + /** + * <p>Create a new [EMAIL PROTECTED] BufferedDocument} instance.</p> + */ + public BufferedDocument(Date lastmodified) { + this.lastmodified = lastmodified; + this.buffer = new Buffer(); + } + + /** + * <p>Return the [EMAIL PROTECTED] Date} when this [EMAIL PROTECTED] Document} was last modified.</p> + * + * @return a [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Document} by triggering SAX events + * into the specified [EMAIL PROTECTED] 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 [EMAIL PROTECTED] #read()} was never called or its + * returned [EMAIL PROTECTED] 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 [EMAIL PROTECTED] ContentHandler} which can be used to build the XML + * content of this [EMAIL PROTECTED] 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 [EMAIL PROTECTED] #read()} was alread called and the + * returned [EMAIL PROTECTED] 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 [EMAIL PROTECTED] BufferedDocument} with the contents + * of another [EMAIL PROTECTED] Document} instance.</p> + * + * @param document a [EMAIL PROTECTED] Document} instance whose content must be compared. + * @return <b>true</b> if the two [EMAIL PROTECTED] 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 [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Document} interface abstracts the concept of a simple XML document + * contained in a [EMAIL PROTECTED] Repository}.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">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 [EMAIL PROTECTED] Date} when this [EMAIL PROTECTED] Document} was last modified.</p> + * + * @return a [EMAIL PROTECTED] Date} instance or <b>null</b> if the last modified date was + * not known. + */ + public Date getLastModified(); + + /** + * <p>Process the contents of this [EMAIL PROTECTED] Document} by triggering SAX events + * into the specified [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Repository} interface describes a simple object providing access to + * a collection of [EMAIL PROTECTED] Document}s.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">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 [EMAIL PROTECTED] Document} is contained in this [EMAIL PROTECTED] Repository}.</p> + * + * @param identifier the unique identifier of the document. + * @return <b>true</b> if this [EMAIL PROTECTED] Repository} contains a [EMAIL PROTECTED] Document} + * associated with the specified identifier. + */ + public boolean contains(String identifier); + + /** + * <p>Retrieve the specified [EMAIL PROTECTED] Document}.</p> + * + * @param identifier the unique identifier of the document. + * @return a [EMAIL PROTECTED] Document} instance or <b>null</b> if not found. + * @throws IOException if an I/O error occurred retrieving the [EMAIL PROTECTED] Document}. + */ + public Document retrieve(String identifier) + throws IOException; + + /** + * <p>Store the specified [EMAIL PROTECTED] Document} in this [EMAIL PROTECTED] Repository} + * associating it with the specified unique identifier.</p> + * + * @param identifier the unique identifier of the document. + * @param document the [EMAIL PROTECTED] Document} to store. + * @return a copy of the previously stored [EMAIL PROTECTED] Document} or <b>null</b> if + * the [EMAIL PROTECTED] Document} did not exist in this [EMAIL PROTECTED] Repository}. + * @throws UnsupportedOperationException if this [EMAIL PROTECTED] Repository} is immutable. + * @throws IOException if an I/O error occurred retrieving the [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Document} from this [EMAIL PROTECTED] Repository}.</p> + * + * @param identifier the unique identifier of the document. + * @return a copy of the deleted [EMAIL PROTECTED] Document} or <b>null</b> if + * the [EMAIL PROTECTED] Document} did not exist in this [EMAIL PROTECTED] Repository}. + * @throws UnsupportedOperationException if this [EMAIL PROTECTED] Repository} is immutable. + * @throws IOException if an I/O error occurred removing the [EMAIL PROTECTED] Document}. + * @throws SAXException if a SAX error occurred processing the content. + */ + public Document delete(String identifier) + throws UnsupportedOperationException, IOException, SAXException; + + /** + * <p>Retrieve an [EMAIL PROTECTED] Iterator} over all [EMAIL PROTECTED] Document} identifiers + * contained in this [EMAIL PROTECTED] Repository}.</p> + * + * @return a <b>non-null</b> [EMAIL PROTECTED] Iterator} instance. + */ + public Iterator documents(); + + /** + * <p>Register a new [EMAIL PROTECTED] RepositoryListener} listening to events generated + * by this [EMAIL PROTECTED] Repository}.</p> + * + * @param listener the [EMAIL PROTECTED] RepositoryListener} to be added. + */ + public void addRepositoryListener(RepositoryListener listener); + + /** + * <p>De-register a previously registered [EMAIL PROTECTED] RepositoryListener}.</p> + * + * @param listener the [EMAIL PROTECTED] 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 [EMAIL PROTECTED] RepositoryListener} interface describes a simple object that, + * once registered in the [EMAIL PROTECTED] Repository}, will be notified of events.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">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 [EMAIL PROTECTED] Document} + * in a [EMAIL PROTECTED] Repository}.</p> + * + * <p>If a [EMAIL PROTECTED] 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 [EMAIL PROTECTED] Repository} instance of the [EMAIL PROTECTED] Document}. + * @param identifier the unique identifier of the modified [EMAIL PROTECTED] Document}. + * @param previous an in-memory copy of the previous [EMAIL PROTECTED] Document} version. + */ + public void documentModified(Repository repository, String identifier, + Document previous); + + /** + * <p>Receive notification of the deletion of a [EMAIL PROTECTED] Document} from a + * [EMAIL PROTECTED] Repository}.</p> + * + * @param repository the [EMAIL PROTECTED] Repository} instance of the [EMAIL PROTECTED] Document}. + * @param identifier the unique identifier of the deleted [EMAIL PROTECTED] Document}. + * @param previous an in-memory copy of the deleted [EMAIL PROTECTED] Document}. + */ + public void documentDeleted(Repository repository, String identifier, + Document previous); +}
