You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by st...@apache.org on 2004/07/21 18:58:04 UTC

cvs commit: jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/util ValueHelper.java

stefan      2004/07/21 09:58:04

  Modified:    proposals/jcrri/src/org/apache/slide/jcr/core ItemImpl.java
                        ItemManager.java NodeImpl.java RepositoryImpl.java
                        SystemTicket.java Test.java TicketImpl.java
                        WorkspaceImpl.java
               proposals/jcrri/src/org/apache/slide/jcr/core/nodetype
                        NodeTypeManagerImpl.java NodeTypeRegistry.java
                        builtin_nodetypes.xml
               proposals/jcrri/src/org/apache/slide/jcr/core/state
                        ItemState.java PersistentItemStateManager.java
               proposals/jcrri/src/org/apache/slide/jcr/core/version
                        VersionImpl.java VersionManager.java
               proposals/jcrri/src/org/apache/slide/jcr/util
                        ValueHelper.java
  Log:
  jcrri
  
  Revision  Changes    Path
  1.14      +49 -27    jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/ItemImpl.java
  
  Index: ItemImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/ItemImpl.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- ItemImpl.java	20 Jul 2004 08:28:33 -0000	1.13
  +++ ItemImpl.java	21 Jul 2004 16:58:03 -0000	1.14
  @@ -33,6 +33,7 @@
   import org.apache.slide.jcr.core.state.*;
   import org.apache.slide.jcr.core.version.VersionImpl;
   import org.apache.slide.jcr.util.IteratorHelper;
  +import org.apache.slide.jcr.util.UUID;
   
   import javax.jcr.*;
   import javax.jcr.access.AccessDeniedException;
  @@ -212,12 +213,17 @@
        * (i.e. it has been temporarily rendered 'invalid').
        */
       private void notifyCreated() {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	ItemLifeCycleListener[] la = new ItemLifeCycleListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    ItemLifeCycleListener listener = (ItemLifeCycleListener) iter.next();
  -	    listener.itemCreated(this);
  +	    la[cnt++] = (ItemLifeCycleListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].itemCreated(this);
  +	    }
   	}
       }
   
  @@ -226,12 +232,17 @@
        * (i.e. it has been temporarily rendered 'invalid').
        */
       protected void notifyInvalidated() {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	ItemLifeCycleListener[] la = new ItemLifeCycleListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    ItemLifeCycleListener listener = (ItemLifeCycleListener) iter.next();
  -	    listener.itemInvalidated(id, this);
  +	    la[cnt++] = (ItemLifeCycleListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].itemInvalidated(id, this);
  +	    }
   	}
       }
   
  @@ -240,12 +251,17 @@
        * (i.e. it has been rendered 'valid' again).
        */
       protected void notifyResurrected() {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	ItemLifeCycleListener[] la = new ItemLifeCycleListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    ItemLifeCycleListener listener = (ItemLifeCycleListener) iter.next();
  -	    listener.itemResurrected(this);
  +	    la[cnt++] = (ItemLifeCycleListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].itemResurrected(this);
  +	    }
   	}
       }
   
  @@ -254,12 +270,17 @@
        * (i.e. it has been permanently rendered 'invalid').
        */
       protected void notifyDestroyed() {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	ItemLifeCycleListener[] la = new ItemLifeCycleListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    ItemLifeCycleListener listener = (ItemLifeCycleListener) iter.next();
  -	    listener.itemDestroyed(id, this);
  +	    la[cnt++] = (ItemLifeCycleListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].itemDestroyed(id, this);
  +	    }
   	}
       }
   
  @@ -493,9 +514,10 @@
   		NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId());
   		if (node.isNodeType(NodeTypeRegistry.MIX_VERSIONABLE)) {
   		    VersionHistory hist = rep.getVersionManager().createVersionHistory(node);
  -		    node.internalSetProperty(VersionImpl.PROPNAME_VERSION_HISTORY, InternalValue.create(hist.getUUID()));
  -		    node.internalSetProperty(VersionImpl.PROPNAME_BASE_VERSION, InternalValue.create(hist.getRootVersion().getUUID()));
  +		    node.internalSetProperty(VersionImpl.PROPNAME_VERSION_HISTORY, InternalValue.create(new UUID(hist.getUUID())));
  +		    node.internalSetProperty(VersionImpl.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(hist.getRootVersion().getUUID())));
   		    node.internalSetProperty(VersionImpl.PROPNAME_IS_CHECKED_OUT, InternalValue.create(true));
  +		    node.internalSetProperty(VersionImpl.PROPNAME_PREDESESSORS, new InternalValue[]{InternalValue.create(new UUID(hist.getRootVersion().getUUID()))});
   		}
   	    }
   	}
  @@ -507,7 +529,7 @@
        *
        * @return JCR path or some fallback value
        */
  -    protected String safeGetJCRPath() {
  +    public String safeGetJCRPath() {
   	return itemMgr.safeGetJCRPath(id);
       }
   
  @@ -850,8 +872,8 @@
   	}
   
   	// all changes are persisted, now dispatch events
  -	WorkspaceImpl ws = (WorkspaceImpl) ticket.getWorkspace();
  -	ws.getRepository().getObservationManagerFactory(ws.wsDef).dispatchEvents(events);
  +	WorkspaceImpl wsp = (WorkspaceImpl) ticket.getWorkspace();
  +	wsp.getRepository().getObservationManagerFactory(wsp.getName()).dispatchEvents(events);
       }
   
       /**
  
  
  
  1.10      +5 -2      jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/ItemManager.java
  
  Index: ItemManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/ItemManager.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- ItemManager.java	20 Jul 2004 08:28:33 -0000	1.9
  +++ ItemManager.java	21 Jul 2004 16:58:03 -0000	1.10
  @@ -31,6 +31,7 @@
   import org.apache.slide.jcr.core.state.*;
   import org.apache.slide.jcr.core.version.VersionHistoryImpl;
   import org.apache.slide.jcr.core.version.VersionImpl;
  +import org.apache.slide.jcr.core.version.FrozenNode;
   import org.apache.slide.jcr.util.IteratorHelper;
   
   import javax.jcr.*;
  @@ -364,6 +365,8 @@
   	// primary types (i.e. nt:version & nt:versionHistory)
   	if (state.getNodeTypeName().equals(NodeTypeRegistry.NT_VERSION_HISTORY)) {
   	    return new VersionHistoryImpl(this, ticket, id, state, def, listeners);
  +	} else if (state.getNodeTypeName().equals(NodeTypeRegistry.NT_FROZEN)) {
  +	    return new FrozenNode(this, ticket, id, state, def, listeners);
   	} else if (state.getNodeTypeName().equals(NodeTypeRegistry.NT_VERSION)) {
   	    return new VersionImpl(this, ticket, id, state, def, listeners);
   	} else {
  
  
  
  1.24      +46 -29    jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/NodeImpl.java
  
  Index: NodeImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/NodeImpl.java,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- NodeImpl.java	20 Jul 2004 08:28:33 -0000	1.23
  +++ NodeImpl.java	21 Jul 2004 16:58:03 -0000	1.24
  @@ -114,7 +114,7 @@
   	    // mix:referenceable node type
   	    if (name.equals(PROPNAME_UUID)) {
   		// jcr:uuid property
  -		genValues = new InternalValue[]{InternalValue.create(new UUID(((NodeState) state).getUUID()))};
  +		genValues = new InternalValue[]{InternalValue.create(((NodeState) state).getUUID())};
   	    }
   	} else if (nt.getQName().equals(NodeTypeRegistry.NT_HIERARCHYNODE)) {
   	    // nt:hierarchyNode node type
  @@ -159,7 +159,7 @@
   	    throws RepositoryException {
   	try {
   	    return (PropertyImpl) getProperty(name);
  -	} catch (PathNotFoundException pnfe) {
  +	} catch (ItemNotFoundException e) {
   	    // does not exist yet:
   	    // find definition for the specified property and create property
   	    PropertyDefImpl def = getApplicablePropertyDef(name, type);
  @@ -358,7 +358,7 @@
   	}
       }
   
  -    private NodeImpl internalAddNode(String relPath, NodeTypeImpl nodeType)
  +    protected NodeImpl internalAddNode(String relPath, NodeTypeImpl nodeType)
   	    throws ItemExistsException, PathNotFoundException,
   	    ConstraintViolationException, RepositoryException {
   	Path nodePath;
  @@ -603,6 +603,10 @@
   
       /**
        * Sets the internal value of a property without checking any constraints.
  +     * <p/>
  +     * Note that no type conversion is being performed, i.e. it's the caller's
  +     * responsibility to make sure the type of the given value is compatible
  +     * with the specified property's definition.
        *
        * @param name
        * @param value
  @@ -610,19 +614,17 @@
        * @throws ValueFormatException
        * @throws RepositoryException
        */
  -    protected Property internalSetProperty(QName name, InternalValue value)
  +    public Property internalSetProperty(QName name, InternalValue value)
   	    throws ValueFormatException, RepositoryException {
  -	// check state of this instance
  -	checkItemState();
  -
  -	int type = (value == null) ? PropertyType.STRING : value.getType();
  -	PropertyImpl prop = getOrCreateProperty(name, type);
  -	prop.internalSetValue(new InternalValue[]{value}, type);
  -	return prop;
  +	return internalSetProperty(name, new InternalValue[]{value});
       }
   
       /**
        * Sets the internal value of a property without checking any constraints.
  +     * <p/>
  +     * Note that no type conversion is being performed, i.e. it's the caller's
  +     * responsibility to make sure the type of the given values is compatible
  +     * with the specified property's definition.
        *
        * @param name
        * @param values
  @@ -1786,7 +1788,7 @@
   	    throws UnsupportedRepositoryOperationException, RepositoryException {
   	if (!isNodeType(NodeTypeRegistry.MIX_VERSIONABLE)) {
   	    String msg = "Unable to perform versioning operation on non versionable node: " + safeGetJCRPath();
  -	    log.warn(msg);
  +	    log.debug(msg);
   	    throw new UnsupportedRepositoryOperationException(msg);
   	}
       }
  @@ -1796,10 +1798,21 @@
        */
       public Version checkin()
   	    throws UnsupportedRepositoryOperationException, RepositoryException {
  -	checkVersionable();
  -
  -	// @todo implement versioning support
  -	throw new UnsupportedRepositoryOperationException();
  +	if (!isCheckedOut()) {
  +	    throw new VersionException("Node is not checked out.");
  +	}
  +	// check transient state
  +	if (isModified()) {
  +	    throw new IllegalStateException("Checkin not allowed on transient node.");
  +	}
  +	Version v = rep.getVersionManager().checkin(this);
  +	Property prop = internalSetProperty(VersionImpl.PROPNAME_IS_CHECKED_OUT, InternalValue.create(false));
  +	prop.save();
  +	prop = internalSetProperty(VersionImpl.PROPNAME_BASE_VERSION, InternalValue.create(new UUID(v.getUUID())));
  +	prop.save();
  +	prop = internalSetProperty(VersionImpl.PROPNAME_PREDESESSORS, new InternalValue[0]);
  +	prop.save();
  +	return v;
       }
   
       /**
  @@ -1807,10 +1820,21 @@
        */
       public void checkout()
   	    throws UnsupportedRepositoryOperationException, RepositoryException {
  -	checkVersionable();
  +	if (isCheckedOut()) {
  +	    throw new VersionException("Node already checked out.");
  +	}
  +	// check transient state
  +	if (isModified()) {
  +	    throw new IllegalStateException("Checkout not allowed on transient node.");
  +	}
  +	Property prop = internalSetProperty(VersionImpl.PROPNAME_IS_CHECKED_OUT, InternalValue.create(true));
  +	prop.save();
  +	prop = internalSetProperty(VersionImpl.PROPNAME_PREDESESSORS,
  +		new InternalValue[]{
  +		    InternalValue.create(new UUID(getBaseVersion().getUUID()))
  +		});
  +	prop.save();
   
  -	// @todo implement versioning support
  -	throw new UnsupportedRepositoryOperationException();
       }
   
       /**
  @@ -1866,12 +1890,7 @@
       public boolean isCheckedOut()
   	    throws UnsupportedRepositoryOperationException, RepositoryException {
   	checkVersionable();
  -
  -	try {
  -	    return getProperty(VersionImpl.PROPNAME_IS_CHECKED_OUT).getBoolean();
  -	} catch (ItemNotFoundException infe) {
  -	    return false;
  -	}
  +	return getProperty(VersionImpl.PROPNAME_IS_CHECKED_OUT).getBoolean();
       }
   
       /**
  @@ -1927,7 +1946,6 @@
       public VersionHistory getVersionHistory()
   	    throws UnsupportedRepositoryOperationException, RepositoryException {
   	checkVersionable();
  -
   	return rep.getVersionManager().getVersionHistory(this);
       }
   
  @@ -1937,7 +1955,6 @@
       public Version getBaseVersion()
   	    throws UnsupportedRepositoryOperationException, RepositoryException {
   	checkVersionable();
  -
   	return rep.getVersionManager().getBaseVersion(this);
       }
   
  
  
  
  1.16      +28 -24    jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/RepositoryImpl.java
  
  Index: RepositoryImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/RepositoryImpl.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- RepositoryImpl.java	20 Jul 2004 08:28:33 -0000	1.15
  +++ RepositoryImpl.java	21 Jul 2004 16:58:03 -0000	1.16
  @@ -275,13 +275,13 @@
   
   	// FIXME version manager should not operate on default workspace
   	// check system root node of system workspace
  -	TicketImpl sysTicket = getSystemTicket((WorkspaceDef) wspDefs.get(DEFAULT_WORKSPACE_NAME));
  +	TicketImpl sysTicket = getSystemTicket(DEFAULT_WORKSPACE_NAME);
   	if (!sysTicket.getRootNode().hasNode(SYSTEM_ROOT_NAME.toJCRName(sysTicket.getNamespaceResolver()))) {
   	    sysTicket.getRootNode().addNode(SYSTEM_ROOT_NAME.toJCRName(sysTicket.getNamespaceResolver()), NodeTypeRegistry.NT_UNSTRUCTURED.toJCRName(sysTicket.getNamespaceResolver()));
   	    sysTicket.getRootNode().save();
   	}
   	// init version manager
  -	vMgr = new VersionManager(getSystemTicket((WorkspaceDef) wspDefs.get(DEFAULT_WORKSPACE_NAME)));
  +	vMgr = new VersionManager(sysTicket);
   
   	// load repository properties
   	repProps = new Properties();
  @@ -294,7 +294,7 @@
   	// register as an event listener
   	Iterator iter = wspDefs.values().iterator();
   	while (iter.hasNext()) {
  -	    Ticket t = getSystemTicket((WorkspaceDef) iter.next());
  +	    Ticket t = getSystemTicket(((WorkspaceDef) iter.next()).getName());
   	    t.getWorkspace().getObservationManager().addEventListener(this,
   		    EventType.CHILD_NODE_ADDED | EventType.CHILD_NODE_REMOVED |
   		    EventType.PROPERTY_ADDED | EventType.PROPERTY_REMOVED,
  @@ -318,12 +318,15 @@
   	return rootNodeUUID;
       }
   
  -    synchronized PersistentItemStateManager getWorkspaceStateManager(WorkspaceDef wd)
  -	    throws RepositoryException {
  +    synchronized PersistentItemStateManager getWorkspaceStateManager(String workspaceName)
  +	    throws NoSuchWorkspaceException, RepositoryException {
  +	WorkspaceDef wd = (WorkspaceDef) wspDefs.get(workspaceName);
  +	if (wd == null) {
  +	    throw new NoSuchWorkspaceException(workspaceName);
  +	}
   	// get/create per named workspace (i.e. per physical storage) item state manager
  -	String wspName = wd.getName();
   	PersistentItemStateManager stateMgr =
  -		(PersistentItemStateManager) wspStateMgrs.get(wspName);
  +		(PersistentItemStateManager) wspStateMgrs.get(workspaceName);
   	if (stateMgr == null) {
   	    if (wd.isDynamic()) {
   /*
  @@ -347,30 +350,32 @@
   		    throw new RepositoryException(msg, ise);
   		}
   	    }
  -	    wspStateMgrs.put(wspName, stateMgr);
  +	    wspStateMgrs.put(workspaceName, stateMgr);
   	}
   	return stateMgr;
       }
   
  -    synchronized ObservationManagerFactory getObservationManagerFactory(WorkspaceDef wd) {
  -	String wspName = wd.getName();
  +    synchronized ObservationManagerFactory getObservationManagerFactory(String workspaceName)
  +	    throws NoSuchWorkspaceException {
  +	if (!wspDefs.containsKey(workspaceName)) {
  +	    throw new NoSuchWorkspaceException(workspaceName);
  +	}
   	ObservationManagerFactory obsMgr
  -		= (ObservationManagerFactory) wspObsMgrFactory.get(wspName);
  +		= (ObservationManagerFactory) wspObsMgrFactory.get(workspaceName);
   	if (obsMgr == null) {
   	    obsMgr = new ObservationManagerFactory();
  -	    wspObsMgrFactory.put(wspName, obsMgr);
  +	    wspObsMgrFactory.put(workspaceName, obsMgr);
   	}
   	return obsMgr;
       }
   
  -    synchronized SystemTicket getSystemTicket(WorkspaceDef wd)
  -	    throws RepositoryException {
  -	String wspName = wd.getName();
  +    synchronized SystemTicket getSystemTicket(String workspaceName)
  +	    throws NoSuchWorkspaceException, RepositoryException {
   	SystemTicket systemTicket
  -		= (SystemTicket) wspSystemTickets.get(wspName);
  +		= (SystemTicket) wspSystemTickets.get(workspaceName);
   	if (systemTicket == null) {
  -	    systemTicket = new SystemTicket(this, wd);
  -	    wspSystemTickets.put(wspName, systemTicket);
  +	    systemTicket = new SystemTicket(this, workspaceName);
  +	    wspSystemTickets.put(workspaceName, systemTicket);
   	}
   	return systemTicket;
       }
  @@ -521,14 +526,13 @@
   	if (workspaceName == null) {
   	    workspaceName = DEFAULT_WORKSPACE_NAME;
   	}
  -	WorkspaceDef wd = (WorkspaceDef) wspDefs.get(workspaceName);
  -	if (wd == null) {
  +	if (!wspDefs.containsKey(workspaceName)) {
   	    throw new NoSuchWorkspaceException(workspaceName);
   	}
   	if (credentials == null) {
   	    // anonymous login
   	    try {
  -		return new TicketImpl(this, ANONYMOUS_CREDENTIALS, wd);
  +		return new TicketImpl(this, ANONYMOUS_CREDENTIALS, workspaceName);
   	    } catch (RepositoryException re) {
   		String msg = "failed to instantiate ticket";
   		log.error(msg, re);
  @@ -539,7 +543,7 @@
   
   	    // @todo implement authentication/authorization
   	    try {
  -		return new TicketImpl(this, credentials, wd);
  +		return new TicketImpl(this, credentials, workspaceName);
   	    } catch (RepositoryException re) {
   		String msg = "failed to instantiate ticket";
   		log.error(msg, re);
  
  
  
  1.3       +5 -4      jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/SystemTicket.java
  
  Index: SystemTicket.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/SystemTicket.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- SystemTicket.java	20 Jul 2004 08:28:33 -0000	1.2
  +++ SystemTicket.java	21 Jul 2004 16:58:03 -0000	1.3
  @@ -44,10 +44,11 @@
        * Package private constructor.
        *
        * @param rep
  +     * @param wspName
        */
  -    SystemTicket(RepositoryImpl rep, WorkspaceDef wd)
  +    SystemTicket(RepositoryImpl rep, String wspName)
   	    throws RepositoryException {
  -	super(rep, SYSTEM_USER_ID, wd);
  +	super(rep, SYSTEM_USER_ID, wspName);
   
   	accessMgr = new SystemAccessManqager();
       }
  
  
  
  1.10      +4 -3      jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/Test.java
  
  Index: Test.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/Test.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- Test.java	20 Jul 2004 08:28:33 -0000	1.9
  +++ Test.java	21 Jul 2004 16:58:03 -0000	1.10
  @@ -130,8 +130,6 @@
   
   	root.save();
   
  -	//t.getWorkspace().move("/imported/src", "/misc/gurk");
  -
   	System.out.println("after save()...");
   	System.out.println();
   	dumpTree(root, System.out);
  @@ -190,6 +188,9 @@
   	dumpTree(root, System.out);
   
   	root.save();
  +
  +	t.getWorkspace().copy("/imported", "/misc/bla");
  +	t.getWorkspace().move("/misc/bla", "/misc/blabla");
   
   	System.out.println("after save()...");
   	System.out.println();
  
  
  
  1.15      +8 -8      jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/TicketImpl.java
  
  Index: TicketImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/TicketImpl.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- TicketImpl.java	20 Jul 2004 08:28:33 -0000	1.14
  +++ TicketImpl.java	21 Jul 2004 16:58:03 -0000	1.15
  @@ -105,9 +105,9 @@
        *
        * @param rep
        * @param credentials
  -     * @param wd
  +     * @param wspName
        */
  -    TicketImpl(RepositoryImpl rep, Credentials credentials, WorkspaceDef wd)
  +    TicketImpl(RepositoryImpl rep, Credentials credentials, String wspName)
   	    throws RepositoryException {
   	this.rep = rep;
   
  @@ -132,7 +132,7 @@
   	nsMappings = new TransientNamespaceMappings(rep.getNamespaceRegistry());
   
   	ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), getNamespaceResolver());
  -	wsp = new WorkspaceImpl(wd, rep.getWorkspaceStateManager(wd), rep, this);
  +	wsp = new WorkspaceImpl(wspName, rep.getWorkspaceStateManager(wspName), rep, this);
   	itemStateMgr = new TicketItemStateManager(rep.getRootNodeUUID(), wsp.getPersistentStateManager(), getNamespaceResolver());
   	hierMgr = itemStateMgr.getHierarchyMgr();
   	itemMgr = new ItemManager(itemStateMgr, hierMgr, this, ntMgr.getRootNodeDefinition(), rep.getRootNodeUUID());
  @@ -144,9 +144,9 @@
        *
        * @param rep
        * @param userId
  -     * @param wd
  +     * @param wspName
        */
  -    protected TicketImpl(RepositoryImpl rep, String userId, WorkspaceDef wd)
  +    protected TicketImpl(RepositoryImpl rep, String userId, String wspName)
   	    throws RepositoryException {
   	this.rep = rep;
   
  @@ -155,7 +155,7 @@
   	nsMappings = new TransientNamespaceMappings(rep.getNamespaceRegistry());
   
   	ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), getNamespaceResolver());
  -	wsp = new WorkspaceImpl(wd, rep.getWorkspaceStateManager(wd), rep, this);
  +	wsp = new WorkspaceImpl(wspName, rep.getWorkspaceStateManager(wspName), rep, this);
   	itemStateMgr = new TicketItemStateManager(rep.getRootNodeUUID(), wsp.getPersistentStateManager(), getNamespaceResolver());
   	hierMgr = itemStateMgr.getHierarchyMgr();
   	itemMgr = new ItemManager(itemStateMgr, hierMgr, this, ntMgr.getRootNodeDefinition(), rep.getRootNodeUUID());
  
  
  
  1.7       +311 -178  jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/WorkspaceImpl.java
  
  Index: WorkspaceImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/WorkspaceImpl.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- WorkspaceImpl.java	20 Jul 2004 08:28:33 -0000	1.6
  +++ WorkspaceImpl.java	21 Jul 2004 16:58:03 -0000	1.7
  @@ -53,7 +53,7 @@
   
   /**
    * A <code>WorkspaceImpl</code> ...
  - *
  + * 
    * @author Stefan Guggisberg
    * @version $Revision$, $Date$
    */
  @@ -62,9 +62,9 @@
       private static Logger log = Logger.getLogger(WorkspaceImpl.class);
   
       /**
  -     * The <code>WorkspaceDef</code> for this <code>Workspace</code> instance.
  +     * The name of this <code>Workspace</code>
        */
  -    protected final WorkspaceDef wsDef;
  +    protected final String wspName;
   
       /**
        * The repository that created this workspace instance
  @@ -96,14 +96,14 @@
   
       /**
        * Package private constructor.
  -     *
  -     * @param wsDef
  -     * @param persistentStateMgr
  -     * @param rep
  -     * @param ticket
  +     * 
  +     * @param wspName            
  +     * @param persistentStateMgr 
  +     * @param rep                
  +     * @param ticket             
        */
  -    WorkspaceImpl(WorkspaceDef wsDef, PersistentItemStateManager persistentStateMgr, RepositoryImpl rep, TicketImpl ticket) {
  -	this.wsDef = wsDef;
  +    WorkspaceImpl(String wspName, PersistentItemStateManager persistentStateMgr, RepositoryImpl rep, TicketImpl ticket) {
  +	this.wspName = wspName;
   	this.rep = rep;
   	this.persistentStateMgr = persistentStateMgr;
   	hierMgr = new HierarchyManagerImpl(rep.getRootNodeUUID(), persistentStateMgr, ticket.getNamespaceResolver());
  @@ -121,12 +121,12 @@
       /**
        * Dumps the state of this <code>Workspace</code> instance
        * (used for diagnostic purposes).
  -     *
  -     * @param ps
  -     * @throws RepositoryException
  +     * 
  +     * @param ps 
  +     * @throws RepositoryException 
        */
       void dump(PrintStream ps) throws RepositoryException {
  -	ps.println("Workspace: " + wsDef.getName() + " (" + this + ")");
  +	ps.println("Workspace: " + wspName + " (" + this + ")");
   	ps.println();
   	persistentStateMgr.dump(ps);
       }
  @@ -148,17 +148,23 @@
   	}
       }
   
  +    //-----------< misc. static helper methods for cross-workspace operations >
       /**
  -     *
        * @param nodePath
  +     * @param nsResolver
  +     * @param hierMgr
  +     * @param stateMgr
        * @return
        * @throws PathNotFoundException
        * @throws RepositoryException
        */
  -    protected PersistentNodeState getNodeState(String nodePath)
  -	throws PathNotFoundException, RepositoryException {
  +    protected static PersistentNodeState getNodeState(String nodePath,
  +						      NamespaceResolver nsResolver,
  +						      HierarchyManagerImpl hierMgr,
  +						      PersistentItemStateManager stateMgr)
  +	    throws PathNotFoundException, RepositoryException {
   	try {
  -	    return getNodeState(Path.create(nodePath, ticket.getNamespaceResolver(), true));
  +	    return getNodeState(Path.create(nodePath, nsResolver, true), hierMgr, stateMgr);
   	} catch (MalformedPathException mpe) {
   	    String msg = "invalid path: " + nodePath;
   	    log.error(msg, mpe);
  @@ -167,16 +173,22 @@
       }
   
       /**
  -     *
        * @param path
  +     * @param nsResolver
  +     * @param hierMgr
  +     * @param stateMgr
        * @return
        * @throws PathNotFoundException
        * @throws RepositoryException
        */
  -    protected PersistentNodeState getParentNodeState(String path)
  -	throws PathNotFoundException, RepositoryException {
  +    protected static PersistentNodeState getParentNodeState(String path,
  +							    NamespaceResolver nsResolver,
  +							    HierarchyManagerImpl hierMgr,
  +							    PersistentItemStateManager stateMgr)
  +
  +	    throws PathNotFoundException, RepositoryException {
   	try {
  -	    return getNodeState(Path.create(path, ticket.getNamespaceResolver(), true).getAncestor(1));
  +	    return getNodeState(Path.create(path, nsResolver, true).getAncestor(1), hierMgr, stateMgr);
   	} catch (MalformedPathException mpe) {
   	    String msg = "invalid path: " + path;
   	    log.error(msg, mpe);
  @@ -185,20 +197,23 @@
       }
   
       /**
  -     *
  -     * @param nodePath
  -     * @return
  -     * @throws PathNotFoundException
  -     * @throws RepositoryException
  -     */
  -    protected PersistentNodeState getNodeState(Path nodePath)
  -	throws PathNotFoundException, RepositoryException {
  +     * @param nodePath 
  +     * @param hierMgr  
  +     * @param stateMgr 
  +     * @return 
  +     * @throws PathNotFoundException 
  +     * @throws RepositoryException   
  +     */
  +    protected static PersistentNodeState getNodeState(Path nodePath,
  +						      HierarchyManagerImpl hierMgr,
  +						      PersistentItemStateManager stateMgr)
  +	    throws PathNotFoundException, RepositoryException {
   	try {
   	    ItemId id = hierMgr.resolvePath(nodePath);
   	    if (!id.denotesNode()) {
   		throw new PathNotFoundException(hierMgr.safeGetJCRPath(nodePath));
   	    }
  -	    return getNodeState((NodeId) id);
  +	    return getNodeState((NodeId) id, stateMgr);
   	} catch (NoSuchItemStateException nsise) {
   	    throw new PathNotFoundException(hierMgr.safeGetJCRPath(nodePath));
   	} catch (ItemStateException ise) {
  @@ -209,37 +224,44 @@
       }
   
       /**
  -     *
        * @param id
  +     * @param stateMgr
        * @return
        * @throws NoSuchItemStateException
        * @throws ItemStateException
        */
  -    protected PersistentNodeState getNodeState(NodeId id)
  -	throws NoSuchItemStateException, ItemStateException {
  -	return (PersistentNodeState) persistentStateMgr.getItemState(id);
  +    protected static PersistentNodeState getNodeState(NodeId id,
  +						      PersistentItemStateManager stateMgr)
  +	    throws NoSuchItemStateException, ItemStateException {
  +	return (PersistentNodeState) stateMgr.getItemState(id);
       }
   
       /**
  -     *
        * @param nodePath
        * @param nodeTypeName
  +     * @param ntReg
  +     * @param accessMgr
  +     * @param hierMgr
  +     * @param stateMgr
        * @throws ConstraintViolationException
        * @throws AccessDeniedException
        * @throws PathNotFoundException
        * @throws ItemExistsException
        * @throws RepositoryException
        */
  -    protected void checkAddNode(Path nodePath, QName nodeTypeName)
  -	throws ConstraintViolationException, AccessDeniedException,
  -	PathNotFoundException, ItemExistsException, RepositoryException {
  +    protected static void checkAddNode(Path nodePath, QName nodeTypeName,
  +				       NodeTypeRegistry ntReg,
  +				       AccessManagerImpl accessMgr,
  +				       HierarchyManagerImpl hierMgr,
  +				       PersistentItemStateManager stateMgr)
  +	    throws ConstraintViolationException, AccessDeniedException,
  +	    PathNotFoundException, ItemExistsException, RepositoryException {
   
   	Path parentPath = nodePath.getAncestor(1);
  -	PersistentNodeState parentState = getNodeState(parentPath);
  +	PersistentNodeState parentState = getNodeState(parentPath, hierMgr, stateMgr);
   
   	// 1. check path & access rights
   
  -	AccessManagerImpl accessMgr = ticket.getAccessManager();
   	Path.PathElement nodeName = nodePath.getNameElement();
   	try {
   	    // check access rights
  @@ -257,13 +279,13 @@
   
   	// 2. check note type constraints
   
  -	ChildNodeDef parentDef = getDefinition(parentPath);
  +	ChildNodeDef parentDef = getDefinition(parentPath, ntReg, hierMgr, stateMgr);
   	if (parentDef.isProtected()) {
   	    throw new ConstraintViolationException(hierMgr.safeGetJCRPath(parentPath) + ": cannot add child node to protected parent node");
   	}
  -	EffectiveNodeType entParent = getEffectiveNodeType(parentState);
  +	EffectiveNodeType entParent = getEffectiveNodeType(parentState, ntReg);
   	entParent.checkAddNodeConstraints(nodeName.getName(), nodeTypeName);
  -	ChildNodeDef newNodeDef = findApplicableDefinition(nodeName.getName(), nodeTypeName, parentState);
  +	ChildNodeDef newNodeDef = findApplicableDefinition(nodeName.getName(), nodeTypeName, parentState, ntReg);
   
   	// 3. check for name collisions
   
  @@ -279,13 +301,13 @@
   	    NodeState conflictingState;
   	    NodeId conflictingId = new NodeId(entry.getUUID());
   	    try {
  -		conflictingState = (NodeState) persistentStateMgr.getItemState(conflictingId);
  +		conflictingState = (NodeState) stateMgr.getItemState(conflictingId);
   	    } catch (ItemStateException ise) {
   		String msg = "internal error: failed to retrieve state of " + hierMgr.safeGetJCRPath(conflictingId);
   		log.error(msg, ise);
   		throw new RepositoryException(msg, ise);
   	    }
  -	    ChildNodeDef conflictingTargetDef = getDefinition(conflictingState, nodeName.getName(), parentState);
  +	    ChildNodeDef conflictingTargetDef = getDefinition(conflictingState, nodeName.getName(), parentState, ntReg);
   	    // check same-name sibling setting of both target and existing node
   	    if (!conflictingTargetDef.allowSameNameSibs() ||
   		    !newNodeDef.allowSameNameSibs()) {
  @@ -295,24 +317,30 @@
       }
   
       /**
  -     *
        * @param nodePath
  +     * @param ntReg
  +     * @param accessMgr
  +     * @param hierMgr
  +     * @param stateMgr
        * @throws ConstraintViolationException
        * @throws AccessDeniedException
        * @throws PathNotFoundException
        * @throws RepositoryException
        */
  -    protected void checkRemoveNode(Path nodePath)
  -	throws ConstraintViolationException, AccessDeniedException,
  -	PathNotFoundException, RepositoryException {
  +    protected static void checkRemoveNode(Path nodePath,
  +					  NodeTypeRegistry ntReg,
  +					  AccessManagerImpl accessMgr,
  +					  HierarchyManagerImpl hierMgr,
  +					  PersistentItemStateManager stateMgr)
  +	    throws ConstraintViolationException, AccessDeniedException,
  +	    PathNotFoundException, RepositoryException {
   
  -	PersistentNodeState targetState = getNodeState(nodePath);
  +	PersistentNodeState targetState = getNodeState(nodePath, hierMgr, stateMgr);
   	Path parentPath = nodePath.getAncestor(1);
  -	PersistentNodeState parentState = getNodeState(parentPath);
  +	PersistentNodeState parentState = getNodeState(parentPath, hierMgr, stateMgr);
   
   	// 1. check path & access rights
   
  -	AccessManagerImpl accessMgr = ticket.getAccessManager();
   	try {
   	    // check access rights
   	    if (!accessMgr.isGranted(targetState.getId(), Permission.READ_ITEM)) {
  @@ -329,11 +357,11 @@
   
   	// 2. check note type constraints
   
  -	ChildNodeDef parentDef = getDefinition(parentPath);
  +	ChildNodeDef parentDef = getDefinition(parentPath, ntReg, hierMgr, stateMgr);
   	if (parentDef.isProtected()) {
   	    throw new ConstraintViolationException(hierMgr.safeGetJCRPath(parentPath) + ": cannot remove child node of protected parent node");
   	}
  -	ChildNodeDef targetDef = getDefinition(nodePath);
  +	ChildNodeDef targetDef = getDefinition(nodePath, ntReg, hierMgr, stateMgr);
   	if (targetDef.isMandatory()) {
   	    throw new ConstraintViolationException(hierMgr.safeGetJCRPath(nodePath) + ": cannot remove mandatory node");
   	}
  @@ -348,13 +376,14 @@
        * node types.
        *
        * @param state
  +     * @param ntReg
        * @return the effective node type
        * @throws RepositoryException
        */
  -    protected EffectiveNodeType getEffectiveNodeType(NodeState state)
  +    protected static EffectiveNodeType getEffectiveNodeType(NodeState state,
  +							    NodeTypeRegistry ntReg)
   	    throws RepositoryException {
  -	// build effective node type of mixins & primary type
  -	NodeTypeRegistry ntReg = ticket.getNodeTypeManager().getNodeTypeRegistry();
  +	// build effective node type of mixins & primary type:
   	// existing mixin's
   	HashSet set = new HashSet(((NodeState) state).getMixinTypeNames());
   	// primary type
  @@ -372,21 +401,32 @@
        * Helper method that returns the definition of the specified node.
        *
        * @param nodePath
  +     * @param ntReg
  +     * @param hierMgr
  +     * @param stateMgr
        * @return
        * @throws PathNotFoundException
  -     * @throws RepositoryException if no applicable child node definition
  -     *                             could be found or if another error occured
  +     * @throws RepositoryException   if no applicable child node definition
  +     *                               could be found or if another error occured
        */
  -    protected ChildNodeDef getDefinition(Path nodePath)
  +    protected static ChildNodeDef getDefinition(Path nodePath,
  +						NodeTypeRegistry ntReg,
  +						HierarchyManagerImpl hierMgr,
  +						PersistentItemStateManager stateMgr)
   	    throws PathNotFoundException, RepositoryException {
  -	NodeState state = getNodeState(nodePath);
  -	NodeState parentState = getNodeState(nodePath.getAncestor(1));
  +	if (nodePath.denotesRoot()) {
  +	    // shortcut
  +	    return ntReg.getRootNodeDef();
  +	}
  +	NodeState state = getNodeState(nodePath, hierMgr, stateMgr);
   	NodeDefId defId = state.getDefinitionId();
   	if (defId != null) {
  -	    return ticket.getNodeTypeManager().getNodeDef(defId).unwrap();
  +	    return ntReg.getNodeDef(defId);
   	} else {
   	    // fallback: find matching definition in parent node's node type
  -	    return findApplicableDefinition(nodePath.getNameElement().getName(), state.getNodeTypeName(), parentState);
  +	    NodeState parentState = getNodeState(nodePath.getAncestor(1), hierMgr, stateMgr);
  +	    return findApplicableDefinition(nodePath.getNameElement().getName(),
  +		    state.getNodeTypeName(), parentState, ntReg);
   	}
       }
   
  @@ -396,18 +436,21 @@
        * @param state
        * @param name
        * @param parentState
  +     * @param ntReg
        * @return a <code>ChildNodeDef</code>
        * @throws RepositoryException if no applicable child node definition
        *                             could be found
        */
  -    protected ChildNodeDef getDefinition(NodeState state, QName name, NodeState parentState)
  +    protected static ChildNodeDef getDefinition(NodeState state, QName name,
  +						NodeState parentState,
  +						NodeTypeRegistry ntReg)
   	    throws RepositoryException {
   	NodeDefId defId = state.getDefinitionId();
   	if (defId != null) {
  -	    return ticket.getNodeTypeManager().getNodeDef(defId).unwrap();
  +	    return ntReg.getNodeDef(defId);
   	} else {
   	    // fallback: find matching definition in parent node's node type
  -	    return findApplicableDefinition(name, state.getNodeTypeName(), parentState);
  +	    return findApplicableDefinition(name, state.getNodeTypeName(), parentState, ntReg);
   	}
       }
   
  @@ -415,48 +458,61 @@
        * Helper method that finds the applicable definition for the
        * a child node with the given name and node type in the parent node's
        * node type and mixin types.
  -     *
  -     * @param name
  -     * @param nodeTypeName
  -     * @param parentState
  +     * 
  +     * @param name         
  +     * @param nodeTypeName 
  +     * @param parentState  
  +     * @param ntReg        
        * @return a <code>ChildNodeDef</code>
        * @throws ConstraintViolationException if no applicable child node definition
        *                                      could be found
        * @throws RepositoryException          if another error occurs
        */
  -    protected ChildNodeDef findApplicableDefinition(QName name, QName nodeTypeName, NodeState parentState)
  +    protected static ChildNodeDef findApplicableDefinition(QName name,
  +							   QName nodeTypeName,
  +							   NodeState parentState,
  +							   NodeTypeRegistry ntReg)
   	    throws RepositoryException, ConstraintViolationException {
  -	EffectiveNodeType entParent = getEffectiveNodeType(parentState);
  +	EffectiveNodeType entParent = getEffectiveNodeType(parentState, ntReg);
   	return entParent.getApplicableChildNodeDef(name, nodeTypeName);
       }
   
  -    private PersistentNodeState copyNodeState(NodeState srcState, String parentUUID)
  +    private static PersistentNodeState copyNodeState(NodeState srcState,
  +						     String parentUUID,
  +						     NodeTypeRegistry ntReg,
  +						     HierarchyManagerImpl srcHierMgr,
  +						     PersistentItemStateManager srcStateMgr,
  +						     PersistentItemStateManager destStateMgr)
   	    throws RepositoryException {
   	PersistentNodeState newState;
   	try {
   	    String uuid = new UUID().toString();	// create new version 4 uuid
  -	    newState = persistentStateMgr.createNodeState(uuid, srcState.getNodeTypeName(), parentUUID);
  +	    newState = destStateMgr.createNodeState(uuid, srcState.getNodeTypeName(), parentUUID);
   	    // copy node state
  +	    // @todo special handling required for nodes with special semantics (e.g. those defined by mix:versionable, et.al.)
  +	    // FIXME delegate to 'node type instance handler'
   	    newState.setMixinTypeNames(srcState.getMixinTypeNames());
   	    newState.setDefinitionId(srcState.getDefinitionId());
   	    // copy child nodes
   	    Iterator iter = srcState.getChildNodeEntries().iterator();
   	    while (iter.hasNext()) {
   		NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
  -		NodeState childState = (NodeState) persistentStateMgr.getItemState(new NodeId(entry.getUUID()));
  +		NodeState srcChildState = (NodeState) srcStateMgr.getItemState(new NodeId(entry.getUUID()));
   		// recursive copying of child node
  -		PersistentNodeState newChildState = copyNodeState(childState, uuid);
  +		PersistentNodeState newChildState = copyNodeState(srcChildState, uuid,
  +			ntReg, srcHierMgr, srcStateMgr, destStateMgr);
   		// persist new child node
   		newChildState.store();
   		// add new child node entry to new node
   		newState.addChildNodeEntry(entry.getName(), newChildState.getUUID());
   	    }
   	    // copy properties
  -	    iter = srcState.getChildNodeEntries().iterator();
  +	    iter = srcState.getPropertyEntries().iterator();
   	    while (iter.hasNext()) {
   		NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
  -		PropertyState childState = (PropertyState) persistentStateMgr.getItemState(new PropertyId(uuid, entry.getName()));
  -		PersistentPropertyState newChildState = copyPropertyState(childState, uuid, entry.getName());
  +		PropertyState srcChildState = (PropertyState) srcStateMgr.getItemState(new PropertyId(srcState.getUUID(), entry.getName()));
  +		PersistentPropertyState newChildState = copyPropertyState(srcChildState, uuid, entry.getName(),
  +			ntReg, srcHierMgr, srcStateMgr, destStateMgr);
   		// persist new property
   		newChildState.store();
   		// add new property entry to new node
  @@ -464,18 +520,26 @@
   	    }
   	    return newState;
   	} catch (ItemStateException ise) {
  -	    String msg = "internal error: failed to copy state of " + hierMgr.safeGetJCRPath(srcState.getId());
  +	    String msg = "internal error: failed to copy state of " + srcHierMgr.safeGetJCRPath(srcState.getId());
   	    log.error(msg, ise);
   	    throw new RepositoryException(msg, ise);
   	}
       }
   
  -    private PersistentPropertyState copyPropertyState(PropertyState srcState, String parentUUID, QName propName)
  +    private static PersistentPropertyState copyPropertyState(PropertyState srcState,
  +							     String parentUUID,
  +							     QName propName,
  +							     NodeTypeRegistry ntReg,
  +							     HierarchyManagerImpl srcHierMgr,
  +							     PersistentItemStateManager srcStateMgr,
  +							     PersistentItemStateManager destStateMgr)
   	    throws RepositoryException {
  +	// @todo special handling required for properties with special semantics (e.g. those defined by mix:versionable, et.al.)
   	PersistentPropertyState newState;
   	try {
  -	    newState = persistentStateMgr.createPropertyState(parentUUID, propName);
  -	    newState.setDefinitionId(srcState.getDefinitionId());
  +	    newState = destStateMgr.createPropertyState(parentUUID, propName);
  +	    PropDefId defId = srcState.getDefinitionId();
  +	    newState.setDefinitionId(defId);
   	    newState.setType(srcState.getType());
   	    InternalValue[] values = srcState.getValues();
   	    if (values != null) {
  @@ -484,64 +548,34 @@
   		    newValues[i] = values[i] != null ? values[i].createCopy() : null;
   		}
   		newState.setValues(values);
  +		// FIXME delegate to 'node type instance handler'
  +		if (defId != null) {
  +		    PropDef def = ntReg.getPropDef(defId);
  +		    if (def.getDeclaringNodeType().equals(NodeTypeRegistry.MIX_REFERENCEABLE)) {
  +			if (propName.equals(ItemImpl.PROPNAME_UUID)) {
  +			    // set correct value of jcr:uuid property
  +			    newState.setValues(new InternalValue[]{InternalValue.create(parentUUID)});
  +			}
  +		    }
  +		}
   	    }
   	    return newState;
   	} catch (ItemStateException ise) {
  -	    String msg = "internal error: failed to copy state of " + hierMgr.safeGetJCRPath(srcState.getId());
  +	    String msg = "internal error: failed to copy state of " + srcHierMgr.safeGetJCRPath(srcState.getId());
   	    log.error(msg, ise);
   	    throw new RepositoryException(msg, ise);
   	}
       }
   
  -    //------------------------------------------------------------< Workspace >
  -    /**
  -     * @see Workspace#getName
  -     */
  -    public String getName() {
  -	return wsDef.getName();
  -    }
  -
  -    /**
  -     * @see Workspace#getTicket
  -     */
  -    public Ticket getTicket() {
  -	return ticket;
  -    }
  -
  -    /**
  -     * @see Workspace#getQueryManager
  -     */
  -    public QueryManager getQueryManager() {
  -	// @todo implement query support
  -	return null;
  -    }
  -
  -    /**
  -     * @see Workspace#getNamespaceRegistry
  -     */
  -    public NamespaceRegistry getNamespaceRegistry() {
  -	return rep.getNamespaceRegistry();
  -    }
  -
  -    /**
  -     * @see Workspace#getNodeTypeManager
  -     */
  -    public NodeTypeManager getNodeTypeManager() {
  -	return ticket.getNodeTypeManager();
  -    }
  -
  -    /**
  -     * @see Workspace#clone(String, String, String)
  -     */
  -    public void clone(String srcAbsPath, String destAbsPath, String destWorkspace) throws NoSuchWorkspaceException, ConstraintViolationException, AccessDeniedException, PathNotFoundException, ItemExistsException, RepositoryException {
  -	// @todo implement workspace clone
  -	throw new RepositoryException("not yet implemented");
  -    }
  -
  -    /**
  -     * @see Workspace#copy(String, String)
  -     */
  -    public void copy(String srcAbsPath, String destAbsPath)
  +    private static void internalCopy(String srcAbsPath,
  +				     PersistentItemStateManager srcStateMgr,
  +				     HierarchyManagerImpl srcHierMgr,
  +				     String destAbsPath,
  +				     PersistentItemStateManager destStateMgr,
  +				     HierarchyManagerImpl destHierMgr,
  +				     AccessManagerImpl accessMgr,
  +				     NamespaceResolver nsResolver,
  +				     NodeTypeRegistry ntReg)
   	    throws ConstraintViolationException, AccessDeniedException,
   	    PathNotFoundException, ItemExistsException, RepositoryException {
   
  @@ -550,8 +584,8 @@
   	Path srcPath;
   	PersistentNodeState srcState;
   	try {
  -	    srcPath = Path.create(srcAbsPath, ticket.getNamespaceResolver(), true);
  -	    srcState = getNodeState(srcPath);
  +	    srcPath = Path.create(srcAbsPath, nsResolver, true);
  +	    srcState = getNodeState(srcPath, srcHierMgr, srcStateMgr);
   	} catch (MalformedPathException mpe) {
   	    String msg = "invalid path: " + srcAbsPath;
   	    log.error(msg, mpe);
  @@ -563,10 +597,10 @@
   	Path destParentPath;
   	PersistentNodeState destParentState;
   	try {
  -	    destPath = Path.create(destAbsPath, ticket.getNamespaceResolver(), true);
  +	    destPath = Path.create(destAbsPath, nsResolver, true);
   	    destName = destPath.getNameElement();
   	    destParentPath = destPath.getAncestor(1);
  -	    destParentState = getNodeState(destParentPath);
  +	    destParentState = getNodeState(destParentPath, destHierMgr, destStateMgr);
   	} catch (MalformedPathException mpe) {
   	    String msg = "invalid path: " + destAbsPath;
   	    log.error(msg, mpe);
  @@ -577,7 +611,7 @@
   
   	try {
   	    // check read access right on source node
  -	    if (!ticket.getAccessManager().isGranted(srcState.getId(), Permission.READ_ITEM)) {
  +	    if (!accessMgr.isGranted(srcState.getId(), Permission.READ_ITEM)) {
   		throw new PathNotFoundException(srcAbsPath);
   	    }
   	} catch (ItemNotFoundException infe) {
  @@ -585,15 +619,9 @@
   	    log.error(msg, infe);
   	    throw new RepositoryException(msg, infe);
   	}
  -	checkAddNode(destPath, srcState.getNodeTypeName());
  -
  -	// 3. do copy operation (modify and persist affected states)
  -
  -	// create new node state
  -	String uuid = new UUID().toString();	// create new version 4 uuid
  -	PersistentNodeState newState = copyNodeState(srcState, uuid);
  -
  -	// add to new parent
  +	// check node type constraints
  +	checkAddNode(destPath, srcState.getNodeTypeName(), ntReg, accessMgr, destHierMgr, destStateMgr);
  +	// check if target node needs to be inserted at specific location in child node entries list
   	boolean insertTargetEntry = false;
   	int ind = destName.getIndex();
   	if (ind > 0) {
  @@ -607,6 +635,20 @@
   	    }
   	    insertTargetEntry = (ind < sameNameSibs.size() + 1) ? true : false;
   	}
  +	if (insertTargetEntry) {
  +	    // check hasOrderableChildNodes flag
  +	    if (!ntReg.getNodeTypeDef(destParentState.getNodeTypeName()).hasOrderableChildNodes()) {
  +		throw new ConstraintViolationException(destAbsPath + ": parent node's node type does not allow explicit ordering of child nodes");
  +	    }
  +	}
  +
  +	// 3. do copy operation (modify and persist affected states)
  +
  +	// create deep copy of source node state
  +	PersistentNodeState newState = copyNodeState(srcState, destParentState.getUUID(),
  +		ntReg, srcHierMgr, srcStateMgr, destStateMgr);
  +
  +	// add to new parent
   	if (!insertTargetEntry) {
   	    // append target entry
   	    destParentState.addChildNodeEntry(destName.getName(), newState.getUUID());
  @@ -624,7 +666,7 @@
   	    }
   	}
   	// change definition (id) of new node
  -	ChildNodeDef newNodeDef = findApplicableDefinition(destName.getName(), srcState.getNodeTypeName(), destParentState);
  +	ChildNodeDef newNodeDef = findApplicableDefinition(destName.getName(), srcState.getNodeTypeName(), destParentState, ntReg);
   	newState.setDefinitionId(new NodeDefId(newNodeDef));
   
   	// persist states
  @@ -638,6 +680,62 @@
   	}
       }
   
  +    //------------------------------------------------------------< Workspace >
  +    /**
  +     * @see Workspace#getName
  +     */
  +    public String getName() {
  +	return wspName;
  +    }
  +
  +    /**
  +     * @see Workspace#getTicket
  +     */
  +    public Ticket getTicket() {
  +	return ticket;
  +    }
  +
  +    /**
  +     * @see Workspace#getNamespaceRegistry
  +     */
  +    public NamespaceRegistry getNamespaceRegistry() {
  +	return rep.getNamespaceRegistry();
  +    }
  +
  +    /**
  +     * @see Workspace#getNodeTypeManager
  +     */
  +    public NodeTypeManager getNodeTypeManager() {
  +	return ticket.getNodeTypeManager();
  +    }
  +
  +    /**
  +     * @see Workspace#clone(String, String, String)
  +     */
  +    public void clone(String srcAbsPath, String destAbsPath, String destWorkspace) throws NoSuchWorkspaceException, ConstraintViolationException, AccessDeniedException, PathNotFoundException, ItemExistsException, RepositoryException {
  +	PersistentItemStateManager destStateMgr = rep.getWorkspaceStateManager(destWorkspace);
  +	// FIXME need to setup a hierarchy manager for destination workspace
  +	HierarchyManagerImpl destHierMgr = new HierarchyManagerImpl(rep.getRootNodeUUID(), destStateMgr, ticket.getNamespaceResolver());
  +	// do cross-workspace copy
  +	internalCopy(srcAbsPath, persistentStateMgr, hierMgr,
  +		destAbsPath, destStateMgr, destHierMgr,
  +		ticket.getAccessManager(), ticket.getNamespaceResolver(),
  +		rep.getNodeTypeRegistry());
  +    }
  +
  +    /**
  +     * @see Workspace#copy(String, String)
  +     */
  +    public void copy(String srcAbsPath, String destAbsPath)
  +	    throws ConstraintViolationException, AccessDeniedException,
  +	    PathNotFoundException, ItemExistsException, RepositoryException {
  +	// do intra-workspace copy
  +	internalCopy(srcAbsPath, persistentStateMgr, hierMgr,
  +		destAbsPath, persistentStateMgr, hierMgr,
  +		ticket.getAccessManager(), ticket.getNamespaceResolver(),
  +		rep.getNodeTypeRegistry());
  +    }
  +
       /**
        * @see Workspace#move
        */
  @@ -645,6 +743,8 @@
   	    throws ConstraintViolationException, AccessDeniedException,
   	    PathNotFoundException, ItemExistsException, RepositoryException {
   
  +	// intra-workspace move...
  +
   	// 1. check paths & retrieve state
   
   	Path srcPath;
  @@ -656,8 +756,8 @@
   	    srcPath = Path.create(srcAbsPath, ticket.getNamespaceResolver(), true);
   	    srcName = srcPath.getNameElement();
   	    srcParentPath = srcPath.getAncestor(1);
  -	    targetState = getNodeState(srcPath);
  -	    srcParentState = getNodeState(srcParentPath);
  +	    targetState = getNodeState(srcPath, hierMgr, persistentStateMgr);
  +	    srcParentState = getNodeState(srcParentPath, hierMgr, persistentStateMgr);
   	} catch (MalformedPathException mpe) {
   	    String msg = "invalid path: " + srcAbsPath;
   	    log.error(msg, mpe);
  @@ -672,7 +772,7 @@
   	    destPath = Path.create(destAbsPath, ticket.getNamespaceResolver(), true);
   	    destName = destPath.getNameElement();
   	    destParentPath = destPath.getAncestor(1);
  -	    destParentState = getNodeState(destParentPath);
  +	    destParentState = getNodeState(destParentPath, hierMgr, persistentStateMgr);
   	} catch (MalformedPathException mpe) {
   	    String msg = "invalid path: " + destAbsPath;
   	    log.error(msg, mpe);
  @@ -681,17 +781,11 @@
   
   	// 2. check node type constraints & access rights
   
  -	checkRemoveNode(srcPath);
  -	checkAddNode(destPath, targetState.getNodeTypeName());
  -
  -	// 3. do move operation (modify and persist affected states)
  -
  -	boolean renameOnly = srcParentState.getUUID().equals(destParentState.getUUID());
  -
  -	// add to new parent
  -	if (!renameOnly) {
  -	    targetState.addParentUUID(destParentState.getUUID());
  -	}
  +	checkRemoveNode(srcPath, rep.getNodeTypeRegistry(), ticket.getAccessManager(), hierMgr, persistentStateMgr);
  +	checkAddNode(destPath, targetState.getNodeTypeName(),
  +		rep.getNodeTypeRegistry(), ticket.getAccessManager(),
  +		hierMgr, persistentStateMgr);
  +	// check if target node needs to be inserted at specific location in child node entries list
   	boolean insertTargetEntry = false;
   	int ind = destName.getIndex();
   	if (ind > 0) {
  @@ -705,6 +799,21 @@
   	    }
   	    insertTargetEntry = (ind < sameNameSibs.size() + 1) ? true : false;
   	}
  +	if (insertTargetEntry) {
  +	    // check hasOrderableChildNodes flag
  +	    if (!rep.getNodeTypeRegistry().getNodeTypeDef(destParentState.getNodeTypeName()).hasOrderableChildNodes()) {
  +		throw new ConstraintViolationException(destAbsPath + ": parent node's node type does not allow explicit ordering of child nodes");
  +	    }
  +	}
  +
  +	// 3. do move operation (modify and persist affected states)
  +
  +	boolean renameOnly = srcParentState.getUUID().equals(destParentState.getUUID());
  +
  +	// add to new parent
  +	if (!renameOnly) {
  +	    targetState.addParentUUID(destParentState.getUUID());
  +	}
   	if (!insertTargetEntry) {
   	    // append target entry
   	    destParentState.addChildNodeEntry(destName.getName(), targetState.getUUID());
  @@ -722,14 +831,22 @@
   	    }
   	}
   	// change definition (id) of target node
  -	ChildNodeDef newTargetDef = findApplicableDefinition(destName.getName(), targetState.getNodeTypeName(), destParentState);
  +	ChildNodeDef newTargetDef = findApplicableDefinition(destName.getName(), targetState.getNodeTypeName(), destParentState, rep.getNodeTypeRegistry());
   	targetState.setDefinitionId(new NodeDefId(newTargetDef));
   
   	// remove from old parent
   	if (!renameOnly) {
   	    targetState.removeParentUUID(srcParentState.getUUID());
   	}
  -	srcParentState.removeChildNodeEntry(srcName.getName(), srcName.getIndex() == 0 ? 1 : srcName.getIndex());
  +	int srcNameIndex = srcName.getIndex() == 0 ? 1 : srcName.getIndex();
  +	// if the net result of the move is changing the position of a child node
  +	// among its same-same siblings, the subscript of the child node entry
  +	// to be removed might need adjustment
  +	if (renameOnly && srcName.getName().equals(destName.getName()) &&
  +		insertTargetEntry && destName.getIndex() <= srcNameIndex) {
  +	    srcNameIndex++;
  +	}
  +	srcParentState.removeChildNodeEntry(srcName.getName(), srcNameIndex);
   
   	// persist states
   	try {
  @@ -748,14 +865,6 @@
       }
   
       /**
  -     * @see Workspace#restore(Version[])
  -     */
  -    public void restore(Version[] versions) throws UnsupportedRepositoryOperationException, VersionException, RepositoryException {
  -	// @todo implement versioning support
  -	throw new UnsupportedRepositoryOperationException();
  -    }
  -
  -    /**
        * @see Workspace#getAccessManager
        */
       public AccessManager getAccessManager() throws UnsupportedRepositoryOperationException {
  @@ -765,11 +874,35 @@
       /**
        * @see Workspace#getObservationManager
        */
  -    public synchronized ObservationManager getObservationManager() {
  +    public synchronized ObservationManager getObservationManager()
  +	    throws UnsupportedRepositoryOperationException {
   	if (obsMgr == null) {
  -	    obsMgr = rep.getObservationManagerFactory(wsDef).createObservationManager(ticket, ticket.getItemManager());
  +	    try {
  +		obsMgr = rep.getObservationManagerFactory(wspName).createObservationManager(ticket, ticket.getItemManager());
  +	    } catch (NoSuchWorkspaceException nswe) {
  +		// should never get here
  +		String msg = "internal error: failed to instantiate observation manager";
  +		log.error(msg, nswe);
  +		throw new UnsupportedRepositoryOperationException(msg, nswe);
  +	    }
   	}
   	return obsMgr;
  +    }
  +
  +    /**
  +     * @see Workspace#getQueryManager
  +     */
  +    public QueryManager getQueryManager() {
  +	// @todo implement query support
  +	return null;
  +    }
  +
  +    /**
  +     * @see Workspace#restore(Version[])
  +     */
  +    public void restore(Version[] versions) throws UnsupportedRepositoryOperationException, VersionException, RepositoryException {
  +	// @todo implement versioning support
  +	throw new UnsupportedRepositoryOperationException();
       }
   
       /**
  
  
  
  1.8       +5 -26     jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/nodetype/NodeTypeManagerImpl.java
  
  Index: NodeTypeManagerImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/nodetype/NodeTypeManagerImpl.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- NodeTypeManagerImpl.java	20 Jul 2004 08:28:35 -0000	1.7
  +++ NodeTypeManagerImpl.java	21 Jul 2004 16:58:04 -0000	1.8
  @@ -32,7 +32,6 @@
   
   import javax.jcr.RepositoryException;
   import javax.jcr.nodetype.*;
  -import javax.jcr.version.OnParentVersionAction;
   import java.io.PrintStream;
   import java.util.ArrayList;
   import java.util.Collections;
  @@ -70,7 +69,7 @@
   	// setup item cache with soft references to node type instances
   	ntCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
   
  -	rootNodeDef = RootNodeDefinition.create(this, nsResolver);
  +	rootNodeDef = new RootNodeDefinition(ntReg.getRootNodeDef(), this, nsResolver);
       }
   
       /**
  @@ -221,30 +220,10 @@
       private static class RootNodeDefinition extends NodeDefImpl {
   
   	/**
  -	 * private constructor
  -	 */
  -	private RootNodeDefinition(ChildNodeDef def, NodeTypeManagerImpl ntMgr, NamespaceResolver nsResolver) {
  -	    super(def, ntMgr, nsResolver);
  -	}
  -
  -	/**
   	 * Creates a new <code>RootNodeDefinition</code>.
   	 */
  -	static RootNodeDefinition create(NodeTypeManagerImpl ntMgr, NamespaceResolver nsResolver) {
  -	    ChildNodeDef def = new ChildNodeDef();
  -
  -	    //def.setName(null);
  -	    //def.setDeclaringNodeType(null);
  -	    def.setRequiredPrimaryTypes(new QName[]{NodeTypeRegistry.NT_BASE});
  -	    def.setDefaultPrimaryType(NodeTypeRegistry.NT_UNSTRUCTURED);
  -	    def.setMandatory(true);
  -	    def.setProtected(false);
  -	    def.setOnParentVersion(OnParentVersionAction.VERSION);
  -	    def.setPrimaryItem(false);
  -	    def.setAllowSameNameSibs(false);
  -	    def.setAutoCreate(true);
  -
  -	    return new RootNodeDefinition(def, ntMgr, nsResolver);
  +	RootNodeDefinition(ChildNodeDef def, NodeTypeManagerImpl ntMgr, NamespaceResolver nsResolver) {
  +	    super(def, ntMgr, nsResolver);
   	}
   
   	/**
  
  
  
  1.10      +57 -12    jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/nodetype/NodeTypeRegistry.java
  
  Index: NodeTypeRegistry.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/nodetype/NodeTypeRegistry.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- NodeTypeRegistry.java	20 Jul 2004 08:28:35 -0000	1.9
  +++ NodeTypeRegistry.java	21 Jul 2004 16:58:04 -0000	1.10
  @@ -72,6 +72,9 @@
       // nt:version
       public static final QName NT_VERSION =
   	    new QName(NamespaceRegistryImpl.NS_NT_URI, "version");
  +    // nt:frozen
  +    public static final QName NT_FROZEN =
  +	    new QName(NamespaceRegistryImpl.NS_NT_URI, "frozen");
   
       private static final String BUILTIN_NODETYPES_RESOURCE_PATH =
   	    "org/apache/slide/jcr/core/nodetype/builtin_nodetypes.xml";
  @@ -97,6 +100,9 @@
       // map of node type names and node type definitions
       private final HashMap registeredNTDefs;
   
  +    // definition of the root node
  +    private final ChildNodeDef rootNodeDef;
  +
       // map of id's and property definitions
       private final HashMap propDefs;
       // map of id's and node definitions
  @@ -153,6 +159,10 @@
   	propDefs = new HashMap();
   	nodeDefs = new HashMap();
   
  +	// setup definition of root node
  +	rootNodeDef = createRootNodeDef();
  +	nodeDefs.put(new NodeDefId(rootNodeDef), rootNodeDef);
  +
   	// load and register pre-defined (i.e. built-in) node types
   	builtInNTDefs = new NodeTypeDefStore();
   	InputStream in = null;
  @@ -214,6 +224,23 @@
   	}
       }
   
  +    private static ChildNodeDef createRootNodeDef() {
  +	ChildNodeDef def = new ChildNodeDef();
  +
  +	//def.setName(null);
  +	// FIXME need a fake declaring node type
  +	def.setDeclaringNodeType(new QName(NamespaceRegistryImpl.NS_DEFAULT_URI, ""));
  +	def.setRequiredPrimaryTypes(new QName[]{NT_BASE});
  +	def.setDefaultPrimaryType(NT_UNSTRUCTURED);
  +	def.setMandatory(true);
  +	def.setProtected(false);
  +	def.setOnParentVersion(OnParentVersionAction.VERSION);
  +	def.setPrimaryItem(false);
  +	def.setAllowSameNameSibs(false);
  +	def.setAutoCreate(true);
  +	return def;
  +    }
  +
       /**
        * Validates and registers the specified collection of <code>NodeTypeDef</code>
        * objects. An <code>InvalidNodeTypeDefException</code> is thrown if the
  @@ -330,12 +357,17 @@
        * Notify the listeners that a node type <code>ntName</code> has been registered.
        */
       private void notifyRegistered(QName ntName) {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	NodeTypeRegistryListener[] la = new NodeTypeRegistryListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    NodeTypeRegistryListener listener = (NodeTypeRegistryListener) iter.next();
  -	    listener.nodeTypeRegistered(ntName);
  +	    la[cnt++] = (NodeTypeRegistryListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].nodeTypeRegistered(ntName);
  +	    }
   	}
       }
   
  @@ -343,12 +375,17 @@
        * Notify the listeners that a node type <code>ntName</code> has been unregistered.
        */
       private void notifyUnregistered(QName ntName) {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	NodeTypeRegistryListener[] la = new NodeTypeRegistryListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    NodeTypeRegistryListener listener = (NodeTypeRegistryListener) iter.next();
  -	    listener.nodeTypeUnregistered(ntName);
  +	    la[cnt++] = (NodeTypeRegistryListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].nodeTypeUnregistered(ntName);
  +	    }
   	}
       }
   
  @@ -604,6 +641,14 @@
        */
       synchronized QName[] getRegisteredNodeTypes() {
   	return (QName[]) registeredNTDefs.keySet().toArray(new QName[registeredNTDefs.size()]);
  +    }
  +
  +    /**
  +     *
  +     * @return
  +     */
  +    public ChildNodeDef getRootNodeDef() {
  +	return rootNodeDef;
       }
   
       /**
  
  
  
  1.4       +8 -4      jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/nodetype/builtin_nodetypes.xml
  
  Index: builtin_nodetypes.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/nodetype/builtin_nodetypes.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- builtin_nodetypes.xml	16 Jul 2004 16:37:23 -0000	1.3
  +++ builtin_nodetypes.xml	21 Jul 2004 16:58:04 -0000	1.4
  @@ -56,7 +56,7 @@
   	<propertyDef name="jcr:encoding" type="String" valueConstraint="" defaultValue="" autoCreate="false" mandatory="false" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
   	<propertyDef name="jcr:mimeType" type="String" valueConstraint="" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
   	<propertyDef name="jcr:data" type="Binary" valueConstraint="" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="COPY" protected="false" primaryItem="true" multiple="false"/>
  -	<propertyDef name="jcr:lastModified" type="Date" valueConstraint="" defaultValue="" autoCreate="false" mandatory="true" onParentVersion="IGNORE" protected="false" primaryItem="false" multiple="false"/>
  +	<propertyDef name="jcr:lastModified" type="Date" valueConstraint="" defaultValue="" autoCreate="false" mandatory="true" onParentVersion="COMPUTE" protected="false" primaryItem="false" multiple="false"/>
       </nodeType>
       <nodeType name="nt:folder" mixin="false" orderableChildNodes="false" supertypes="nt:hierarchyNode">
   	<childNodeDef name="" requiredPrimaryTypes="nt:hierarchyNode" defaultPrimaryType="" autoCreate="false" mandatory="false" onParentVersion="VERSION" protected="false" primaryItem="false" sameNameSibs="false"/>
  @@ -96,18 +96,21 @@
   	<childNodeDef name="jcr:rootVersion" requiredPrimaryTypes="nt:version" defaultPrimaryType="nt:version" autoCreate="true" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" sameNameSibs="false"/>
   	<childNodeDef name="" requiredPrimaryTypes="nt:version" defaultPrimaryType="nt:version" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" sameNameSibs="false"/>
       </nodeType>
  +    <nodeType name="nt:frozenChild" mixin="false" orderableChildNodes="false" supertypes="nt:base">
  +	<propertyDef name="jcr:versionHistory" type="Reference" valueConstraint="nt:versionHistory" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="COPY" protected="true" primaryItem="false" multiple="false"/>
  +    </nodeType>
       <nodeType name="nt:frozen" mixin="false" orderableChildNodes="false" supertypes="nt:base">
   	<propertyDef name="jcr:frozenPrimaryType" type="String" valueConstraint="" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
   	<propertyDef name="jcr:frozenMixinTypes" type="String" valueConstraint="" defaultValue="" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
   	<propertyDef name="jcr:frozenUUID" type="String" valueConstraint="" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
   	<propertyDef name="" type="undefined" valueConstraint="" defaultValue="" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
  -	<childNodeDef name="" requiredPrimaryTypes="nt:base" defaultPrimaryType="" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" sameNameSibs="true"/>
  +	<childNodeDef name="" requiredPrimaryTypes="nt:base" defaultPrimaryType="nt:frozen" autoCreate="false" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" sameNameSibs="true"/>
       </nodeType>
       <nodeType name="nt:version" mixin="false" orderableChildNodes="false" supertypes="nt:frozen,mix:referenceable">
   	<propertyDef name="jcr:versionLabels" type="String" valueConstraint="" defaultValue="" autoCreate="true" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
   	<propertyDef name="jcr:created" type="Date" valueConstraint="" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="false"/>
  -	<propertyDef name="jcr:predecessors" type="Reference" valueConstraint="nt:version" defaultValue="" autoCreate="true" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
  -	<propertyDef name="jcr:successors" type="Reference" valueConstraint="nt:version" defaultValue="" autoCreate="true" mandatory="false" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
  +	<propertyDef name="jcr:predecessors" type="Reference" valueConstraint="nt:version" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
  +	<propertyDef name="jcr:successors" type="Reference" valueConstraint="nt:version" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="ABORT" protected="true" primaryItem="false" multiple="true"/>
       </nodeType>
       <nodeType name="nt:query" mixin="false" orderableChildNodes="false" supertypes="nt:base">
   	<propertyDef name="jcr:statement" type="String" valueConstraint="" defaultValue="" autoCreate="false" mandatory="false" onParentVersion="COPY" protected="false" primaryItem="false" multiple="false"/>
  @@ -127,5 +130,6 @@
   	<propertyDef name="jcr:versionHistory" type="Reference" valueConstraint="nt:versionHistory" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="COPY" protected="true" primaryItem="false" multiple="false"/>
   	<propertyDef name="jcr:baseVersion" type="Reference" valueConstraint="nt:version" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="IGNORE" protected="true" primaryItem="false" multiple="false"/>
   	<propertyDef name="jcr:isCheckedOut" type="Boolean" valueConstraint="" defaultValue="true" autoCreate="true" mandatory="true" onParentVersion="IGNORE" protected="true" primaryItem="false" multiple="false"/>
  +	<propertyDef name="jcr:predecessors" type="Reference" valueConstraint="nt:version" defaultValue="" autoCreate="true" mandatory="true" onParentVersion="COPY" protected="true" primaryItem="false" multiple="true"/>
       </nodeType>
   </nodeTypes>
  
  
  
  1.6       +42 -21    jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/ItemState.java
  
  Index: ItemState.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/ItemState.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ItemState.java	20 Jul 2004 08:28:36 -0000	1.5
  +++ ItemState.java	21 Jul 2004 16:58:04 -0000	1.6
  @@ -167,12 +167,17 @@
        * representing has been discarded.
        */
       protected void notifyStateDiscarded() {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	ItemStateListener[] la = new ItemStateListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    ItemStateListener listener = (ItemStateListener) iter.next();
  -	    listener.stateDiscarded(this);
  +	    la[cnt++] = (ItemStateListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].stateDiscarded(this);
  +	    }
   	}
       }
   
  @@ -181,11 +186,17 @@
        * representing has been created.
        */
       protected void notifyStateCreated() {
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	ItemStateListener[] la = new ItemStateListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    ItemStateListener listener = (ItemStateListener) iter.next();
  -	    listener.stateCreated(this);
  +	    la[cnt++] = (ItemStateListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].stateCreated(this);
  +	    }
   	}
       }
   
  @@ -194,12 +205,17 @@
        * representing has been changed.
        */
       protected void notifyStateModified() {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	ItemStateListener[] la = new ItemStateListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    ItemStateListener listener = (ItemStateListener) iter.next();
  -	    listener.stateModified(this);
  +	    la[cnt++] = (ItemStateListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].stateModified(this);
  +	    }
   	}
       }
   
  @@ -208,12 +224,17 @@
        * representing has been destroyed.
        */
       protected void notifyStateDestroyed() {
  -	// use temp array to avoid ConcurrentModificationException
  -	Collection tmp = new ArrayList(listeners.values());
  -	Iterator iter = tmp.iterator();
  +	// copy listeners to array to avoid ConcurrentModificationException
  +	ItemStateListener[] la = new ItemStateListener[listeners.size()];
  +	Iterator iter = listeners.values().iterator();
  +	int cnt = 0;
   	while (iter.hasNext()) {
  -	    ItemStateListener listener = (ItemStateListener) iter.next();
  -	    listener.stateDestroyed(this);
  +	    la[cnt++] = (ItemStateListener) iter.next();
  +	}
  +	for (int i = 0; i < la.length; i++) {
  +	    if (la[i] != null) {
  +		la[i].stateDestroyed(this);
  +	    }
   	}
       }
   
  
  
  
  1.8       +0 -0      jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/PersistentItemStateManager.java
  
  Index: PersistentItemStateManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/state/PersistentItemStateManager.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  
  
  
  1.3       +78 -104   jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/version/VersionImpl.java
  
  Index: VersionImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/version/VersionImpl.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- VersionImpl.java	20 Jul 2004 08:28:37 -0000	1.2
  +++ VersionImpl.java	21 Jul 2004 16:58:04 -0000	1.3
  @@ -23,14 +23,13 @@
    */
   package org.apache.slide.jcr.core.version;
   
  -import org.apache.slide.jcr.core.*;
   import org.apache.slide.jcr.core.state.NodeState;
  +import org.apache.slide.jcr.core.*;
  +import org.apache.slide.jcr.util.UUID;
   
  -import javax.jcr.RepositoryException;
  -import javax.jcr.StringValue;
  -import javax.jcr.Value;
  -import javax.jcr.nodetype.NodeDef;
   import javax.jcr.version.Version;
  +import javax.jcr.*;
  +import javax.jcr.nodetype.NodeDef;
   import java.util.Calendar;
   
   /**
  @@ -39,62 +38,34 @@
    * @author Tobias Strasser
    * @version $Revision$, $Date$
    */
  -public class VersionImpl extends NodeImpl implements Version {
  +public class VersionImpl extends FrozenNode implements Version {
   
  -    /**
  -     * name of the 'jcr:versionLabels' property
  -     */
  +    /** name of the 'jcr:versionLabels' property */
       public static final QName PROPNAME_VERSION_LABELS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "uuid");
   
  -    /**
  -     * name of the 'jcr:predecessors' property
  -     */
  +    /** name of the 'jcr:predecessors' property */
       public static final QName PROPNAME_PREDESESSORS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "predecessors");
   
  -    /**
  -     * name of the 'jcr:successors' property
  -     */
  +    /** name of the 'jcr:successors' property */
       public static final QName PROPNAME_SUCCESSORS = new QName(NamespaceRegistryImpl.NS_JCR_URI, "successors");
   
  -    /**
  -     * name of the 'jcr:isCheckedOut' property
  -     */
  +    /** name of the 'jcr:isCheckedOut' property */
       public static final QName PROPNAME_IS_CHECKED_OUT = new QName(NamespaceRegistryImpl.NS_JCR_URI, "isCheckedOut");
   
  -    /**
  -     * name of the 'jcr:versionHistory' property
  -     */
  +    /** name of the 'jcr:versionHistory' property */
       public static final QName PROPNAME_VERSION_HISTORY = new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionHistory");
   
  -    /**
  -     * name of the 'jcr:frozenUUID' property
  -     */
  -    public static final QName PROPNAME_FROZEN_UUID = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozenUUID");
  -
  -    /**
  -     * name of the 'jcr:frozenPrimaryType' property
  -     */
  -    public static final QName PROPNAME_FROZEN_PRIMARY_TYPE = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozenPrimaryType");
  -
  -    /**
  -     * name of the 'jcr:frozenMixinTypes' property
  -     */
  -    public static final QName PROPNAME_FROZEN_MIXIN_TYPES = new QName(NamespaceRegistryImpl.NS_JCR_URI, "frozenMixinTypes");
  -
  -    /**
  -     * name of the 'jcr:baseVersion' property
  -     */
  +    /** name of the 'jcr:baseVersion' property */
       public static final QName PROPNAME_BASE_VERSION = new QName(NamespaceRegistryImpl.NS_JCR_URI, "baseVersion");
   
       /**
        * Creates a new Version node. This is only called by the ItemManager when
        * creating new node instances.
  -     *
        * @see org.apache.slide.jcr.core.ItemManager#createNodeInstance(org.apache.slide.jcr.core.state.NodeState, javax.jcr.nodetype.NodeDef)
        */
       public VersionImpl(ItemManager itemMgr, TicketImpl ticket, NodeId id,
  -		       NodeState state, NodeDef definition,
  -		       ItemLifeCycleListener[] listeners)
  +			  NodeState state, NodeDef definition,
  +			  ItemLifeCycleListener[] listeners)
   	    throws RepositoryException {
   	super(itemMgr, ticket, id, state, definition, listeners);
       }
  @@ -114,9 +85,9 @@
       public String[] getVersionLabels() throws RepositoryException {
   	if (hasProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver()))) {
   	    Value[] values = getProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver())).getValues();
  -	    if (values != null) {
  +	    if (values!=null) {
   		String[] labels = new String[values.length];
  -		for (int i = 0; i < values.length; i++) {
  +		for (int i=0; i<values.length; i++) {
   		    labels[i] = values[i].getString();
   		}
   		return labels;
  @@ -129,17 +100,7 @@
        * @see Version#hasVersionLabel()
        */
       public boolean hasVersionLabel(String label) throws RepositoryException {
  -	if (hasProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver()))) {
  -	    Value[] values = getProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver())).getValues();
  -	    if (values != null) {
  -		for (int i = 0; i < values.length; i++) {
  -		    if (values[i].getString().equals(label)) {
  -			return true;
  -		    }
  -		}
  -	    }
  -	}
  -	return false;
  +	return getHistory().getVersionByLabel(label) == this;
       }
   
       /**
  @@ -151,21 +112,21 @@
   	    return;
   	}
   
  -	Value[] oldValues = null;
  -	Value[] newValues = null;
  -	if (hasProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver()))) {
  -	    oldValues = getProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver())).getValues();
  -	}
  -	if (oldValues != null) {
  -	    newValues = new Value[oldValues.length + 1];
  -	    for (int i = 0; i < oldValues.length; i++) {
  -		newValues[i] = oldValues[i];
  +	Value[] oldValues=null;
  +	InternalValue[] newValues=null;
  +	if (hasProperty(PROPNAME_VERSION_LABELS)) {
  +	    oldValues = getProperty(PROPNAME_VERSION_LABELS).getValues();
  +	}
  +	if (oldValues!=null) {
  +	    newValues = new InternalValue[oldValues.length+1];
  +	    for (int i=0; i<oldValues.length; i++) {
  +		newValues[i] = InternalValue.create(oldValues[i].getString());
   	    }
  -	    newValues[oldValues.length] = new StringValue(label);
  +	    newValues[oldValues.length] = InternalValue.create(label);
   	} else {
  -	    newValues = new Value[]{new StringValue(label)};
  +	    newValues = new InternalValue[]{InternalValue.create(label)};
   	}
  -	setProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver()), newValues);
  +	internalSetProperty(PROPNAME_VERSION_LABELS, newValues);
   	save();
       }
   
  @@ -176,23 +137,23 @@
   	// check history first
   	getHistory().removeVersionLabel(label);
   
  -	Value[] oldValues = getProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver())).getValues();
  -	Value[] newValues = new Value[oldValues.length - 1];
  -	int j = 0;
  -	for (int i = 0; i < oldValues.length; i++) {
  +	Value[] oldValues=getProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver())).getValues();
  +	InternalValue[] newValues=new InternalValue[oldValues.length-1];
  +	int j=0;
  +	for (int i=0; i<oldValues.length; i++) {
   	    if (!oldValues[i].getString().equals(label)) {
  -		if (j < newValues.length) {
  -		    newValues[j] = oldValues[i];
  +		if (j<newValues.length) {
  +		    newValues[j] = InternalValue.create(oldValues[i].getString());
   		}
   		j++;
   	    }
   	}
   
  -	if (j == 0) {
  -	    setProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver()), (Value[]) null);
  +	if (j==0) {
  +	    internalSetProperty(PROPNAME_VERSION_LABELS, (InternalValue[]) null);
   	    save();
   	} else {
  -	    setProperty(PROPNAME_VERSION_LABELS.toJCRName(ticket.getNamespaceResolver()), newValues);
  +	    internalSetProperty(PROPNAME_VERSION_LABELS, newValues);
   	    save();
   	}
       }
  @@ -201,11 +162,11 @@
        * @see Version#getSuccessors()
        */
       public Version[] getSuccessors() throws RepositoryException {
  -	if (hasProperty(PROPNAME_SUCCESSORS.toJCRName(ticket.getNamespaceResolver()))) {
  -	    Value[] values = getProperty(PROPNAME_SUCCESSORS.toJCRName(ticket.getNamespaceResolver())).getValues();
  -	    if (values != null) {
  +	if (hasProperty(PROPNAME_SUCCESSORS)) {
  +	    Value[] values = getProperty(PROPNAME_SUCCESSORS).getValues();
  +	    if (values!=null) {
   		Version[] preds = new Version[values.length];
  -		for (int i = 0; i < values.length; i++) {
  +		for (int i=0; i<values.length; i++) {
   		    preds[i] = (Version) ticket.getNodeByUUID(values[i].getString());
   		}
   		return preds;
  @@ -215,14 +176,47 @@
       }
   
       /**
  +     * Adds a successor to the jcr:successor list
  +     * @param succ
  +     */
  +    void internalAddSuccessor(VersionImpl succ) throws RepositoryException {
  +	Version[] successors = getSuccessors();
  +	InternalValue[] values = new InternalValue[successors.length+1];
  +	values[0] = InternalValue.create(succ.getUUID());
  +	for (int i=0; i<successors.length; i++) {
  +	    values[i+1] = InternalValue.create(new UUID(successors[i].getUUID()));
  +	}
  +	Property prop = internalSetProperty(PROPNAME_SUCCESSORS, values);
  +	prop.save();
  +    }
  +
  +    /**
  +     * @see NodeImpl#internalSetProperty(org.apache.slide.jcr.core.QName, org.apache.slide.jcr.core.InternalValue)
  +     */
  +    public Property internalSetProperty(QName name,
  +					   InternalValue value)
  +	    throws ValueFormatException, RepositoryException {
  +	return super.internalSetProperty(name, value);
  +    }
  +
  +    /**
  +     * @see NodeImpl#internalSetProperty(org.apache.slide.jcr.core.QName, org.apache.slide.jcr.core.InternalValue[])
  +     */
  +    protected Property internalSetProperty(QName name,
  +					   InternalValue[] value)
  +	    throws ValueFormatException, RepositoryException {
  +	return super.internalSetProperty(name, value);
  +    }
  +
  +    /**
        * @see Version#getPredecessors()
        */
       public Version[] getPredecessors() throws RepositoryException {
   	if (hasProperty(PROPNAME_PREDESESSORS.toJCRName(ticket.getNamespaceResolver()))) {
   	    Value[] values = getProperty(PROPNAME_PREDESESSORS.toJCRName(ticket.getNamespaceResolver())).getValues();
  -	    if (values != null) {
  +	    if (values!=null) {
   		Version[] succs = new Version[values.length];
  -		for (int i = 0; i < values.length; i++) {
  +		for (int i=0; i<values.length; i++) {
   		    succs[i] = (Version) ticket.getNodeByUUID(values[i].getString());
   		}
   		return succs;
  @@ -233,31 +227,11 @@
   
       /**
        * Returns the version history of this version and not the extended node.
  -     *
        * @return the version history of this version graph
        * @throws RepositoryException
        */
       private VersionHistoryImpl getHistory() throws RepositoryException {
   	return (VersionHistoryImpl) getParent();
  -    }
  -
  -    /**
  -     * Initializes the frozen state of a version. i.e. copies the uuid,
  -     * primary types etc.
  -     *
  -     * @param node
  -     */
  -    void initFrozenState(NodeImpl node)
  -	    throws RepositoryException {
  -	internalSetProperty(VersionImpl.PROPNAME_FROZEN_UUID,
  -		InternalValue.create(node.getProperty(VersionImpl.PROPNAME_UUID).getString()));
  -	internalSetProperty(VersionImpl.PROPNAME_FROZEN_PRIMARY_TYPE,
  -		InternalValue.create(node.getProperty(VersionImpl.PROPNAME_PRIMARYTYPE).getString()));
  -
  -	if (node.hasProperty(VersionImpl.PROPNAME_MIXINTYPES)) {
  -	    internalSetProperty(VersionImpl.PROPNAME_FROZEN_MIXIN_TYPES,
  -		    InternalValue.create(node.getProperty(VersionImpl.PROPNAME_MIXINTYPES).getString()));
  -	}
       }
   
   
  
  
  
  1.3       +129 -19   jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/version/VersionManager.java
  
  Index: VersionManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/version/VersionManager.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- VersionManager.java	20 Jul 2004 08:28:37 -0000	1.2
  +++ VersionManager.java	21 Jul 2004 16:58:04 -0000	1.3
  @@ -23,13 +23,16 @@
    */
   package org.apache.slide.jcr.core.version;
   
  -import org.apache.slide.jcr.core.*;
   import org.apache.slide.jcr.core.nodetype.NodeTypeRegistry;
  +import org.apache.slide.jcr.core.*;
  +import org.apache.slide.jcr.util.UUID;
  +import org.apache.log4j.Logger;
   
  -import javax.jcr.Node;
   import javax.jcr.RepositoryException;
  -import javax.jcr.version.Version;
  +import javax.jcr.Node;
  +import javax.jcr.Value;
   import javax.jcr.version.VersionHistory;
  +import javax.jcr.version.Version;
   
   /**
    * This Class implements...
  @@ -39,6 +42,8 @@
    */
   public class VersionManager {
   
  +    private static Logger log = Logger.getLogger(VersionManager.class);
  +
       // root path for version storage
       public static final QName VERSION_HISTORY_ROOT_NAME =
   	    new QName(NamespaceRegistryImpl.NS_JCR_URI, "versionStorage");
  @@ -46,14 +51,11 @@
       // the system ticket for the versioning
       private final TicketImpl ticket;
   
  -    /**
  -     * the root node of the version histories
  -     */
  +    /** the root node of the version histories */
       private final Node historyRoot;
   
       /**
        * Creates a new VersionManager.
  -     *
        * @param ticket
        * @throws RepositoryException
        */
  @@ -64,15 +66,19 @@
   	Node systemRoot = ((RepositoryImpl) ticket.getRepository()).getSystemRootNode(ticket);
   	if (!systemRoot.hasNode(VERSION_HISTORY_ROOT_NAME.toJCRName(ticket.getNamespaceResolver()))) {
   	    // if not exist, create
  -	    systemRoot.addNode(VERSION_HISTORY_ROOT_NAME.toJCRName(ticket.getNamespaceResolver()), NodeTypeRegistry.NT_UNSTRUCTURED.toJCRName(ticket.getNamespaceResolver()));
  +	    systemRoot.addNode(VERSION_HISTORY_ROOT_NAME.toJCRName(
  +		    ticket.getNamespaceResolver()),
  +		    NodeTypeRegistry.NT_UNSTRUCTURED.toJCRName(ticket.getNamespaceResolver())
  +	    );
   	    systemRoot.save();
   	}
  -	historyRoot = systemRoot.getNode(VERSION_HISTORY_ROOT_NAME.toJCRName(ticket.getNamespaceResolver()));
  +	historyRoot = systemRoot.getNode(
  +		VERSION_HISTORY_ROOT_NAME.toJCRName(ticket.getNamespaceResolver())
  +	);
       }
   
       /**
        * Creates a new Version History and returns the UUID of it.
  -     *
        * @param node the node for which the version history is to be initialized
        * @return the UUID of the new version history node
        * @throws RepositoryException
  @@ -88,8 +94,12 @@
   	}
   
   	// create new history node
  -	VersionHistoryImpl vh = VersionHistoryImpl.create((NodeImpl) historyRoot.addNode(relPath,
  -		NodeTypeRegistry.NT_VERSION_HISTORY.toJCRName(ticket.getNamespaceResolver())));
  +	VersionHistoryImpl vh = VersionHistoryImpl.create(
  +		(NodeImpl) historyRoot.addNode(
  +			relPath,
  +			NodeTypeRegistry.NT_VERSION_HISTORY.toJCRName(ticket.getNamespaceResolver())
  +		)
  +	);
   
   	// and initialize the root version
   	((VersionImpl) vh.getRootVersion()).initFrozenState(node);
  @@ -103,24 +113,124 @@
   
       /**
        * Returns the base version of the given node. assuming mix:versionable
  -     *
        * @param node
        * @return
        * @throws RepositoryException
        */
       public Version getBaseVersion(NodeImpl node) throws RepositoryException {
  -	return (Version) node.getProperty(VersionImpl.PROPNAME_BASE_VERSION).getItem();
  +	return (Version) node.getTicket().getNodeByUUID(
  +		node.getProperty(
  +			VersionImpl.PROPNAME_BASE_VERSION
  +		).getString()
  +	);
       }
   
       /**
        * Returns the version history for the given node. assuming mix:versionable
        * and version history set in property
  -     *
        * @param node
        * @return
        * @throws RepositoryException
        */
  -    public VersionHistory getVersionHistory(NodeImpl node) throws RepositoryException {
  -	return VersionHistoryImpl.create((NodeImpl) node.getTicket().getNodeByUUID(node.getProperty(VersionImpl.PROPNAME_VERSION_HISTORY).getString()));
  +    public VersionHistoryImpl getVersionHistory(NodeImpl node) throws RepositoryException {
  +	return VersionHistoryImpl.create(
  +		(NodeImpl) node.getTicket().getNodeByUUID(
  +			node.getProperty(
  +				VersionImpl.PROPNAME_VERSION_HISTORY
  +			).getString()
  +		)
  +	);
  +    }
  +
  +    /**
  +     * Checks in a node
  +     * @see Node#checkin()
  +     * @param node
  +     * @return
  +     * @throws RepositoryException
  +     */
  +    public Version checkin(NodeImpl node) throws RepositoryException {
  +	// assuming node is versionable and checkout (check in nodeimpl)
  +	// To create a new version of a versionable node N, the client calls N.checkin.
  +	//  This causes the following series of events:
  +
  +	// 0. collect some values
  +	// todo: simplyfy, as soon as mandatroy mv cannot return null
  +	Value[] values = node.hasProperty(VersionImpl.PROPNAME_PREDESESSORS)
  +		? node.getProperty(VersionImpl.PROPNAME_PREDESESSORS).getValues()
  +		: null;
  +	VersionImpl[] preds = values==null
  +		? new VersionImpl[]{(VersionImpl) node.getBaseVersion()}
  +		: new VersionImpl[values.length];
  +	if (values!=null) {
  +	    for (int i=0; i<values.length; i++) {
  +		preds[i] = (VersionImpl) node.getTicket().getNodeByUUID(values[i].getString());
  +	    }
  +	}
  +
  +	// 0.1 search a predecessor, suitable for generating the new name
  +	String versionName=null;
  +	for (int i=0; i<preds.length; i++) {
  +	    // take the first pred. without a successor
  +	    if (preds[i].getSuccessors().length==0) {
  +		versionName = preds[i].getName();
  +		int pos = versionName.lastIndexOf('.');
  +		versionName = pos<0 ? "1.0" : versionName.substring(0, pos+1) + (Integer.parseInt(versionName.substring(pos+1))+1);
  +		break;
  +	    }
  +	}
  +	// if no empty found, generate new name
  +	if (versionName==null) {
  +	    versionName = preds[0].getName()+".1";
  +	}
  +
  +	VersionHistoryImpl vh = getVersionHistory(node);
  +	try {
  +	    // 1. A new nt:version node V is created and added as a child node to VH,
  +	    //    the nt:versionHistory pointed to by N�s jcr:versionHistory property.
  +	    VersionImpl v = (VersionImpl) vh.addNode(
  +		    versionName,
  +		    NodeTypeRegistry.NT_VERSION.toJCRName(ticket.getNamespaceResolver())
  +	    );
  +
  +	    // 3. N�s base version is changed to V by altering N�s jcr:baseVersion
  +	    //    property to point to V.
  +	    //   (will be done in the nodeimpl)
  +
  +	    // 4. N�s checked-in/checked-out status is changed to checked-in by
  +	    //    changing its jcr:isCheckedOut property to false.
  +	    //    (will be done in NodeImpl)
  +
  +	    // 5. The state of N is recorded in V by storing information about
  +	    //    N�s child items (properties or child nodes) to V, as prescribed by
  +	    //    the OnParentVersion attribute of each of N�s child items.
  +	    //    See 7.2.8, below, for the details. The jcr:primaryType,
  +	    //    jcr:mixinTypes and jcr:uuid properties of N are copied over to V
  +	    //    but renamed to jcr:frozenPrimaryType, jcr:frozenMixinTypes and
  +	    //    jcr:frozenUUID to avoid conflict with V's own properties with these names.
  +	    v.createFrozenState(node);
  +
  +	    // 2. N�s current jcr:predecessors property is copied to V, and N�s
  +	    //    jcr:predecessors property is then set to null.  A reference to V
  +	    //    is then added to the jcr:successors property of each of the versions
  +	    //    identified in V�s jcr:predecessors property.
  +	    InternalValue[] ivPreds = new InternalValue[preds.length];
  +	    for (int i=0; i<preds.length; i++) {
  +		ivPreds[i] = InternalValue.create(new UUID(preds[i].getUUID()));
  +		preds[i].internalAddSuccessor(v);
  +	    }
  +	    v.internalSetProperty(VersionImpl.PROPNAME_PREDESESSORS, ivPreds);
  +
  +	    // 6. V is given a name, sometimes based upon the name of V�s predecessor.
  +	    //    For example, an increment from �1.5� to �1.6�.
  +	    // (is done before)
  +	    vh.save();
  +	    return v;
  +
  +	} catch (RepositoryException e) {
  +	    log.error("Aborting checkin. Error while creating version: " + e.toString());
  +	    vh.refresh(false);
  +	    throw e;
  +	}
       }
   }
  
  
  
  1.6       +18 -2     jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/util/ValueHelper.java
  
  Index: ValueHelper.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/util/ValueHelper.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ValueHelper.java	20 Jul 2004 08:28:38 -0000	1.5
  +++ ValueHelper.java	21 Jul 2004 16:58:04 -0000	1.6
  @@ -264,4 +264,20 @@
   	}
   	return newVal;
       }
  +
  +    /**
  +     * @param srcVal
  +     * @return
  +     * @throws IllegalStateException
  +     */
  +    public static Value[] copy(Value[] srcVal) throws IllegalStateException {
  +	if (srcVal == null) {
  +	    return null;
  +	}
  +	Value[] newVal = new Value[srcVal.length];
  +	for (int i = 0; i < srcVal.length; i++) {
  +	    newVal[i] = copy(srcVal[i]);
  +	}
  +	return newVal;
  +    }
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: slide-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: slide-dev-help@jakarta.apache.org