You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2008/10/07 14:43:57 UTC
svn commit: r702459 [2/2] - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/cluster/
main/java/org/apache/jackrabbit/core/journal/
main/java/org/apache/jackrabbit/core/state/
test/java/org/apache/jackrabbit/core/cluster/ ...
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java?rev=702459&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java Tue Oct 7 05:43:55 2008
@@ -0,0 +1,412 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.core.cluster;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.cluster.SimpleEventListener.LockEvent;
+import org.apache.jackrabbit.core.cluster.SimpleEventListener.NamespaceEvent;
+import org.apache.jackrabbit.core.cluster.SimpleEventListener.NodeTypeEvent;
+import org.apache.jackrabbit.core.cluster.SimpleEventListener.UnlockEvent;
+import org.apache.jackrabbit.core.cluster.SimpleEventListener.UpdateEvent;
+import org.apache.jackrabbit.core.config.BeanConfig;
+import org.apache.jackrabbit.core.config.ClusterConfig;
+import org.apache.jackrabbit.core.config.JournalConfig;
+import org.apache.jackrabbit.core.journal.MemoryJournal;
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+import org.apache.jackrabbit.core.observation.EventState;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.PathFactory;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.apache.jackrabbit.test.JUnitTest;
+import org.apache.jackrabbit.uuid.UUID;
+
+/**
+ * Test cases for cluster record production and consumption. Verifies that
+ * cluster record serialization and deseralization is correct.
+ */
+public class ClusterRecordTest extends JUnitTest {
+
+ /**
+ * Defaut workspace name.
+ */
+ private static final String DEFAULT_WORKSPACE = "default";
+
+ /**
+ * Default user.
+ */
+ private static final String DEFAULT_USER = "admin";
+
+ /**
+ * Root node id.
+ */
+ private static final NodeId ROOT_NODE_ID = RepositoryImpl.ROOT_NODE_ID;
+
+ /**
+ * Default sync delay: 5 seconds.
+ */
+ private static final long SYNC_DELAY = 5000;
+
+ /**
+ * Default session, used for event state creation.
+ */
+ private final Session session = new ClusterSession(DEFAULT_USER);
+
+ /**
+ * Name factory.
+ */
+ private NameFactory nameFactory = NameFactoryImpl.getInstance();
+
+ /**
+ * Path factory.
+ */
+ private PathFactory pathFactory = PathFactoryImpl.getInstance();
+
+ /**
+ * Records shared among multiple memory journals.
+ */
+ private ArrayList records = new ArrayList();
+
+ /**
+ * Master.
+ */
+ private ClusterNode master;
+
+ /**
+ * Slave.
+ */
+ private ClusterNode slave;
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void setUp() throws Exception {
+ master = createClusterNode("master", records);
+ master.start();
+
+ slave = createClusterNode("slave", records);
+
+ super.setUp();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void tearDown() throws Exception {
+ if (master != null) {
+ master.stop();
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Test producing and consuming an update.
+ * @throws Exception
+ */
+ public void testUpdateOperation() throws Exception {
+ NodeState n1 = createNodeState();
+ NodeState n2 = createNodeState();
+ NodeState n3 = createNodeState();
+ PropertyState p1 = createPropertyState(n1.getNodeId(), "{}a");
+ PropertyState p2 = createPropertyState(n2.getNodeId(), "{}b");
+
+ ChangeLog changes = new ChangeLog();
+ changes.added(n1);
+ changes.added(p1);
+ changes.deleted(p2);
+ changes.modified(n2);
+ changes.deleted(n3);
+
+ List events = new ArrayList();
+ events.add(createEventState(n1, Event.NODE_ADDED, "{}n1"));
+ events.add(createEventState(p1, n1, Event.PROPERTY_ADDED));
+ events.add(createEventState(p2, n2, Event.PROPERTY_REMOVED));
+ events.add(createEventState(n3, Event.NODE_REMOVED, "{}n3"));
+
+ UpdateEvent update = new UpdateEvent(changes, events);
+
+ UpdateEventChannel channel = master.createUpdateChannel(DEFAULT_WORKSPACE);
+ channel.updateCreated(update);
+ channel.updatePrepared(update);
+ channel.updateCommitted(update);
+
+ SimpleEventListener listener = new SimpleEventListener();
+ slave.createUpdateChannel(DEFAULT_WORKSPACE).setListener(listener);
+ slave.sync();
+
+ assertEquals(1, listener.getClusterEvents().size());
+ assertEquals(listener.getClusterEvents().get(0), update);
+ }
+
+ /**
+ * Test producing and consuming a lock operation.
+ * @throws Exception
+ */
+ public void testLockOperation() throws Exception {
+ LockEvent event = new LockEvent(new NodeId(UUID.randomUUID()), true, "admin");
+
+ master.createLockChannel(DEFAULT_WORKSPACE).create(event.getNodeId(),
+ event.isDeep(), event.getUserId()).ended(true);
+
+ SimpleEventListener listener = new SimpleEventListener();
+ slave.createLockChannel(DEFAULT_WORKSPACE).setListener(listener);
+ slave.sync();
+
+ assertEquals(1, listener.getClusterEvents().size());
+ assertEquals(listener.getClusterEvents().get(0), event);
+ }
+
+ /**
+ * Test producing and consuming an unlock operation.
+ * @throws Exception
+ */
+ public void testUnlockOperation() throws Exception {
+ UnlockEvent event = new UnlockEvent(new NodeId(UUID.randomUUID()));
+
+ master.createLockChannel(DEFAULT_WORKSPACE).create(event.getNodeId()).ended(true);
+
+ SimpleEventListener listener = new SimpleEventListener();
+ slave.createLockChannel(DEFAULT_WORKSPACE).setListener(listener);
+ slave.sync();
+
+ assertEquals(1, listener.getClusterEvents().size());
+ assertEquals(listener.getClusterEvents().get(0), event);
+ }
+
+ /**
+ * Test producing and consuming a node type registration.
+ * @throws Exception
+ */
+ public void testNodeTypeRegistration() throws Exception {
+ NodeTypeDef ntd = new NodeTypeDef();
+ ntd.setName(NameFactoryImpl.getInstance().create("", "test"));
+ ntd.setSupertypes(new Name[]{NameConstants.NT_BASE});
+
+ ArrayList list = new ArrayList();
+ list.add(ntd);
+
+ NodeTypeEvent event = new NodeTypeEvent(NodeTypeEvent.REGISTER, list);
+ master.registered(event.getCollection());
+
+ SimpleEventListener listener = new SimpleEventListener();
+ slave.setListener((NodeTypeEventListener) listener);
+ slave.sync();
+
+ assertEquals(1, listener.getClusterEvents().size());
+ assertEquals(listener.getClusterEvents().get(0), event);
+ }
+
+ /**
+ * Test producing and consuming a node type reregistration.
+ * @throws Exception
+ */
+ public void testNodeTypeReregistration() throws Exception {
+ NodeTypeDef ntd = new NodeTypeDef();
+ ntd.setName(NameFactoryImpl.getInstance().create("", "test"));
+ ntd.setSupertypes(new Name[]{NameConstants.NT_BASE});
+
+ ArrayList list = new ArrayList();
+ list.add(ntd);
+
+ NodeTypeEvent event = new NodeTypeEvent(NodeTypeEvent.REREGISTER, list);
+ master.reregistered(ntd);
+
+ SimpleEventListener listener = new SimpleEventListener();
+ slave.setListener((NodeTypeEventListener) listener);
+ slave.sync();
+
+ assertEquals(1, listener.getClusterEvents().size());
+ assertEquals(listener.getClusterEvents().get(0), event);
+ }
+
+ /**
+ * Test producing and consuming a node type unregistration.
+ * @throws Exception
+ */
+ public void testNodeTypeUnregistration() throws Exception {
+ Name name = NameFactoryImpl.getInstance().create("", "test");
+
+ ArrayList list = new ArrayList();
+ list.add(name);
+
+ NodeTypeEvent event = new NodeTypeEvent(NodeTypeEvent.UNREGISTER, list);
+ master.unregistered(list);
+
+ SimpleEventListener listener = new SimpleEventListener();
+ slave.setListener((NodeTypeEventListener) listener);
+ slave.sync();
+
+ assertEquals(1, listener.getClusterEvents().size());
+ assertEquals(listener.getClusterEvents().get(0), event);
+ }
+
+ /**
+ * Test producing and consuming a namespace registration.
+ * @throws Exception
+ */
+ public void testNamespaceRegistration() throws Exception {
+ NamespaceEvent event = new NamespaceEvent(null, "test", "http://www.test.com");
+
+ master.remapped(event.getOldPrefix(), event.getNewPrefix(), event.getUri());
+
+ SimpleEventListener listener = new SimpleEventListener();
+ slave.setListener((NamespaceEventListener) listener);
+ slave.sync();
+
+ assertEquals(1, listener.getClusterEvents().size());
+ assertEquals(listener.getClusterEvents().get(0), event);
+ }
+
+ /**
+ * Test producing and consuming a namespace unregistration.
+ * @throws Exception
+ */
+ public void testNamespaceUnregistration() throws Exception {
+ NamespaceEvent event = new NamespaceEvent("test", null, null);
+
+ master.remapped(event.getOldPrefix(), event.getNewPrefix(), event.getUri());
+
+ SimpleEventListener listener = new SimpleEventListener();
+ slave.setListener((NamespaceEventListener) listener);
+ slave.sync();
+
+ assertEquals(1, listener.getClusterEvents().size());
+ assertEquals(listener.getClusterEvents().get(0), event);
+ }
+
+ /**
+ * Create a cluster node, with a memory journal referencing a list of records.
+ *
+ * @param id cluster node id
+ * @param records memory journal's list of records
+ */
+ private ClusterNode createClusterNode(String id, ArrayList records)
+ throws ClusterException {
+
+ BeanConfig bc = new BeanConfig(MemoryJournal.class.getName(), new Properties());
+ JournalConfig jc = new JournalConfig(bc);
+ ClusterConfig cc = new ClusterConfig(id, SYNC_DELAY, jc);
+ SimpleClusterContext context = new SimpleClusterContext(cc, null);
+
+ ClusterNode clusterNode = new ClusterNode();
+ clusterNode.init(context);
+ if (records != null) {
+ ((MemoryJournal) clusterNode.getJournal()).setRecords(records);
+ }
+ return clusterNode;
+ }
+
+ /**
+ * Create a node state.
+ *
+ * @return node state
+ */
+ private NodeState createNodeState() {
+ Name ntName = nameFactory.create("{}testnt");
+ NodeState n = new NodeState(
+ new NodeId(UUID.randomUUID()), ntName,
+ ROOT_NODE_ID, NodeState.STATUS_EXISTING, false);
+ n.setMixinTypeNames(Collections.EMPTY_SET);
+ return n;
+ }
+
+ /**
+ * Create a property state.
+ *
+ * @param parentId parent node id
+ * @param name property name
+ */
+ private PropertyState createPropertyState(NodeId parentId, String name) {
+ Name propName = nameFactory.create(name);
+ return new PropertyState(
+ new PropertyId(parentId, propName),
+ NodeState.STATUS_EXISTING, false);
+ }
+
+ /**
+ * Create an event state for an operation on a node.
+ *
+ * @param n node state
+ * @param type <code>Event.NODE_ADDED</code> or <code>Event.NODE_REMOVED</code>
+ * @param name node name
+ * @return event state
+ */
+ private EventState createEventState(NodeState n, int type, String name) {
+ Path.Element relPath = pathFactory.createElement(nameFactory.create(name));
+
+ switch (type) {
+ case Event.NODE_ADDED:
+ return EventState.childNodeAdded(
+ n.getParentId(), pathFactory.getRootPath(),
+ n.getNodeId(), relPath, n.getNodeTypeName(),
+ n.getMixinTypeNames(), session);
+ case Event.NODE_REMOVED:
+ return EventState.childNodeRemoved(
+ n.getParentId(), pathFactory.getRootPath(),
+ n.getNodeId(), relPath, n.getNodeTypeName(),
+ n.getMixinTypeNames(), session);
+ }
+ return null;
+ }
+
+ /**
+ * Create an event state for a property operation.
+ *
+ * @param n node state
+ * @param type <code>Event.NODE_ADDED</code> or <code>Event.NODE_REMOVED</code>
+ * @param name property name
+ * @return event state
+ */
+ private EventState createEventState(PropertyState p, NodeState parent, int type) {
+ Path.Element relPath = pathFactory.createElement(p.getName());
+
+ switch (type) {
+ case Event.PROPERTY_ADDED:
+ return EventState.propertyAdded(
+ p.getParentId(), pathFactory.getRootPath(), relPath,
+ parent.getNodeTypeName(), parent.getMixinTypeNames(),
+ session);
+ case Event.PROPERTY_CHANGED:
+ return EventState.propertyChanged(
+ p.getParentId(), pathFactory.getRootPath(), relPath,
+ parent.getNodeTypeName(), parent.getMixinTypeNames(),
+ session);
+ case Event.PROPERTY_REMOVED:
+ return EventState.propertyRemoved(
+ p.getParentId(), pathFactory.getRootPath(), relPath,
+ parent.getNodeTypeName(), parent.getMixinTypeNames(),
+ session);
+ }
+ return null;
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterTest.java?rev=702459&r1=702458&r2=702459&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterTest.java Tue Oct 7 05:43:55 2008
@@ -23,6 +23,7 @@
import org.apache.jackrabbit.core.config.BeanConfig;
import org.apache.jackrabbit.core.config.ClusterConfig;
import org.apache.jackrabbit.core.config.JournalConfig;
+import org.apache.jackrabbit.core.journal.MemoryJournal;
import org.apache.jackrabbit.test.JUnitTest;
/**
@@ -30,10 +31,14 @@
*/
public class ClusterTest extends JUnitTest {
- /** Repository home value. */
+ /**
+ * Repository home value.
+ */
private static final String REPOSITORY_HOME = "target/repository_for_test";
- /** Repository home. */
+ /**
+ * Repository home.
+ */
private File repositoryHome;
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleClusterContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleClusterContext.java?rev=702459&r1=702458&r2=702459&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleClusterContext.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleClusterContext.java Tue Oct 7 05:43:55 2008
@@ -21,18 +21,29 @@
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.core.config.ClusterConfig;
+import org.apache.jackrabbit.core.nodetype.xml.SimpleNamespaceRegistry;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
+import org.apache.jackrabbit.spi.commons.namespace.RegistryNamespaceResolver;
/**
* Simple cluster context, providing only limited functionality.
*/
public class SimpleClusterContext implements ClusterContext {
- /** Cluster config. */
- private ClusterConfig cc;
+ /**
+ * Cluster config.
+ */
+ private final ClusterConfig cc;
- /** Repository home. */
- private File repositoryHome;
+ /**
+ * Repository home.
+ */
+ private final File repositoryHome;
+
+ /**
+ * Namespace resolver.
+ */
+ private final NamespaceResolver nsResolver;
/**
* Create a new instance of this class.
@@ -43,8 +54,12 @@
public SimpleClusterContext(ClusterConfig cc, File repositoryHome) {
this.cc = cc;
this.repositoryHome = repositoryHome;
+
+ nsResolver = new RegistryNamespaceResolver(new SimpleNamespaceRegistry());
}
+ //----------------------------------------------------------- ClusterContext
+
/**
* {@inheritDoc}
*/
@@ -56,7 +71,7 @@
* {@inheritDoc}
*/
public NamespaceResolver getNamespaceResolver() {
- return null;
+ return nsResolver;
}
/**
@@ -69,10 +84,14 @@
/**
* {@inheritDoc}
*/
- public void lockEventsReady(String workspace) throws RepositoryException {}
+ public void lockEventsReady(String workspace) throws RepositoryException {
+ // nothing to be done here
+ }
/**
* {@inheritDoc}
*/
- public void updateEventsReady(String workspace) throws RepositoryException {}
+ public void updateEventsReady(String workspace) throws RepositoryException {
+ // nothing to be done here
+ }
}
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleEventListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleEventListener.java?rev=702459&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleEventListener.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleEventListener.java Tue Oct 7 05:43:55 2008
@@ -0,0 +1,597 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.core.cluster;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.cluster.LockEventListener;
+import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.ItemState;
+
+/**
+ * Simple event listener that can be registered for all cluster event listener
+ * types and records external events in an array list.
+ */
+public class SimpleEventListener implements LockEventListener,
+ NodeTypeEventListener, NamespaceEventListener, UpdateEventListener {
+
+ /**
+ * List of cluster events received.
+ */
+ public List clusterEvents = new ArrayList();
+
+ //-------------------------------------------------------- LockEventListener
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalLock(NodeId nodeId, boolean isDeep, String userId)
+ throws RepositoryException {
+
+ clusterEvents.add(new LockEvent(nodeId, isDeep, userId));
+ }
+
+ /**
+ * Lock event auxiliary class.
+ */
+ public static class LockEvent {
+
+ /**
+ * Node id.
+ */
+ private final NodeId nodeId;
+
+ /**
+ * Deep flag.
+ */
+ private final boolean isDeep;
+
+ /**
+ * User id.
+ */
+ private final String userId;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param nodeId node id
+ * @param isDeep deep flag
+ * @param userId user id
+ */
+ public LockEvent(NodeId nodeId, boolean isDeep, String userId) {
+ this.nodeId = nodeId;
+ this.isDeep = isDeep;
+ this.userId = userId;
+ }
+
+ /**
+ * Return the node id.
+ *
+ * @return the node id
+ */
+ public NodeId getNodeId() {
+ return nodeId;
+ }
+
+ /**
+ * Return a flag indicating whether the lock is deep.
+ *
+ * @return <code>true</code> if the lock is deep;
+ * <code>false</code> otherwise
+ */
+ public boolean isDeep() {
+ return isDeep;
+ }
+
+ /**
+ * Return the user owning the lock.
+ *
+ * @return user id
+ */
+ public String getUserId() {
+ return userId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return nodeId.hashCode() ^ userId.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof LockEvent) {
+ LockEvent other = (LockEvent) obj;
+ return nodeId.equals(other.nodeId) &&
+ isDeep == other.isDeep &&
+ userId.equals(other.userId);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalUnlock(NodeId nodeId) throws RepositoryException {
+ clusterEvents.add(new UnlockEvent(nodeId));
+ }
+
+ /**
+ * Unlock event auxiliary class.
+ */
+ public static class UnlockEvent {
+
+ /**
+ * Node id.
+ */
+ private final NodeId nodeId;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param nodeId node id
+ */
+ public UnlockEvent(NodeId nodeId) {
+ this.nodeId = nodeId;
+ }
+
+ /**
+ * Return the node id.
+ *
+ * @return node id
+ */
+ public NodeId getNodeId() {
+ return nodeId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return nodeId.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof UnlockEvent) {
+ UnlockEvent other = (UnlockEvent) obj;
+ return nodeId.equals(other.nodeId);
+ }
+ return false;
+ }
+ }
+
+ //---------------------------------------------------- NodeTypeEventListener
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalRegistered(Collection ntDefs)
+ throws RepositoryException, InvalidNodeTypeDefException {
+
+ clusterEvents.add(new NodeTypeEvent(NodeTypeEvent.REGISTER, ntDefs));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalReregistered(NodeTypeDef ntDef)
+ throws NoSuchNodeTypeException, InvalidNodeTypeDefException,
+ RepositoryException {
+
+ ArrayList ntDefs = new ArrayList();
+ ntDefs.add(ntDef);
+
+ clusterEvents.add(new NodeTypeEvent(NodeTypeEvent.REREGISTER, ntDefs));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalUnregistered(Collection ntNames)
+ throws RepositoryException, NoSuchNodeTypeException {
+
+ clusterEvents.add(new NodeTypeEvent(NodeTypeEvent.UNREGISTER, ntNames));
+ }
+
+ /**
+ * Node type event auxiliary class.
+ */
+ public static class NodeTypeEvent {
+
+ /**
+ * Operation type: registration.
+ */
+ public static final int REGISTER = NodeTypeRecord.REGISTER;
+
+ /**
+ * Operation type: re-registration.
+ */
+ public static final int REREGISTER = NodeTypeRecord.REREGISTER;
+
+ /**
+ * Operation type: unregistration.
+ */
+ public static final int UNREGISTER = NodeTypeRecord.UNREGISTER;
+
+ /**
+ * Operation.
+ */
+ private int operation;
+
+ /**
+ * Collection of node type definitions or node type names.
+ */
+ private Collection collection;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param operation operation
+ * @param collection collection of node type definitions or node
+ * type names
+ */
+ public NodeTypeEvent(int operation, Collection collection) {
+ this.operation = operation;
+ this.collection = collection;
+ }
+
+ /**
+ * Return the operation.
+ *
+ * @return operation
+ */
+ public int getOperation() {
+ return operation;
+ }
+
+ /**
+ * Return the collection.
+ *
+ * @return collection
+ */
+ public Collection getCollection() {
+ return collection;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return operation ^ collection.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof NodeTypeEvent) {
+ NodeTypeEvent other = (NodeTypeEvent) obj;
+ return operation == other.operation &&
+ SimpleEventListener.equals(collection, other.collection);
+ }
+ return false;
+ }
+ }
+
+ //--------------------------------------------------- NamespaceEventListener
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalRemap(String oldPrefix, String newPrefix, String uri)
+ throws RepositoryException {
+
+ clusterEvents.add(new NamespaceEvent(oldPrefix, newPrefix, uri));
+ }
+
+ /**
+ * Namespace event auxiliary class.
+ */
+ public static class NamespaceEvent {
+
+ /**
+ * Old prefix.
+ */
+ private final String oldPrefix;
+
+ /**
+ * New prefix.
+ */
+ private final String newPrefix;
+
+ /**
+ * URI.
+ */
+ private final String uri;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param oldPrefix old prefix
+ * @param newPrefix new prefix
+ * @param uri URI
+ */
+ public NamespaceEvent(String oldPrefix, String newPrefix, String uri) {
+ this.oldPrefix = oldPrefix;
+ this.newPrefix = newPrefix;
+ this.uri = uri;
+ }
+
+ /**
+ * Return the old prefix.
+ *
+ * @return old prefix
+ */
+ public String getOldPrefix() {
+ return oldPrefix;
+ }
+
+ /**
+ * Return the new prefix.
+ *
+ * @return new prefix
+ */
+ public String getNewPrefix() {
+ return newPrefix;
+ }
+
+ /**
+ * Return the URI.
+ *
+ * @return URI
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ int hashCode = 0;
+ if (oldPrefix != null) {
+ hashCode ^= oldPrefix.hashCode();
+ }
+ if (newPrefix != null) {
+ hashCode ^= newPrefix.hashCode();
+ }
+ if (uri != null) {
+ hashCode ^= uri.hashCode();
+ }
+ return hashCode;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof NamespaceEvent) {
+ NamespaceEvent other = (NamespaceEvent) obj;
+ return SimpleEventListener.equals(oldPrefix, other.oldPrefix) &&
+ SimpleEventListener.equals(newPrefix, other.newPrefix) &&
+ SimpleEventListener.equals(uri, other.uri);
+ }
+ return false;
+ }
+ }
+
+ //------------------------------------------------------ UpdateEventListener
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalUpdate(ChangeLog changes, List events)
+ throws RepositoryException {
+
+ clusterEvents.add(new UpdateEvent(changes, events));
+
+ }
+
+ /**
+ * Update event auxiliary class.
+ */
+ public static class UpdateEvent implements Update {
+
+ /**
+ * Change log.
+ */
+ private final ChangeLog changes;
+
+ /**
+ * List of <code>EventState</code>s.
+ */
+ private final List events;
+
+ /**
+ * Attributes to be stored.
+ */
+ private final transient Map attributes = new HashMap();
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param changes change log
+ * @param events list of <code>EventState</code>s
+ */
+ public UpdateEvent(ChangeLog changes, List events) {
+ this.changes = changes;
+ this.events = events;
+ }
+
+ /**
+ * Return the change log.
+ *
+ * @return the change log
+ */
+ public ChangeLog getChanges() {
+ return changes;
+ }
+
+ /**
+ * Return the list of <code>EventState</code>s
+ *
+ * @return list of <code>EventState</code>s
+ */
+ public List getEvents() {
+ return events;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setAttribute(String name, Object value) {
+ attributes.put(name, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getAttribute(String name) {
+ return attributes.get(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode() {
+ return changes.hashCode() ^ events.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof UpdateEvent) {
+ UpdateEvent other = (UpdateEvent) obj;
+ return SimpleEventListener.equals(changes, other.changes) &&
+ SimpleEventListener.equals(events, other.events);
+ }
+ return false;
+ }
+
+ }
+
+ /**
+ * Return the collected cluster events.
+ *
+ * @return cluster events
+ */
+ public List getClusterEvents() {
+ return Collections.unmodifiableList(clusterEvents);
+ }
+
+ /**
+ * Check whether two objects are equals, allowing <code>null</code> values.
+ *
+ * @param o1 object 1
+ * @param o2 object 2
+ * @return <code>true</code> if they are equal; <code>false</code> otherwise
+ */
+ private static boolean equals(Object o1, Object o2) {
+ if (o1 == null) {
+ return o2 == null;
+ } else {
+ return o1.equals(o2);
+ }
+ }
+
+ /**
+ * Check whether two collections contain the same elements. Made necessary
+ * because the <code>Collections.unmodifiableXXX</code> methods do not
+ * return objects that override <code>equals</code> and <code>hashCode</code>.
+ *
+ * @param c1 collection 1
+ * @param c2 collection 2
+ * @return <code>true</code> if they are equal; <code>false</code> otherwise
+ */
+ private static boolean equals(Collection c1, Collection c2) {
+ if (c1.size() != c2.size()) {
+ return false;
+ }
+ Iterator iter1 = c1.iterator();
+ Iterator iter2 = c2.iterator();
+
+ while (iter1.hasNext()) {
+ Object o1 = iter1.next();
+ Object o2 = iter2.next();
+ if (!o1.equals(o2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check whether two changes logs contain the same elements. Not feasible
+ * by comparing the maps because <code>ItemState</code>s do not override
+ * {@link Object#equals(Object)}.
+ *
+ * @param changes1 change log
+ * @param changes2 change log
+ * @return <code>true</code> if the change logs are equals;
+ * <code>false</code> otherwise.
+ */
+ private static boolean equals(ChangeLog changes1, ChangeLog changes2) {
+ return equals(changes1.addedStates(), changes2.addedStates()) &&
+ equals(changes1.deletedStates(), changes2.deletedStates()) &&
+ equals(changes1.modifiedStates(), changes2.modifiedStates());
+ }
+
+ /**
+ * Check whether two iterators return the same item states, where "same"
+ * means having the same <code>ItemId</code>
+ * @param iter1 first iterator
+ * @param iter2 second iterator
+ * @return <code>true</code> if the two iterators are equal;
+ * <code>false</code> otherwise
+ */
+ private static boolean equals(Iterator iter1, Iterator iter2) {
+ for (;;) {
+ if (!iter1.hasNext() && !iter2.hasNext()) {
+ return true;
+ }
+ if (iter1.hasNext() && !iter2.hasNext()) {
+ return false;
+ }
+ if (!iter1.hasNext() && iter2.hasNext()) {
+ return false;
+ }
+ ItemState state1 = (ItemState) iter1.next();
+ ItemState state2 = (ItemState) iter2.next();
+ return state1.getId().equals(state2.getId());
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleEventListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/SimpleEventListener.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/TestAll.java?rev=702459&r1=702458&r2=702459&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/TestAll.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/TestAll.java Tue Oct 7 05:43:55 2008
@@ -37,6 +37,7 @@
public static Test suite() {
TestSuite suite = new TestSuite();
+ suite.addTestSuite(ClusterRecordTest.class);
suite.addTestSuite(ClusterTest.class);
return suite;
Copied: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java (from r701066, jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/MemoryJournal.java)
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java?p2=jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java&p1=jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/MemoryJournal.java&r1=701066&r2=702459&rev=702459&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/MemoryJournal.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java Tue Oct 7 05:43:55 2008
@@ -14,34 +14,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.core.cluster;
+package org.apache.jackrabbit.core.journal;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import org.apache.jackrabbit.core.journal.AbstractJournal;
+import org.apache.jackrabbit.core.journal.AppendRecord;
import org.apache.jackrabbit.core.journal.InstanceRevision;
-import org.apache.jackrabbit.core.journal.Journal;
import org.apache.jackrabbit.core.journal.JournalException;
-import org.apache.jackrabbit.core.journal.RecordConsumer;
-import org.apache.jackrabbit.core.journal.RecordProducer;
+import org.apache.jackrabbit.core.journal.RecordIterator;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
/**
* Memory-based journal, useful for testing purposes only.
*/
-public class MemoryJournal implements Journal {
+public class MemoryJournal extends AbstractJournal {
- /** Revision. */
+ /**
+ * Revision.
+ */
private InstanceRevision revision = new MemoryRevision();
- /** Journal id. */
- private String id;
-
/**
- * Return this journal's id.
- *
- * @return id
+ * List of records.
*/
- public String getId() {
- return id;
- }
+ private ArrayList records = new ArrayList();
/**
* {@inheritDoc}
@@ -53,40 +55,198 @@
/**
* {@inheritDoc}
*/
- public RecordProducer getProducer(String identifier)
+ public void init(String id, NamespaceResolver resolver)
throws JournalException {
- throw new JournalException("Not implemented");
+ super.init(id, resolver);
}
/**
* {@inheritDoc}
*/
- public void init(String id, NamespaceResolver resolver)
+ protected void doLock() throws JournalException {
+ // not implemented
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void append(AppendRecord record, InputStream in, int length)
throws JournalException {
- this.id = id;
+ byte[] data = new byte[length];
+ int off = 0;
+
+ while (off < data.length) {
+ try {
+ int len = in.read(data, off, data.length - off);
+ if (len < 0) {
+ String msg = "Unexpected end of record after " + off + " bytes.";
+ throw new JournalException(msg);
+ }
+ off += len;
+ } catch (IOException e) {
+ String msg = "I/O error after " + off + " bytes.";
+ throw new JournalException(msg, e);
+ }
+ }
+ records.add(new MemoryRecord(getId(), record.getProducerId(), data));
+ record.setRevision(records.size());
}
/**
* {@inheritDoc}
*/
- public void register(RecordConsumer consumer) throws JournalException {}
+ protected void doUnlock(boolean successful) {
+ // not implemented
+ }
/**
* {@inheritDoc}
*/
- public void sync() throws JournalException {}
+ protected RecordIterator getRecords(long startRevision)
+ throws JournalException {
+
+ startRevision = Math.max(startRevision, 0);
+ long stopRevision = records.size();
+
+ return new MemoryRecordIterator(startRevision, stopRevision);
+ }
/**
- * {@inheritDoc}
+ * Set records. Used to share records between two journal implementations.
+ *
+ * @param records array list that should back up this memory journal
*/
- public boolean unregister(RecordConsumer consumer) {
- return false;
+ public void setRecords(ArrayList records) {
+ this.records = records;
}
/**
* {@inheritDoc}
*/
- public void close() {}
+ public void close() {
+ // nothing to be done here
+ }
+
+
+ /**
+ * Memory record.
+ */
+ public class MemoryRecord {
+
+ /**
+ * Journal id.
+ */
+ private String journalId;
+
+ /**
+ * Producer id.
+ */
+ private String producerId;
+
+ /**
+ * Data.
+ */
+ private byte[] data;
+
+ /**
+ * Create a new instance of this class
+ *
+ * @param journalId journal id
+ * @param producerId producer id
+ * @param data data
+ */
+ public MemoryRecord(String journalId, String producerId, byte[] data) {
+ this.journalId = journalId;
+ this.producerId = producerId;
+ this.data = data;
+ }
+
+ /**
+ * Return the journal id.
+ *
+ * @return the journal id
+ */
+ public String getJournalId() {
+ return journalId;
+ }
+
+ /**
+ * Return the producer id.
+ *
+ * @return the producer id
+ */
+ public String getProducerId() {
+ return producerId;
+ }
+
+ /**
+ * Return the data.
+ *
+ * @return data
+ */
+ public byte[] getData() {
+ return data;
+ }
+ }
+
+ /**
+ * Record iterator implementation.
+ */
+ public class MemoryRecordIterator implements RecordIterator {
+
+ /**
+ * Current revision.
+ */
+ private long revision;
+
+ /**
+ * Last revision.
+ */
+ private final long stopRevision;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param startRevision start revision
+ * @param stopRevision stop revision
+ */
+ public MemoryRecordIterator(long startRevision, long stopRevision) {
+ this.revision = startRevision;
+ this.stopRevision = stopRevision;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNext() {
+ return revision < stopRevision;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Record nextRecord() throws NoSuchElementException,
+ JournalException {
+
+ int index = (int) revision;
+ MemoryRecord record = (MemoryRecord) records.get(index);
+
+ byte[] data = record.getData();
+ DataInputStream dataIn = new DataInputStream(
+ new ByteArrayInputStream(data));
+
+ return new ReadRecord(record.getJournalId(), record.getProducerId(),
+ ++revision, dataIn, data.length,
+ getResolver(), getNamePathResolver());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() {
+ // nothing to be done here
+ }
+ }
}
Copied: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryRevision.java (from r701066, jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/MemoryRevision.java)
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryRevision.java?p2=jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryRevision.java&p1=jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/MemoryRevision.java&r1=701066&r2=702459&rev=702459&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/MemoryRevision.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryRevision.java Tue Oct 7 05:43:55 2008
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.core.cluster;
+package org.apache.jackrabbit.core.journal;
import org.apache.jackrabbit.core.journal.InstanceRevision;
import org.apache.jackrabbit.core.journal.JournalException;
@@ -24,7 +24,9 @@
*/
public class MemoryRevision implements InstanceRevision {
- /** Revision. */
+ /**
+ * Revision.
+ */
private long revision;
/**
@@ -44,5 +46,7 @@
/**
* {@inheritDoc}
*/
- public void close() {}
+ public void close() {
+ // nothing to be done here
+ }
}
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/TestAll.java?rev=702459&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/TestAll.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/TestAll.java Tue Oct 7 05:43:55 2008
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.core.journal;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Collects all test classes setting up test data in the workspace. This test
+ * data is specific to Jackrabbit and will probably not work in other
+ * implementations.
+ */
+public class TestAll extends TestCase {
+
+ /**
+ * Returns a <code>Test</code> suite that executes all tests inside this
+ * package.
+ *
+ * @return a <code>Test</code> suite that executes all tests inside this
+ * package.
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+
+ suite.addTestSuite(FileJournalTest.class);
+
+ return suite;
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/TestAll.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/TestAll.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/xml/SimpleNamespaceRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/xml/SimpleNamespaceRegistry.java?rev=702459&r1=702458&r2=702459&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/xml/SimpleNamespaceRegistry.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/nodetype/xml/SimpleNamespaceRegistry.java Tue Oct 7 05:43:55 2008
@@ -26,7 +26,7 @@
* Simple utility implementation of the NamespaceRegistry interface.
* Used by the node type formatter test cases.
*/
-class SimpleNamespaceRegistry implements NamespaceRegistry {
+public class SimpleNamespaceRegistry implements NamespaceRegistry {
/** Map from namespace prefixes to namespace URIs. */
private final Properties prefixToURI = new Properties();