📄 lockmanagerimpl.java
字号:
/* * 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.lock;import EDU.oswego.cs.dl.util.concurrent.ReentrantLock;import org.apache.commons.collections.map.LinkedMap;import org.apache.jackrabbit.core.ItemId;import org.apache.jackrabbit.core.NodeId;import org.apache.jackrabbit.core.NodeImpl;import org.apache.jackrabbit.util.PathMap;import org.apache.jackrabbit.core.SessionImpl;import org.apache.jackrabbit.core.SessionListener;import org.apache.jackrabbit.core.util.Dumpable;import org.apache.jackrabbit.core.cluster.LockEventChannel;import org.apache.jackrabbit.core.cluster.LockEventListener;import org.apache.jackrabbit.core.cluster.ClusterOperation;import org.apache.jackrabbit.core.fs.FileSystem;import org.apache.jackrabbit.core.fs.FileSystemException;import org.apache.jackrabbit.core.fs.FileSystemResource;import org.apache.jackrabbit.core.observation.EventImpl;import org.apache.jackrabbit.core.observation.SynchronousEventListener;import org.apache.jackrabbit.name.MalformedPathException;import org.apache.jackrabbit.name.NamespaceResolver;import org.apache.jackrabbit.name.Path;import org.apache.jackrabbit.name.QName;import org.apache.jackrabbit.name.PathFormat;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.jcr.ItemNotFoundException;import javax.jcr.Node;import javax.jcr.PathNotFoundException;import javax.jcr.RepositoryException;import javax.jcr.Session;import javax.jcr.lock.Lock;import javax.jcr.lock.LockException;import javax.jcr.observation.Event;import javax.jcr.observation.EventIterator;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintStream;import java.util.ArrayList;import java.util.Iterator;/** * Provides the functionality needed for locking and unlocking nodes. */public class LockManagerImpl implements LockManager, SynchronousEventListener, LockEventListener, Dumpable { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(LockManagerImpl.class); /** * Name of the lock file */ private static final String LOCKS_FILE = "locks"; /** * Path map containing all locks at the leaves. */ private final PathMap lockMap = new PathMap(); /** * Lock to path map. */ private final ReentrantLock lockMapLock = new ReentrantLock(); /** * System session */ private final SessionImpl session; /** * Locks file */ private final FileSystemResource locksFile; /** * Flag indicating whether automatic saving is disabled. */ private boolean savingDisabled; /** * Namespace resolver */ private final NamespaceResolver nsResolver; /** * Lock event channel. */ private LockEventChannel eventChannel; /** * Create a new instance of this class. * * @param session system session * @param fs file system for persisting locks * @throws RepositoryException if an error occurs */ public LockManagerImpl(SessionImpl session, FileSystem fs) throws RepositoryException { this.session = session; this.nsResolver = session.getNamespaceResolver(); this.locksFile = new FileSystemResource(fs, FileSystem.SEPARATOR + LOCKS_FILE); session.getWorkspace().getObservationManager(). addEventListener(this, Event.NODE_ADDED | Event.NODE_REMOVED, "/", true, null, null, true); try { if (locksFile.exists()) { load(); } } catch (FileSystemException e) { throw new RepositoryException("I/O error while reading locks from '" + locksFile.getPath() + "'", e); } } /** * Close this lock manager. Writes back all changes. */ public void close() { save(); } /** * Read locks from locks file and populate path map */ private void load() throws FileSystemException { BufferedReader reader = null; try { reader = new BufferedReader( new InputStreamReader(locksFile.getInputStream())); while (true) { String s = reader.readLine(); if (s == null || s.equals("")) { break; } reapplyLock(LockToken.parse(s)); } } catch (IOException e) { throw new FileSystemException("error while reading locks file", e); } finally { if (reader != null) { try { reader.close(); } catch (IOException e2) { /* ignore */ } } } } /** * Reapply a lock given a lock token that was read from the locks file * * @param lockToken lock token to apply */ private void reapplyLock(LockToken lockToken) { try { NodeImpl node = (NodeImpl) session.getItemManager().getItem(lockToken.id); Path path = getPath(lockToken.id); LockInfo info = new LockInfo(lockToken, false, node.getProperty(QName.JCR_LOCKISDEEP).getBoolean(), node.getProperty(QName.JCR_LOCKOWNER).getString()); info.setLive(true); lockMap.put(path, info); } catch (RepositoryException e) { log.warn("Unable to recreate lock '" + lockToken + "': " + e.getMessage()); log.debug("Root cause: ", e); } } /** * Write locks to locks file */ private void save() { if (savingDisabled) { return; } final ArrayList list = new ArrayList(); lockMap.traverse(new PathMap.ElementVisitor() { public void elementVisited(PathMap.Element element) { LockInfo info = (LockInfo) element.get(); if (!info.sessionScoped) { list.add(info); } } }, false); BufferedWriter writer = null; try { writer = new BufferedWriter( new OutputStreamWriter(locksFile.getOutputStream())); for (int i = 0; i < list.size(); i++) { AbstractLockInfo info = (AbstractLockInfo) list.get(i); writer.write(info.lockToken.toString()); writer.newLine(); } } catch (FileSystemException fse) { log.warn("I/O error while saving locks to '" + locksFile.getPath() + "': " + fse.getMessage()); log.debug("Root cause: ", fse); } catch (IOException ioe) { log.warn("I/O error while saving locks to '" + locksFile.getPath() + "': " + ioe.getMessage()); log.debug("Root cause: ", ioe); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { // ignore } } } } /** * Internal <code>lock</code> implementation that takes the same parameters * as the public method but will not modify content. * @param node node to lock * @param isDeep whether the lock applies to this node only * @param isSessionScoped whether the lock is session scoped * @return lock * @throws LockException if the node is already locked * @throws RepositoryException if another error occurs */ AbstractLockInfo internalLock(NodeImpl node, boolean isDeep, boolean isSessionScoped) throws LockException, RepositoryException { SessionImpl session = (SessionImpl) node.getSession(); LockInfo info = new LockInfo(new LockToken(node.getNodeId()), isSessionScoped, isDeep, session.getUserID()); ClusterOperation operation = null; boolean successful = false; // Cluster is only informed about open-scoped locks if (eventChannel != null && !isSessionScoped) { operation = eventChannel.create(node.getNodeId(), isDeep, session.getUserID()); } acquire(); try { // check whether node is already locked Path path = getPath(node.getId()); PathMap.Element element = lockMap.map(path, false); LockInfo other = (LockInfo) element.get(); if (other != null) { if (element.hasPath(path)) { throw new LockException("Node already locked: " + node.safeGetJCRPath()); } else if (other.deep) { throw new LockException("Parent node has deep lock."); } } if (info.deep && element.hasPath(path) && element.getChildrenCount() > 0) { throw new LockException("Some child node is locked."); } // create lock token info.setLockHolder(session); info.setLive(true); session.addListener(info); session.addLockToken(info.lockToken.toString(), false); lockMap.put(path, info); if (!info.sessionScoped) { save(); successful = true; } return info; } finally { release(); if (operation != null) { operation.ended(successful); } } } /** * Unlock a node (internal implementation) * @param node node to unlock * @throws LockException if the node can not be unlocked * @throws RepositoryException if another error occurs */ void internalUnlock(NodeImpl node) throws LockException, RepositoryException { ClusterOperation operation = null; boolean successful = false; if (eventChannel != null) { operation = eventChannel.create(node.getNodeId()); } acquire(); try { SessionImpl session = (SessionImpl) node.getSession(); // check whether node is locked by this session PathMap.Element element = lockMap.map( getPath(node.getId()), true); if (element == null) { throw new LockException("Node not locked: " + node.safeGetJCRPath()); } AbstractLockInfo info = (AbstractLockInfo) element.get(); if (info == null) { throw new LockException("Node not locked: " + node.safeGetJCRPath()); } if (session != info.getLockHolder()) { throw new LockException("Node not locked by session: " + node.safeGetJCRPath()); } session.removeLockToken(info.getLockToken(session), false); element.set(null); info.setLive(false); if (!info.sessionScoped) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -