Package org.apache.jackrabbit.core

Source Code of org.apache.jackrabbit.core.WorkspaceImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.core;

import java.util.HashMap;

import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidItemStateException;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.NamespaceRegistry;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.observation.ObservationManager;
import javax.jcr.query.QueryManager;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionManager;

import org.apache.jackrabbit.api.JackrabbitWorkspace;
import org.apache.jackrabbit.commons.AbstractWorkspace;
import org.apache.jackrabbit.core.config.WorkspaceConfig;
import org.apache.jackrabbit.core.id.ItemId;
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.lock.LockManager;
import org.apache.jackrabbit.core.lock.SessionLockManager;
import org.apache.jackrabbit.core.observation.EventStateCollection;
import org.apache.jackrabbit.core.observation.EventStateCollectionFactory;
import org.apache.jackrabbit.core.observation.ObservationManagerImpl;
import org.apache.jackrabbit.core.query.QueryManagerImpl;
import org.apache.jackrabbit.core.retention.RetentionRegistry;
import org.apache.jackrabbit.core.state.LocalItemStateManager;
import org.apache.jackrabbit.core.state.SharedItemStateManager;
import org.apache.jackrabbit.core.version.DateVersionSelector;
import org.apache.jackrabbit.core.version.JcrVersionManagerImpl;
import org.apache.jackrabbit.core.version.VersionImpl;
import org.apache.jackrabbit.core.version.VersionSelector;
import org.apache.jackrabbit.core.xml.ImportHandler;
import org.apache.jackrabbit.core.xml.Importer;
import org.apache.jackrabbit.core.xml.WorkspaceImporter;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.commons.conversion.NameException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;

/**
* A <code>WorkspaceImpl</code> ...
*/
public class WorkspaceImpl extends AbstractWorkspace
        implements JackrabbitWorkspace, javax.jcr.Workspace,
        EventStateCollectionFactory {

    private static Logger log = LoggerFactory.getLogger(WorkspaceImpl.class);

    /**
     * The configuration of this <code>Workspace</code>
     */
    protected final WorkspaceConfig wspConfig;

    /**
     * The repository that created this workspace instance
     */
    protected final RepositoryImpl rep;

    /**
     * The persistent state mgr associated with the workspace represented by <i>this</i>
     * <code>Workspace</code> instance.
     */
    protected final LocalItemStateManager stateMgr;

    /**
     * The hierarchy mgr that reflects persistent state only
     * (i.e. that is isolated from transient changes made through
     * the session).
     */
    protected final CachingHierarchyManager hierMgr;

    /**
     * The <code>ObservationManager</code> instance for this session.
     */
    protected ObservationManagerImpl obsMgr;

    /**
     * The <code>QueryManager</code> for this <code>Workspace</code>.
     */
    protected QueryManagerImpl queryManager;

    /**
     * the session that was used to acquire this <code>Workspace</code>
     */
    protected final SessionImpl session;

    /**
     * The <code>LockManager</code> for this <code>Workspace</code>
     */
    protected LockManager lockMgr;

    /**
     * The API LockManager for this workspace, used to create and release
     * locks and determine the lock status.
     */
    private javax.jcr.lock.LockManager jcr283LockManager;

    /**
     * The API Version manager for this workspace
     */
    protected JcrVersionManagerImpl versionMgr;

    /**
     * The internal manager used to evaluate effective retention policies and
     * holds.
     */
    private RetentionRegistry retentionRegistry;

    /**
     * Protected constructor.
     *
     * @param wspConfig The workspace configuration
     * @param stateMgr  The shared item state manager
     * @param rep       The repository
     * @param session   The session
     */
    protected WorkspaceImpl(WorkspaceConfig wspConfig,
                            SharedItemStateManager stateMgr, RepositoryImpl rep,
                            SessionImpl session) {
        this.wspConfig = wspConfig;
        this.rep = rep;
        this.stateMgr = createItemStateManager(stateMgr);
        this.hierMgr =
            new CachingHierarchyManager(rep.getRootNodeId(), this.stateMgr);
        this.stateMgr.addListener(hierMgr);
        this.session = session;
    }

    /**
     * The hierarchy manager that reflects workspace state only
     * (i.e. that is isolated from transient changes made through
     * the session)
     *
     * @return the hierarchy manager of this workspace
     */
    public HierarchyManager getHierarchyManager() {
        return hierMgr;
    }

    /**
     * Returns the item state manager associated with the workspace
     * represented by <i>this</i> <code>WorkspaceImpl</code> instance.
     *
     * @return the item state manager of this workspace
     */
    public LocalItemStateManager getItemStateManager() {
        return stateMgr;
    }

    /**
     * Disposes this <code>WorkspaceImpl</code> and frees resources.
     */
    void dispose() {
        if (obsMgr != null) {
            obsMgr.dispose();
            obsMgr = null;
        }
        stateMgr.dispose();
    }

    /**
     * Performs a sanity check on this workspace and the associated session.
     *
     * @throws RepositoryException if this workspace has been rendered invalid
     *                             for some reason
     */
    public void sanityCheck() throws RepositoryException {
        // check session status
        session.sanityCheck();
    }

    //--------------------------------------------------< new JSR 283 methods >
    /**
     * {@inheritDoc}
     */
    public void createWorkspace(String name, String srcWorkspace)
            throws AccessDeniedException, UnsupportedRepositoryOperationException,
            RepositoryException {
        // check state of this instance
        sanityCheck();

        session.createWorkspace(name);

        SessionImpl tmpSession = null;
        try {
            // create a temporary session on new workspace for current subject
            tmpSession = rep.createSession(session.getSubject(), name);
            WorkspaceImpl newWsp = (WorkspaceImpl) tmpSession.getWorkspace();

            newWsp.clone(srcWorkspace, "/", "/", false);
        } finally {
            if (tmpSession != null) {
                // we don't need the temporary session anymore, logout
                tmpSession.logout();
            }
        }
    }

    /**
     * {@inheritDoc}
     * <p/>
     * Always throws <code>UnsupportedRepositoryOperationException</code> since
     * removal of workspaces is currently not supported.
     */
    public void deleteWorkspace(String name) throws AccessDeniedException,
            UnsupportedRepositoryOperationException, RepositoryException {
        // check if workspace exists (will throw NoSuchWorkspaceException if not)
        rep.getWorkspaceInfo(name);
        // todo implement deleteWorkspace
        throw new UnsupportedRepositoryOperationException("not yet implemented");
    }

    /**
     * @see javax.jcr.Workspace#getLockManager()
     * @see javax.jcr.lock.LockManager
     */
    public javax.jcr.lock.LockManager getLockManager() throws UnsupportedRepositoryOperationException, RepositoryException {
        if (jcr283LockManager == null) {
            jcr283LockManager = new SessionLockManager(session, session.getLockManager());
        }
        return jcr283LockManager;
    }

    /**
     * @see javax.jcr.Workspace#getVersionManager()
     */
    public VersionManager getVersionManager()
            throws UnsupportedRepositoryOperationException, RepositoryException {
        if (versionMgr == null) {
            versionMgr = new JcrVersionManagerImpl(session);
        }
        return versionMgr;
    }

    //-------------------------------< JackrabbitWorkspace/new JSR 283 method >

    /**
     * Creates a new <code>Workspace</code> with the specified
     * <code>name</code>. The new workspace is empty, meaning it contains only
     * root node.
     * <p/>
     * The new workspace can be accessed through a <code>login</code>
     * specifying its name.
     * <p/>
     * Throws an <code>AccessDeniedException</code> if the session through which
     * this <code>Workspace</code> object was acquired does not have permission
     * to create the new workspace.
     * <p/>
     * Throws an <code>UnsupportedRepositoryOperationException</code> if the repository does
     * not support the creation of workspaces.
     * <p/>
     * A <code>RepositoryException</code> is thrown if another error occurs.
     *
     * @param name A <code>String</code>, the name of the new workspace.
     * @throws AccessDeniedException if the session through which
     * this <code>Workspace</code> object was acquired does not have permission
     * to create the new workspace.
     * @throws UnsupportedRepositoryOperationException if the repository does
     * not support the creation of workspaces.
     * @throws RepositoryException if another error occurs.
     * @since JCR 2.0
     */
    public void createWorkspace(String name)
            throws AccessDeniedException,
            UnsupportedRepositoryOperationException,
            RepositoryException {
        // check state of this instance
        sanityCheck();

        session.createWorkspace(name);
    }

    //--------------------------------------------------< JackrabbitWorkspace >
    /**
     * Creates a workspace with the given name and a workspace configuration
     * template.
     *
     * @param workspaceName name of the new workspace
     * @param configTemplate the configuration template of the new workspace
     * @throws AccessDeniedException if the current session is not allowed to
     *                               create the workspace
     * @throws RepositoryException   if a workspace with the given name
     *                               already exists or if another error occurs
     * @see #getAccessibleWorkspaceNames()
     */
    public void createWorkspace(String workspaceName, InputSource configTemplate)
            throws AccessDeniedException, RepositoryException {
        // check state of this instance
        sanityCheck();

        session.createWorkspace(workspaceName, configTemplate);
    }

    /**
     * Returns the configuration of this workspace.
     * @return the workspace configuration
     */
    public WorkspaceConfig getConfig() {
        return wspConfig;
    }

    /**
     * @param srcAbsPath
     * @param srcWsp
     * @param destAbsPath
     * @param flag        one of
     *                    <ul>
     *                    <li><code>COPY</code></li>
     *                    <li><code>CLONE</code></li>
     *                    <li><code>CLONE_REMOVE_EXISTING</code></li>
     *                    </ul>
     * @return the path of the node at its new position
     * @throws ConstraintViolationException
     * @throws AccessDeniedException
     * @throws VersionException
     * @throws PathNotFoundException
     * @throws ItemExistsException
     * @throws LockException
     * @throws RepositoryException
     */
    private String internalCopy(String srcAbsPath,
                              WorkspaceImpl srcWsp,
                              String destAbsPath,
                              int flag)
            throws ConstraintViolationException, AccessDeniedException,
            VersionException, PathNotFoundException, ItemExistsException,
            LockException, RepositoryException {

        Path srcPath;
        try {
            srcPath = session.getQPath(srcAbsPath).getNormalizedPath();
        } catch (NameException e) {
            String msg = "invalid path: " + srcAbsPath;
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }
        if (!srcPath.isAbsolute()) {
            throw new RepositoryException("not an absolute path: " + srcAbsPath);
        }

        Path destPath;
        try {
            destPath = session.getQPath(destAbsPath).getNormalizedPath();
        } catch (NameException e) {
            String msg = "invalid path: " + destAbsPath;
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }
        if (!destPath.isAbsolute()) {
            throw new RepositoryException("not an absolute path: " + destAbsPath);
        }

        BatchedItemOperations ops = new BatchedItemOperations(
                stateMgr, rep.getNodeTypeRegistry(), session.getLockManager(),
                session, hierMgr);

        try {
            ops.edit();
        } catch (IllegalStateException e) {
            String msg = "unable to start edit operation";
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }

        boolean succeeded = false;

        try {
            NodeId id = ops.copy(srcPath, srcWsp.getItemStateManager(),
                    srcWsp.getHierarchyManager(),
                    ((SessionImpl) srcWsp.getSession()).getAccessManager(),
                    destPath, flag);
            ops.update();
            succeeded = true;
            return session.getJCRPath(hierMgr.getPath(id));
        } finally {
            if (!succeeded) {
                // update operation failed, cancel all modifications
                ops.cancel();
            }
        }
    }

    /**
     * Handles a clone inside the same workspace, which is supported with
     * shareable nodes.
     *
     * @see {@link #clone()}
     *
     * @param srcAbsPath source path
     * @param destAbsPath destination path
     * @return the path of the node at its new position
     * @throws ConstraintViolationException
     * @throws AccessDeniedException
     * @throws VersionException
     * @throws PathNotFoundException
     * @throws ItemExistsException
     * @throws LockException
     * @throws RepositoryException
     */
    private String internalClone(String srcAbsPath, String destAbsPath)
            throws ConstraintViolationException, AccessDeniedException,
                   VersionException, PathNotFoundException, ItemExistsException,
                   LockException, RepositoryException {

        Path srcPath;
        try {
            srcPath = session.getQPath(srcAbsPath).getNormalizedPath();
        } catch (NameException e) {
            String msg = "invalid path: " + srcAbsPath;
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }
        if (!srcPath.isAbsolute()) {
            throw new RepositoryException("not an absolute path: " + srcAbsPath);
        }

        Path destPath;
        try {
            destPath = session.getQPath(destAbsPath).getNormalizedPath();
        } catch (NameException e) {
            String msg = "invalid path: " + destAbsPath;
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }
        if (!destPath.isAbsolute()) {
            throw new RepositoryException("not an absolute path: " + destAbsPath);
        }

        BatchedItemOperations ops = new BatchedItemOperations(
                stateMgr, rep.getNodeTypeRegistry(), session.getLockManager(),
                session, hierMgr);

        try {
            ops.edit();
        } catch (IllegalStateException e) {
            String msg = "unable to start edit operation";
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }

        boolean succeeded = false;

        try {
            ItemId id = ops.clone(srcPath, destPath);
            ops.update();
            succeeded = true;
            return session.getJCRPath(hierMgr.getPath(id));
        } finally {
            if (!succeeded) {
                // update operation failed, cancel all modifications
                ops.cancel();
            }
        }
    }

    /**
     * Return the lock manager for this workspace. If not already done, creates
     * a new instance.
     *
     * @return lock manager for this workspace
     * @throws RepositoryException if an error occurs
     */
    public synchronized org.apache.jackrabbit.core.lock.LockManager getInternalLockManager() throws RepositoryException {

        // check state of this instance
        sanityCheck();

        if (lockMgr == null) {
            lockMgr = rep.getLockManager(wspConfig.getName());
        }
        return lockMgr;
    }

    /**
     * Return the internal effective retention/hold manager for this workspace.
     * If not already done, creates a new instance.
     *
     * @return effective retention/hold manager for this workspace
     * @throws RepositoryException if an error occurs
     */
    synchronized RetentionRegistry getRetentionRegistry() throws RepositoryException {
        // check state of this instance
        sanityCheck();
        if (retentionRegistry == null) {
            retentionRegistry = rep.getRetentionRegistry(wspConfig.getName());
        }
        return retentionRegistry;
    }

    //------------------------------------------------------------< Workspace >
    /**
     * {@inheritDoc}
     */
    public String getName() {
        return wspConfig.getName();
    }

    /**
     * {@inheritDoc}
     */
    public Session getSession() {
        return session;
    }

    /**
     * {@inheritDoc}
     */
    public NamespaceRegistry getNamespaceRegistry() throws RepositoryException {
        // check state of this instance
        sanityCheck();

        return rep.getNamespaceRegistry();
    }

    /**
     * {@inheritDoc}
     */
    public NodeTypeManager getNodeTypeManager() throws RepositoryException {
        // check state of this instance
        sanityCheck();

        return session.getNodeTypeManager();
    }

    /**
     * {@inheritDoc}
     */
    public void clone(String srcWorkspace, String srcAbsPath,
                      String destAbsPath, boolean removeExisting)
            throws NoSuchWorkspaceException, ConstraintViolationException,
            VersionException, AccessDeniedException, PathNotFoundException,
            ItemExistsException, LockException, RepositoryException {
        // check state of this instance
        sanityCheck();

        // check workspace name
        if (getName().equals(srcWorkspace)) {
            // clone to same workspace is allowed for mix:shareable nodes,
            // but only if removeExisting is false
            if (!removeExisting) {
                internalClone(srcAbsPath, destAbsPath);
                return;
            }
            // same as current workspace
            String msg = srcWorkspace + ": illegal workspace (same as current)";
            log.debug(msg);
            throw new RepositoryException(msg);
        }

        // check authorization for specified workspace
        if (!session.getAccessManager().canAccess(srcWorkspace)) {
            throw new AccessDeniedException("not authorized to access " + srcWorkspace);
        }

        // clone (i.e. pull) subtree at srcAbsPath from srcWorkspace
        // to 'this' workspace at destAbsPath

        SessionImpl srcSession = null;
        try {
            // create session on other workspace for current subject
            // (may throw NoSuchWorkspaceException and AccessDeniedException)
            srcSession = rep.createSession(session.getSubject(), srcWorkspace);
            WorkspaceImpl srcWsp = (WorkspaceImpl) srcSession.getWorkspace();

            // do cross-workspace copy
            int mode = BatchedItemOperations.CLONE;
            if (removeExisting) {
                mode = BatchedItemOperations.CLONE_REMOVE_EXISTING;
            }
            internalCopy(srcAbsPath, srcWsp, destAbsPath, mode);
        } finally {
            if (srcSession != null) {
                // we don't need the other session anymore, logout
                srcSession.logout();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void copy(String srcAbsPath, String destAbsPath)
            throws ConstraintViolationException, VersionException,
            AccessDeniedException, PathNotFoundException, ItemExistsException,
            LockException, RepositoryException {
        // check state of this instance
        sanityCheck();

        // do intra-workspace copy
        internalCopy(srcAbsPath, this, destAbsPath, BatchedItemOperations.COPY);
    }

    /**
     * {@inheritDoc}
     */
    public void copy(String srcWorkspace, String srcAbsPath, String destAbsPath)
            throws NoSuchWorkspaceException, ConstraintViolationException,
            VersionException, AccessDeniedException, PathNotFoundException,
            ItemExistsException, LockException, RepositoryException {

        // check state of this instance
        sanityCheck();

        // check workspace name
        if (getName().equals(srcWorkspace)) {
            // same as current workspace, delegate to intra-workspace copy method
            copy(srcAbsPath, destAbsPath);
            return;
        }

        // check authorization for specified workspace
        if (!session.getAccessManager().canAccess(srcWorkspace)) {
            throw new AccessDeniedException("not authorized to access " + srcWorkspace);
        }

        // copy (i.e. pull) subtree at srcAbsPath from srcWorkspace
        // to 'this' workspace at destAbsPath

        SessionImpl srcSession = null;
        try {
            // create session on other workspace for current subject
            // (may throw NoSuchWorkspaceException and AccessDeniedException)
            srcSession = rep.createSession(session.getSubject(), srcWorkspace);
            WorkspaceImpl srcWsp = (WorkspaceImpl) srcSession.getWorkspace();

            // do cross-workspace copy
            internalCopy(srcAbsPath, srcWsp, destAbsPath, BatchedItemOperations.COPY);
        } finally {
            if (srcSession != null) {
                // we don't need the other session anymore, logout
                srcSession.logout();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void move(String srcAbsPath, String destAbsPath)
            throws ConstraintViolationException, VersionException,
            AccessDeniedException, PathNotFoundException, ItemExistsException,
            LockException, RepositoryException {
        // check state of this instance
        sanityCheck();

        // intra-workspace move...

        Path srcPath;
        try {
            srcPath = session.getQPath(srcAbsPath).getNormalizedPath();
        } catch (NameException e) {
            String msg = "invalid path: " + srcAbsPath;
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }
        if (!srcPath.isAbsolute()) {
            throw new RepositoryException("not an absolute path: " + srcAbsPath);
        }

        Path destPath;
        try {
            destPath = session.getQPath(destAbsPath).getNormalizedPath();
        } catch (NameException e) {
            String msg = "invalid path: " + destAbsPath;
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }
        if (!destPath.isAbsolute()) {
            throw new RepositoryException("not an absolute path: " + destAbsPath);
        }

        BatchedItemOperations ops = new BatchedItemOperations(
                stateMgr, rep.getNodeTypeRegistry(), session.getLockManager(),
                session, hierMgr);

        try {
            ops.edit();
        } catch (IllegalStateException e) {
            String msg = "unable to start edit operation";
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }

        boolean succeeded = false;

        try {
            ops.move(srcPath, destPath);
            ops.update();
            succeeded = true;
        } finally {
            if (!succeeded) {
                // update operation failed, cancel all modifications
                ops.cancel();
            }
        }
    }

    /**
     * Returns the observation manager of this session. The observation manager
     * is lazily created if it does not exist yet.
     *
     * @return the observation manager of this session
     * @throws RepositoryException if a repository error occurs
     */
    public ObservationManager getObservationManager()
            throws RepositoryException {
        // check state of this instance
        sanityCheck();

        if (obsMgr == null) {
            try {
                obsMgr = new ObservationManagerImpl(
                        rep.getObservationDispatcher(wspConfig.getName()),
                        session,
                        session.getItemManager(),
                        rep.getClusterNode());
            } catch (NoSuchWorkspaceException nswe) {
                // should never get here
                String msg = "internal error: failed to instantiate observation manager";
                log.debug(msg);
                throw new RepositoryException(msg, nswe);
            }
        }
        return obsMgr;
    }

    /**
     * {@inheritDoc}
     */
    public synchronized QueryManager getQueryManager() throws RepositoryException {

        // check state of this instance
        sanityCheck();

        if (queryManager == null) {
            SearchManager searchManager;
            try {
                searchManager = rep.getSearchManager(wspConfig.getName());
                if (searchManager == null) {
                    String msg = "no search manager configured for this workspace";
                    log.debug(msg);
                    throw new RepositoryException(msg);
                }
            } catch (NoSuchWorkspaceException nswe) {
                // should never get here
                String msg = "internal error: failed to instantiate query manager";
                log.debug(msg);
                throw new RepositoryException(msg, nswe);
            }
            queryManager = new QueryManagerImpl(session, session.getItemManager(), searchManager);
        }
        return queryManager;
    }

    /**
     * {@inheritDoc}
     */
    public void restore(Version[] versions, boolean removeExisting)
            throws ItemExistsException, UnsupportedRepositoryOperationException,
            VersionException, LockException, InvalidItemStateException,
            RepositoryException {

        // todo: perform restore operations direct on the node states

        // check state of this instance
        sanityCheck();

        // add all versions to map of versions to restore
        final HashMap<String, VersionImpl> toRestore = new HashMap<String, VersionImpl>();
        for (Version v : versions) {
            VersionHistory vh = v.getContainingHistory();
            // check for collision
            if (toRestore.containsKey(vh.getUUID())) {
                throw new VersionException("Unable to restore. Two or more versions have same version history.");
            }
            toRestore.put(vh.getUUID(), (VersionImpl) v);
        }

        // create a version selector to the set of versions
        VersionSelector vsel = new VersionSelector() {
            public Version select(VersionHistory versionHistory) throws RepositoryException {
                // try to select version as specified
                Version v = toRestore.get(versionHistory.getUUID());
                if (v == null) {
                    // select latest one
                    v = DateVersionSelector.selectByDate(versionHistory, null);
                }
                return v;
            }
        };

        // check for pending changes
        if (session.hasPendingChanges()) {
            String msg = "Unable to restore version. Session has pending changes.";
            log.debug(msg);
            throw new InvalidItemStateException(msg);
        }
        // TODO: add checks for lock/hold...
        boolean success = false;
        try {
            // now restore all versions that have a node in the ws
            int numRestored = 0;
            while (toRestore.size() > 0) {
                Version[] restored = null;
                for (VersionImpl v : toRestore.values()) {
                    try {
                        NodeImpl node = (NodeImpl) session.getNodeById(v.getInternalFrozenNode().getFrozenId());
                        restored = node.internalRestore(v, vsel, removeExisting);
                        // remove restored versions from set
                        for (Version r : restored) {
                            toRestore.remove(r.getContainingHistory().getUUID());
                        }
                        numRestored += restored.length;
                        break;
                    } catch (ItemNotFoundException e) {
                        // ignore
                    }
                }
                if (restored == null) {
                    if (numRestored == 0) {
                        throw new VersionException("Unable to restore. At least one version needs"
                                + " existing versionable node in workspace.");
                    } else {
                        throw new VersionException("Unable to restore. All versions with non"
                                + " existing versionable nodes need parent.");
                    }
                }
            }
            session.save();
            success = true;
        } finally {
            if (!success) {
                // revert session
                try {
                    log.debug("reverting changes applied during restore...");
                    session.refresh(false);
                } catch (RepositoryException e) {
                    log.error("Error while reverting changes applied during restore.", e);
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public String[] getAccessibleWorkspaceNames() throws RepositoryException {
        // check state of this instance
        sanityCheck();

        return session.getWorkspaceNames();
    }

    /**
     * {@inheritDoc}
     */
    public ContentHandler getImportContentHandler(String parentAbsPath,
                                                  int uuidBehavior)
            throws PathNotFoundException, ConstraintViolationException,
            VersionException, LockException, RepositoryException {

        // check state of this instance
        sanityCheck();

        Path parentPath;
        try {
            parentPath = session.getQPath(parentAbsPath).getNormalizedPath();
        } catch (NameException e) {
            String msg = "invalid path: " + parentAbsPath;
            log.debug(msg);
            throw new RepositoryException(msg, e);
        }
        if (!parentPath.isAbsolute()) {
            throw new RepositoryException("not an absolute path: " + parentAbsPath);
        }

        Importer importer = new WorkspaceImporter(parentPath, this,
                rep.getNodeTypeRegistry(), uuidBehavior);
        return new ImportHandler(importer, session);
    }

    /**
     * Create the persistent item state manager on top of the shared item
     * state manager. May be overridden by subclasses.
     * @param shared shared item state manager
     * @return local item state manager
     */
    protected LocalItemStateManager createItemStateManager(SharedItemStateManager shared) {
        return LocalItemStateManager.createInstance(shared, this, rep.getItemStateCacheFactory());
    }

    //------------------------------------------< EventStateCollectionFactory >
    /**
     * {@inheritDoc}
     * <p/>
     * Implemented in this object and forwarded rather than {@link #obsMgr}
     * since creation of the latter is lazy.
     */
    public EventStateCollection createEventStateCollection()
            throws RepositoryException {

        return ((ObservationManagerImpl) getObservationManager()).createEventStateCollection();
    }
}

TOP

Related Classes of org.apache.jackrabbit.core.WorkspaceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.