You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2009/01/28 10:50:51 UTC
svn commit: r738422 [2/3] - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/
main/java/org/apache/jackrabbit/core/lock/
main/java/org/apache/jackrabbit/core/retention/
main/java/org/apache/jackrabbit/core/security/authori...
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionManagerImpl.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionManagerImpl.java Wed Jan 28 09:50:50 2009
@@ -16,69 +16,193 @@
*/
package org.apache.jackrabbit.core.retention;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.jackrabbit.api.jsr283.retention.RetentionManager;
import org.apache.jackrabbit.api.jsr283.retention.Hold;
+import org.apache.jackrabbit.api.jsr283.retention.RetentionManager;
import org.apache.jackrabbit.api.jsr283.retention.RetentionPolicy;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.ProtectedItemModifier;
+import org.apache.jackrabbit.core.PropertyImpl;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import javax.jcr.PathNotFoundException;
import javax.jcr.AccessDeniedException;
+import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.version.VersionException;
+import javax.jcr.Value;
+import javax.jcr.PropertyType;
import javax.jcr.lock.LockException;
+import javax.jcr.version.VersionException;
+import java.util.ArrayList;
+import java.util.List;
/**
* <code>RetentionManagerImpl</code>...
*/
-public class RetentionManagerImpl implements RetentionManager {
+public class RetentionManagerImpl extends ProtectedItemModifier implements RetentionManager {
private static Logger log = LoggerFactory.getLogger(RetentionManagerImpl.class);
- private final Session session;
-
- public RetentionManagerImpl(Session session) {
+ private static final NameFactory NAME_FACTORY = NameFactoryImpl.getInstance();
+
+ static final Name REP_RETENTION_MANAGEABLE = NAME_FACTORY.create(Name.NS_REP_URI, "RetentionManageable");
+ static final Name REP_HOLD = NAME_FACTORY.create(Name.NS_REP_URI, "hold");
+ static final Name REP_RETENTION_POLICY = NAME_FACTORY.create(Name.NS_REP_URI, "retentionPolicy");
+
+ private final SessionImpl session;
+
+ /**
+ *
+ * @param session The editing session.
+ */
+ public RetentionManagerImpl(SessionImpl session) {
+ super(Permission.RETENTION_MNGMT);
this.session = session;
}
-
+
+ //---------------------------------------------------< RetentionManager >---
+ /**
+ * @see RetentionManager#getHolds(String)
+ */
public Hold[] getHolds(String absPath) throws PathNotFoundException,
AccessDeniedException, RepositoryException {
- //TODO
- return new Hold[0];
+
+ NodeImpl n = (NodeImpl) session.getNode(absPath);
+ session.getAccessManager().checkPermission(session.getQPath(absPath), Permission.RETENTION_MNGMT);
+
+ Hold[] holds;
+ if (n.isNodeType(REP_RETENTION_MANAGEABLE) && n.hasProperty(REP_HOLD)) {
+ holds = HoldImpl.createFromProperty(n.getProperty(REP_HOLD), n.getNodeId());
+ } else {
+ holds = new Hold[0];
+ }
+ return holds;
}
+ /**
+ * @see RetentionManager#addHold(String, String, boolean)
+ */
public Hold addHold(String absPath, String name, boolean isDeep) throws
PathNotFoundException, AccessDeniedException, LockException,
VersionException, RepositoryException {
- //TODO
- throw new UnsupportedOperationException("Not yet implemented");
- }
+ NodeImpl n = (NodeImpl) session.getNode(absPath);
+ if (!n.isNodeType(REP_RETENTION_MANAGEABLE)) {
+ n.addMixin(REP_RETENTION_MANAGEABLE);
+ }
+
+ HoldImpl hold = new HoldImpl(session.getQName(name), isDeep, n.getNodeId(), session);
+ Value[] vls;
+ if (n.hasProperty(REP_HOLD)) {
+ Value[] vs = n.getProperty(REP_HOLD).getValues();
+ // check if the same hold already exists
+ for (int i = 0; i < vs.length; i++) {
+ if (hold.equals(HoldImpl.createFromValue(vs[i], n.getNodeId(), session))) {
+ throw new RepositoryException("Hold already exists.");
+ }
+ }
+ vls = new Value[vs.length + 1];
+ System.arraycopy(vs, 0, vls, 0, vs.length);
+ } else {
+ vls = new Value[1];
+ }
+
+ // add the value of the new hold
+ vls[vls.length - 1] = hold.toValue(session.getValueFactory());
+ setProperty(n, REP_HOLD, vls);
+ return hold;
+ }
+
+ /**
+ * @see RetentionManager#removeHold(String, Hold)
+ */
public void removeHold(String absPath, Hold hold) throws
PathNotFoundException, AccessDeniedException, LockException,
VersionException, RepositoryException {
- //TODO
- throw new UnsupportedOperationException("Not yet implemented");
- }
+ NodeImpl n = (NodeImpl) session.getNode(absPath);
+ if (hold instanceof HoldImpl
+ && n.getNodeId().equals(((HoldImpl) hold).getNodeId())
+ && n.isNodeType(REP_RETENTION_MANAGEABLE)
+ && n.hasProperty(REP_HOLD)) {
+
+ PropertyImpl p = n.getProperty(REP_HOLD);
+ Value[] vls = p.getValues();
+
+ List newValues = new ArrayList(vls.length - 1);
+ for (int i = 0; i < vls.length; i++) {
+ if (!hold.equals(HoldImpl.createFromValue(vls[i], n.getNodeId(), session))) {
+ newValues.add(vls[i]);
+ }
+ }
+ if (newValues.size() < vls.length) {
+ if (newValues.size() == 0) {
+ removeItem(p);
+ } else {
+ setProperty(n, REP_HOLD, (Value[]) newValues.toArray(new Value[newValues.size()]));
+ }
+ } else {
+ // no matching hold.
+ throw new RepositoryException("Cannot remove '" + hold.getName() + "' at " + absPath + ".");
+ }
+ } else {
+ // invalid hold or no hold at absPath
+ throw new RepositoryException("Cannot remove '" + hold.getName() + "' at " + absPath + ".");
+ }
+ }
+
+ /**
+ * @see RetentionManager#getRetentionPolicy(String)
+ */
public RetentionPolicy getRetentionPolicy(String absPath) throws
PathNotFoundException, AccessDeniedException, RepositoryException {
- // TODO
- return null;
+
+ NodeImpl n = (NodeImpl) session.getNode(absPath);
+ session.getAccessManager().checkPermission(session.getQPath(absPath), Permission.RETENTION_MNGMT);
+
+ RetentionPolicy rPolicy = null;
+ if (n.isNodeType(REP_RETENTION_MANAGEABLE) && n.hasProperty(REP_RETENTION_POLICY)) {
+ String jcrName = n.getProperty(REP_RETENTION_POLICY).getString();
+ rPolicy = new RetentionPolicyImpl(jcrName, n.getNodeId(), session);
+ }
+
+ return rPolicy;
}
+ /**
+ * @see RetentionManager#setRetentionPolicy(String, RetentionPolicy)
+ */
public void setRetentionPolicy(String absPath, RetentionPolicy retentionPolicy)
throws PathNotFoundException, AccessDeniedException, LockException,
VersionException, RepositoryException {
- //TODO
- throw new UnsupportedOperationException("Not yet implemented");
+
+ NodeImpl n = (NodeImpl) session.getNode(absPath);
+ if (!(retentionPolicy instanceof RetentionPolicyImpl)) {
+ throw new RepositoryException("Invalid retention policy.");
+ }
+ Value retentionReference = session.getValueFactory().createValue(retentionPolicy.getName(), PropertyType.NAME);
+ if (!n.isNodeType(REP_RETENTION_MANAGEABLE)) {
+ n.addMixin(REP_RETENTION_MANAGEABLE);
+ }
+ setProperty(n, REP_RETENTION_POLICY, retentionReference);
}
+ /**
+ * @see RetentionManager#removeRetentionPolicy(String)
+ */
public void removeRetentionPolicy(String absPath) throws
PathNotFoundException, AccessDeniedException, LockException,
VersionException, RepositoryException {
- //TODO
- throw new UnsupportedOperationException("Not yet implemented");
+
+ NodeImpl n = (NodeImpl) session.getNode(absPath);
+ if (n.isNodeType(REP_RETENTION_MANAGEABLE) && n.hasProperty(REP_RETENTION_POLICY)) {
+ removeItem(n.getProperty(REP_RETENTION_POLICY));
+ } else {
+ throw new RepositoryException("Cannot remove retention policy at absPath.");
+ }
}
}
\ No newline at end of file
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionPolicyImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionPolicyImpl.java?rev=738422&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionPolicyImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionPolicyImpl.java Wed Jan 28 09:50:50 2009
@@ -0,0 +1,93 @@
+/*
+ * 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.retention;
+
+import org.apache.jackrabbit.api.jsr283.retention.RetentionPolicy;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
+import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.NamespaceException;
+
+/**
+ * Basic implementation of the <code>RetentionPolicy</code> interface.
+ */
+public class RetentionPolicyImpl implements RetentionPolicy {
+
+ private final Name name;
+ private final NodeId nodeId;
+ private final NameResolver resolver;
+
+ private int hashCode = 0;
+
+ public RetentionPolicyImpl(String jcrName, NameResolver resolver) throws IllegalNameException, NamespaceException {
+ this(resolver.getQName(jcrName), null, resolver);
+ }
+
+ RetentionPolicyImpl(String jcrName, NodeId nodeId, NameResolver resolver) throws IllegalNameException, NamespaceException {
+ this(resolver.getQName(jcrName), nodeId, resolver);
+ }
+
+ private RetentionPolicyImpl(Name name, NodeId nodeId, NameResolver resolver) {
+ this.name = name;
+ this.nodeId = nodeId;
+ this.resolver = resolver;
+ }
+
+ NodeId getNodeId() {
+ return nodeId;
+ }
+
+ //----------------------------------------------------< RetentionPolicy >---
+ /**
+ * @see org.apache.jackrabbit.api.jsr283.retention.RetentionPolicy#getName()
+ */
+ public String getName() throws RepositoryException {
+ return resolver.getJCRName(name);
+ }
+
+ //-------------------------------------------------------------< Object >---
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode() {
+ if (hashCode == 0) {
+ int h = 17;
+ h = 37 * h + name.hashCode();
+ h = 37 * h + nodeId.hashCode();
+ hashCode = h;
+ }
+ return hashCode;
+ }
+
+ /**
+ * @see Object#equals(Object)
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj instanceof RetentionPolicyImpl) {
+ RetentionPolicyImpl other = (RetentionPolicyImpl) obj;
+ return name.equals(other.name) && ((nodeId == null) ? other.nodeId == null : nodeId.equals(other.nodeId));
+ }
+ return false;
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionPolicyImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionPolicyImpl.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistry.java?rev=738422&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistry.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistry.java Wed Jan 28 09:50:50 2009
@@ -0,0 +1,31 @@
+/*
+ * 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.retention;
+
+import org.apache.jackrabbit.spi.Path;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * <code>RetentionEvaluator</code>...
+ */
+public interface RetentionRegistry {
+
+ public boolean hasEffectiveHold(Path nodePath, boolean checkParent) throws RepositoryException;
+
+ public boolean hasEffectiveRetention(Path nodePath, boolean checkParent) throws RepositoryException;
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistry.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistry.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java?rev=738422&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java Wed Jan 28 09:50:50 2009
@@ -0,0 +1,349 @@
+/*
+ * 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.retention;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.api.jsr283.retention.Hold;
+import org.apache.jackrabbit.api.jsr283.retention.RetentionPolicy;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.PropertyImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+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.SynchronousEventListener;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.name.PathMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
+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.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * <code>RetentionEvaluatorImpl</code>...
+ */
+public class RetentionRegistryImpl implements RetentionRegistry, SynchronousEventListener {
+
+ /**
+ * logger instance
+ */
+ private static final Logger log = LoggerFactory.getLogger(RetentionRegistryImpl.class);
+ /**
+ * Name of the file storing the existing retention/holds
+ */
+ private static final String FILE_NAME = "retention";
+
+ private final PathMap retentionMap = new PathMap();
+ private final PathMap holdMap = new PathMap();
+
+ private final SessionImpl session;
+ private final FileSystemResource retentionFile;
+
+ private long holdCnt = 0;
+ private long retentionCnt = 0;
+
+ private boolean initialized = false;
+
+ public RetentionRegistryImpl(SessionImpl session, FileSystem fs) throws RepositoryException {
+ this.session = session;
+ this.retentionFile = new FileSystemResource(fs, FileSystem.SEPARATOR + FILE_NAME);
+
+ // start listening to added/changed or removed holds and retention policies.
+ Workspace wsp = session.getWorkspace();
+ // register eventlistener to be informed about new/removed holds and retention plcs.
+ int types = Event.PROPERTY_ADDED | Event.PROPERTY_REMOVED | Event.PROPERTY_CHANGED;
+ String[] ntFilter = new String[] {session.getJCRName(RetentionManagerImpl.REP_RETENTION_MANAGEABLE)};
+ wsp.getObservationManager().addEventListener(this, types, "/", true, null, ntFilter, false);
+
+ // populate the retentionMap and the holdMap with the effective
+ // holds and retention plcs present within the content.
+ try {
+ readRetentionFile();
+ } catch (FileSystemException e) {
+ throw new RepositoryException("Error while reading retention/holds from '" + retentionFile.getPath() + "'", e);
+ } catch (IOException e) {
+ throw new RepositoryException("Error while reading retention/holds from '" + retentionFile.getPath() + "'", e);
+ }
+ initialized = true;
+ }
+
+ /**
+ * Read the file system resource containing the node ids of those nodes
+ * contain holds/retention policies and populate the 2 path maps.
+ *
+ * If an entry in the retention file doesn't have a corresponding entry
+ * (either rep:hold property or rep:retentionPolicy property at the
+ * node identified by the node id entry) or doesn't correspond to an existing
+ * node, that entry will be ignored. Upon {@link #close()} of this
+ * manager, the file will be updated to reflect the actual set of holds/
+ * retentions present and effective in the content.
+ *
+ * @throws IOException
+ * @throws FileSystemException
+ */
+ private void readRetentionFile() throws IOException, FileSystemException {
+ if (retentionFile.exists()) {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(retentionFile.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ NodeId nodeId = NodeId.valueOf(line);
+ try {
+ NodeImpl node = (NodeImpl) session.getItemManager().getItem(nodeId);
+ Path nodePath = node.getPrimaryPath();
+
+ if (node.hasProperty(RetentionManagerImpl.REP_HOLD)) {
+ PropertyImpl prop = node.getProperty(RetentionManagerImpl.REP_HOLD);
+ addHolds(nodePath, prop);
+ }
+ if (node.hasProperty(RetentionManagerImpl.REP_RETENTION_POLICY)) {
+ PropertyImpl prop = node.getProperty(RetentionManagerImpl.REP_RETENTION_POLICY);
+ addRetentionPolicy(nodePath, prop);
+ }
+ } catch (RepositoryException e) {
+ // node doesn't exist any more or hold/retention has been removed.
+ // ignore. upon close() the file will not contain the given nodeId
+ // any more.
+ log.warn("Unable to read retention policy / holds from node '" + nodeId + "': " + e.getMessage());
+ }
+ }
+ } finally {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+ }
+
+ /**
+ * Write back the file system resource containing the node ids of those
+ * nodes containing holds and/or retention policies. Each node id is
+ * present only once.
+ */
+ private void writeRetentionFile() {
+ final Set nodeIds = new HashSet();
+
+ // first look for nodes containing holds
+ holdMap.traverse(new PathMap.ElementVisitor() {
+ public void elementVisited(PathMap.Element element) {
+ List holds = (List) element.get();
+ if (!holds.isEmpty()) {
+ nodeIds.add(((HoldImpl) holds.get(0)).getNodeId());
+ }
+ }
+ }, false);
+
+ // then collect ids of nodes having an retention policy
+ retentionMap.traverse(new PathMap.ElementVisitor() {
+ public void elementVisited(PathMap.Element element) {
+ RetentionPolicyImpl rp = (RetentionPolicyImpl) element.get();
+ nodeIds.add(rp.getNodeId());
+ }
+ }, false);
+
+ if (!nodeIds.isEmpty()) {
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new OutputStreamWriter(retentionFile.getOutputStream()));
+ for (Iterator it = nodeIds.iterator(); it.hasNext();) {
+ writer.write(it.next().toString());
+ if (it.hasNext()) {
+ writer.newLine();
+ }
+ }
+ } catch (FileSystemException fse) {
+ log.error("Error while saving locks to '" + retentionFile.getPath() + "': " + fse.getMessage());
+ } catch (IOException ioe) {
+ log.error("Error while saving locks to '" + retentionFile.getPath() + "': " + ioe.getMessage());
+ } finally {
+ IOUtils.closeQuietly(writer);
+ }
+ }
+ }
+
+ public void close() {
+ writeRetentionFile();
+ initialized = false;
+ }
+
+ private void addHolds(Path nodePath, PropertyImpl p) throws RepositoryException {
+ synchronized (holdMap) {
+ Hold[] holds = HoldImpl.createFromProperty(p, ((PropertyId) p.getId()).getParentId());
+ holdMap.put(nodePath, Arrays.asList(holds));
+ holdCnt++;
+ }
+ }
+
+ private void removeHolds(Path nodePath) {
+ synchronized (holdMap) {
+ PathMap.Element el = holdMap.map(nodePath, true);
+ if (el != null) {
+ el.remove();
+ holdCnt--;
+ } // else: no entry for holds on nodePath (should not occur)
+ }
+ }
+
+ private void addRetentionPolicy(Path nodePath, PropertyImpl p) throws RepositoryException {
+ synchronized (retentionMap) {
+ RetentionPolicy rp = new RetentionPolicyImpl(p.getString(), ((PropertyId) p.getId()).getParentId(), session);
+ retentionMap.put(nodePath, rp);
+ retentionCnt++;
+ }
+ }
+
+ private void removeRetentionPolicy(Path nodePath) {
+ synchronized (retentionMap) {
+ PathMap.Element el = retentionMap.map(nodePath, true);
+ if (el != null) {
+ el.remove();
+ retentionCnt--;
+ } // else: no entry for holds on nodePath (should not occur)
+ }
+ }
+
+ //--------------------------------------------------< RetentionRegistry >---
+ /**
+ * @see RetentionRegistry#hasEffectiveHold(org.apache.jackrabbit.spi.Path,boolean)
+ */
+ public boolean hasEffectiveHold(Path nodePath, boolean checkParent) throws RepositoryException {
+ if (!initialized) {
+ throw new IllegalStateException("Not initialized.");
+ }
+ if (holdCnt <= 0) {
+ return false;
+ }
+ PathMap.Element element = holdMap.map(nodePath, false);
+ List holds = (List) element.get();
+ if (holds != null) {
+ if (element.hasPath(nodePath)) {
+ // one or more holds on the specified path
+ return true;
+ } else if (checkParent && !nodePath.denotesRoot() &&
+ element.hasPath(nodePath.getAncestor(1))) {
+ // hold present on the parent node whithout checking for being
+ // a deep hold.
+ // this required for removal of a node that can be inhibited
+ // by a hold on the node itself, by a hold on the parent or
+ // by a deep hold on any ancestor.
+ return true;
+ } else {
+ for (Iterator it = holds.iterator(); it.hasNext();) {
+ Hold h = (Hold) it.next();
+ if (h.isDeep()) {
+ return true;
+ }
+ }
+ }
+ }
+ // no hold at path or no deep hold on parent.
+ return false;
+ }
+
+ /**
+ * @see RetentionRegistry#hasEffectiveRetention(org.apache.jackrabbit.spi.Path,boolean)
+ */
+ public boolean hasEffectiveRetention(Path nodePath, boolean checkParent) throws RepositoryException {
+ if (!initialized) {
+ throw new IllegalStateException("Not initialized.");
+ }
+ if (retentionCnt <= 0) {
+ return false;
+ }
+ RetentionPolicy rp = null;
+ PathMap.Element element = retentionMap.map(nodePath, true);
+ if (element != null) {
+ rp = (RetentionPolicy) element.get();
+ }
+ if (rp == null && checkParent ) {
+ element = retentionMap.map(nodePath.getAncestor(1), true);
+ if (element != null) {
+ rp = (RetentionPolicy) element.get();
+ }
+ }
+ return rp != null;
+ }
+
+ //-------------------------------------------< SynchronousEventListener >---
+ /**
+ * @param events Events reporting hold/retention policy changes.
+ */
+ public void onEvent(EventIterator events) {
+ while (events.hasNext()) {
+ Event ev = events.nextEvent();
+ try {
+ Path evPath = session.getQPath(ev.getPath());
+ Path nodePath = evPath.getAncestor(1);
+ Name propName = evPath.getNameElement().getName();
+
+ if (RetentionManagerImpl.REP_HOLD.equals(propName)) {
+ // hold changes
+ switch (ev.getType()) {
+ case Event.PROPERTY_ADDED:
+ case Event.PROPERTY_CHANGED:
+ // build the Hold objects from the rep:hold property
+ // and put them into the hold map.
+ PropertyImpl p = (PropertyImpl) session.getProperty(ev.getPath());
+ addHolds(nodePath, p);
+ break;
+ case Event.PROPERTY_REMOVED:
+ // all holds present on this node were remove
+ // -> remove the corresponding entry in the holdMap.
+ removeHolds(nodePath);
+ break;
+ }
+ } else if (RetentionManagerImpl.REP_RETENTION_POLICY.equals(propName)) {
+ // retention policy changes
+ switch (ev.getType()) {
+ case Event.PROPERTY_ADDED:
+ case Event.PROPERTY_CHANGED:
+ // build the RetentionPolicy objects from the rep:retentionPolicy property
+ // and put it into the retentionMap.
+ PropertyImpl p = (PropertyImpl) session.getProperty(ev.getPath());
+ addRetentionPolicy(nodePath, p);
+ break;
+ case Event.PROPERTY_REMOVED:
+ // retention policy present on this node was remove
+ // -> remove the corresponding entry in the retentionMap.
+ removeRetentionPolicy(nodePath);
+ break;
+ }
+ }
+ // else: not interested in any other property -> ignore.
+
+ } catch (RepositoryException e) {
+ log.warn("Internal error while processing event.",e.getMessage());
+ // ignore.
+ }
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java Wed Jan 28 09:50:50 2009
@@ -22,13 +22,14 @@
import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
import org.apache.jackrabbit.api.jsr283.security.AccessControlList;
import org.apache.jackrabbit.core.NodeImpl;
-import org.apache.jackrabbit.core.SecurityItemModifier;
+import org.apache.jackrabbit.core.ProtectedItemModifier;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
import org.apache.jackrabbit.core.security.authorization.AccessControlUtils;
import org.apache.jackrabbit.core.security.authorization.JackrabbitAccessControlEntry;
import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.authorization.Permission;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.commons.conversion.NameException;
import org.apache.jackrabbit.spi.commons.conversion.NameParser;
@@ -49,7 +50,7 @@
/**
* <code>ACLEditor</code>...
*/
-public class ACLEditor extends SecurityItemModifier implements AccessControlEditor, AccessControlConstants {
+public class ACLEditor extends ProtectedItemModifier implements AccessControlEditor, AccessControlConstants {
/**
* the default logger
@@ -67,7 +68,7 @@
private final AccessControlUtils utils;
ACLEditor(Session editingSession, AccessControlUtils utils) {
- super(true);
+ super(Permission.MODIFY_AC);
if (editingSession instanceof SessionImpl) {
session = ((SessionImpl) editingSession);
// TODO: review and find better solution
@@ -147,7 +148,7 @@
access and removed the explicitely
*/
if (aclNode != null) {
- removeSecurityItem(aclNode);
+ removeItem(aclNode);
}
// now (re) create it
aclNode = createAclNode(nodePath);
@@ -161,16 +162,16 @@
ValueFactory vf = session.getValueFactory();
// create the ACE node
- NodeImpl aceNode = addSecurityNode(aclNode, nodeName, ntName);
+ NodeImpl aceNode = addNode(aclNode, nodeName, ntName);
// write the rep:principalName property
String principalName = ace.getPrincipal().getName();
- setSecurityProperty(aceNode, P_PRINCIPAL_NAME, vf.createValue(principalName));
+ setProperty(aceNode, P_PRINCIPAL_NAME, vf.createValue(principalName));
// ... and the rep:privileges property
Privilege[] pvlgs = ace.getPrivileges();
Value[] names = getPrivilegeNames(pvlgs, vf);
- setSecurityProperty(aceNode, P_PRIVILEGES, names);
+ setProperty(aceNode, P_PRIVILEGES, names);
}
}
@@ -183,7 +184,7 @@
NodeImpl aclNode = getAclNode(nodePath);
if (aclNode != null) {
- removeSecurityItem(aclNode);
+ removeItem(aclNode);
} else {
throw new AccessControlException("No policy to remove at " + nodePath);
}
@@ -265,7 +266,7 @@
if (!protectedNode.isNodeType(NT_REP_ACCESS_CONTROLLABLE)) {
protectedNode.addMixin(NT_REP_ACCESS_CONTROLLABLE);
}
- return addSecurityNode(protectedNode, N_POLICY, NT_REP_ACL);
+ return addNode(protectedNode, N_POLICY, NT_REP_ACL);
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java Wed Jan 28 09:50:50 2009
@@ -23,11 +23,12 @@
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.jackrabbit.api.security.principal.NoSuchPrincipalException;
import org.apache.jackrabbit.core.NodeImpl;
-import org.apache.jackrabbit.core.SecurityItemModifier;
+import org.apache.jackrabbit.core.ProtectedItemModifier;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
import org.apache.jackrabbit.core.security.authorization.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.core.security.authorization.Permission;
import org.apache.jackrabbit.core.security.principal.ItemBasedPrincipal;
import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
import org.apache.jackrabbit.spi.Name;
@@ -49,7 +50,7 @@
/**
* <code>CombinedEditor</code>...
*/
-public class ACLEditor extends SecurityItemModifier implements AccessControlEditor, AccessControlConstants {
+public class ACLEditor extends ProtectedItemModifier implements AccessControlEditor, AccessControlConstants {
private static Logger log = LoggerFactory.getLogger(ACLEditor.class);
/**
@@ -64,7 +65,7 @@
private final String acRootPath;
ACLEditor(SessionImpl session, Path acRootPath) throws RepositoryException {
- super(true);
+ super(Permission.MODIFY_AC);
this.session = session;
this.acRootPath = session.getJCRPath(acRootPath);
}
@@ -162,10 +163,10 @@
NodeImpl aclNode;
if (acNode.hasNode(N_POLICY)) {
aclNode = acNode.getNode(N_POLICY);
- removeSecurityItem(aclNode);
+ removeItem(aclNode);
}
/* now (re) create it */
- aclNode = addSecurityNode(acNode, N_POLICY, NT_REP_ACL);
+ aclNode = addNode(acNode, N_POLICY, NT_REP_ACL);
/* add all entries defined on the template */
AccessControlEntry[] aces = acl.getAccessControlEntries();
@@ -175,25 +176,25 @@
// create the ACE node
Name nodeName = getUniqueNodeName(aclNode, "entry");
Name ntName = (ace.isAllow()) ? NT_REP_GRANT_ACE : NT_REP_DENY_ACE;
- NodeImpl aceNode = addSecurityNode(aclNode, nodeName, ntName);
+ NodeImpl aceNode = addNode(aclNode, nodeName, ntName);
ValueFactory vf = session.getValueFactory();
// write the rep:principalName property
- setSecurityProperty(aceNode, P_PRINCIPAL_NAME, vf.createValue(ace.getPrincipal().getName()));
+ setProperty(aceNode, P_PRINCIPAL_NAME, vf.createValue(ace.getPrincipal().getName()));
// ... and the rep:privileges property
Privilege[] privs = ace.getPrivileges();
Value[] vs = new Value[privs.length];
for (int j = 0; j < privs.length; j++) {
vs[j] = vf.createValue(privs[j].getName(), PropertyType.NAME);
}
- setSecurityProperty(aceNode, P_PRIVILEGES, vs);
+ setProperty(aceNode, P_PRIVILEGES, vs);
// store the restrictions:
String[] restrNames = ace.getRestrictionNames();
for (int rnIndex = 0; rnIndex < restrNames.length; rnIndex++) {
Name pName = session.getQName(restrNames[rnIndex]);
Value value = ace.getRestriction(restrNames[rnIndex]);
- setSecurityProperty(aceNode, pName, value);
+ setProperty(aceNode, pName, value);
}
}
}
@@ -210,7 +211,7 @@
// build the template in order to have a return value
AccessControlPolicy tmpl = createTemplate(acNode);
if (tmpl.equals(policy)) {
- removeSecurityItem(acNode.getNode(N_POLICY));
+ removeItem(acNode.getNode(N_POLICY));
return;
}
}
@@ -248,7 +249,7 @@
throw new RepositoryException("Internal error: Unexpected nodetype " + node.getPrimaryNodeType().getName() + " below /rep:accessControl");
}
} else {
- node = addSecurityNode(node, nName, NT_REP_ACCESS_CONTROL);
+ node = addNode(node, nName, NT_REP_ACCESS_CONTROL);
}
}
return node;
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java Wed Jan 28 09:50:50 2009
@@ -23,7 +23,7 @@
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.core.ItemImpl;
import org.apache.jackrabbit.core.NodeImpl;
-import org.apache.jackrabbit.core.SecurityItemModifier;
+import org.apache.jackrabbit.core.ProtectedItemModifier;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.security.principal.ItemBasedPrincipal;
import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
@@ -54,7 +54,7 @@
/**
* UserManagerImpl
*/
-public class UserManagerImpl extends SecurityItemModifier implements UserManager, UserConstants {
+public class UserManagerImpl extends ProtectedItemModifier implements UserManager, UserConstants {
private static final Logger log = LoggerFactory.getLogger(UserManagerImpl.class);
@@ -71,7 +71,7 @@
private final Map idPathMap = new LRUMap(1000);
public UserManagerImpl(SessionImpl session, String adminId) throws RepositoryException {
- super(false);
+ super();
this.session = session;
this.adminId = adminId;
@@ -216,11 +216,11 @@
parent = createParentNode(parentPath);
Name nodeName = session.getQName(Text.escapeIllegalJcrChars(userID));
- NodeImpl userNode = addSecurityNode(parent, nodeName, NT_REP_USER);
+ NodeImpl userNode = addNode(parent, nodeName, NT_REP_USER);
- setSecurityProperty(userNode, P_USERID, getValue(userID));
- setSecurityProperty(userNode, P_PASSWORD, getValue(UserImpl.buildPasswordValue(password)));
- setSecurityProperty(userNode, P_PRINCIPAL_NAME, getValue(principal.getName()));
+ setProperty(userNode, P_USERID, getValue(userID), true);
+ setProperty(userNode, P_PASSWORD, getValue(UserImpl.buildPasswordValue(password)), true);
+ setProperty(userNode, P_PRINCIPAL_NAME, getValue(principal.getName()), true);
parent.save();
log.debug("User created: " + userID + "; " + userNode.getPath());
@@ -271,8 +271,8 @@
parent = createParentNode(parentPath);
Name groupID = getGroupId(principal.getName());
- NodeImpl groupNode = addSecurityNode(parent, groupID, NT_REP_GROUP);
- setSecurityProperty(groupNode, P_PRINCIPAL_NAME, getValue(principal.getName()));
+ NodeImpl groupNode = addNode(parent, groupID, NT_REP_GROUP);
+ setProperty(groupNode, P_PRINCIPAL_NAME, getValue(principal.getName()));
parent.save();
log.debug("Group created: " + groupID + "; " + groupNode.getPath());
@@ -303,17 +303,17 @@
}
void setProtectedProperty(NodeImpl node, Name propName, Value value) throws RepositoryException, LockException, ConstraintViolationException, ItemExistsException, VersionException {
- setSecurityProperty(node, propName, value);
+ setProperty(node, propName, value);
node.save();
}
void setProtectedProperty(NodeImpl node, Name propName, Value[] values) throws RepositoryException, LockException, ConstraintViolationException, ItemExistsException, VersionException {
- setSecurityProperty(node, propName, values);
+ setProperty(node, propName, values);
node.save();
}
void removeProtectedItem(ItemImpl item, Node parent) throws RepositoryException, AccessDeniedException, VersionException {
- removeSecurityItem(item);
+ removeItem(item);
parent.save();
}
@@ -491,7 +491,7 @@
} else {
ntName = NT_REP_AUTHORIZABLE_FOLDER;
}
- NodeImpl added = addSecurityNode(parent, nName, ntName);
+ NodeImpl added = addNode(parent, nName, ntName);
parent.save();
parent = added;
} else {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java Wed Jan 28 09:50:50 2009
@@ -146,7 +146,7 @@
// create new with new uuid:
// check if new node can be added (check access rights &
// node type constraints only, assume locking & versioning status
- // has already been checked on ancestor)
+ // and retention/hold has already been checked on ancestor)
itemOps.checkAddNode(parent, nodeInfo.getName(),
nodeInfo.getNodeTypeName(),
BatchedItemOperations.CHECK_ACCESS
@@ -192,14 +192,16 @@
BatchedItemOperations.CHECK_ACCESS
| BatchedItemOperations.CHECK_LOCK
| BatchedItemOperations.CHECK_VERSIONING
- | BatchedItemOperations.CHECK_CONSTRAINTS);
+ | BatchedItemOperations.CHECK_CONSTRAINTS
+ | BatchedItemOperations.CHECK_HOLD
+ | BatchedItemOperations.CHECK_RETENTION);
// do remove conflicting (recursive)
itemOps.removeNodeState(conflicting);
// create new with given uuid:
// check if new node can be added (check access rights &
// node type constraints only, assume locking & versioning status
- // has already been checked on ancestor)
+ // and retention/hold has already been checked on ancestor)
itemOps.checkAddNode(parent, nodeInfo.getName(),
nodeInfo.getNodeTypeName(),
BatchedItemOperations.CHECK_ACCESS
@@ -231,7 +233,9 @@
BatchedItemOperations.CHECK_ACCESS
| BatchedItemOperations.CHECK_LOCK
| BatchedItemOperations.CHECK_VERSIONING
- | BatchedItemOperations.CHECK_CONSTRAINTS);
+ | BatchedItemOperations.CHECK_CONSTRAINTS
+ | BatchedItemOperations.CHECK_HOLD
+ | BatchedItemOperations.CHECK_RETENTION);
// 'replace' is actually a 'remove existing/add new' operation;
// this unfortunately changes the order of the parent's
@@ -244,13 +248,16 @@
itemOps.removeNodeState(conflicting);
// create new with given uuid at same location as conflicting:
// check if new node can be added at other location
- // (access rights, node type constraints, locking & versioning status)
+ // (access rights, node type constraints, locking & versioning
+ // status and retention/hold)
itemOps.checkAddNode(parent, nodeInfo.getName(),
nodeInfo.getNodeTypeName(),
BatchedItemOperations.CHECK_ACCESS
| BatchedItemOperations.CHECK_LOCK
| BatchedItemOperations.CHECK_VERSIONING
- | BatchedItemOperations.CHECK_CONSTRAINTS);
+ | BatchedItemOperations.CHECK_CONSTRAINTS
+ | BatchedItemOperations.CHECK_HOLD
+ | BatchedItemOperations.CHECK_RETENTION);
// do create new node
node = itemOps.createNodeState(parent, nodeInfo.getName(),
nodeInfo.getNodeTypeName(), nodeInfo.getMixinNames(),
@@ -463,7 +470,7 @@
// check if new node can be added (check access rights &
// node type constraints only, assume locking & versioning status
- // has already been checked on ancestor)
+ // and retention/hold has already been checked on ancestor)
itemOps.checkAddNode(parent, nodeName, ntName,
BatchedItemOperations.CHECK_ACCESS
| BatchedItemOperations.CHECK_CONSTRAINTS);
@@ -496,7 +503,7 @@
// check if new node can be added (check access rights &
// node type constraints only, assume locking & versioning status
- // has already been checked on ancestor)
+ // and retention/hold has already been checked on ancestor)
itemOps.checkAddNode(parent, nodeName, ntName,
BatchedItemOperations.CHECK_ACCESS
| BatchedItemOperations.CHECK_CONSTRAINTS);
Modified: jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd Wed Jan 28 09:50:50 2009
@@ -221,4 +221,13 @@
[rep:AuthorizableFolder] > nt:base, mix:referenceable
+ * (rep:Authorizable) = rep:User protected version
- + * (rep:AuthorizableFolder) = rep:AuthorizableFolder protected version
\ No newline at end of file
+ + * (rep:AuthorizableFolder) = rep:AuthorizableFolder protected version
+
+// -----------------------------------------------------------------------------
+// J A C K R A B B I T R E T E N T I O N M A N A G E M E N T
+// -----------------------------------------------------------------------------
+
+[rep:RetentionManageable]
+ mixin
+ - rep:hold (undefined) protected multiple ignore
+ - rep:retentionPolicy (undefined) protected ignore
\ No newline at end of file
Modified: jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml Wed Jan 28 09:50:50 2009
@@ -520,4 +520,11 @@
</requiredPrimaryTypes>
</childNodeDefinition>
</nodeType>
+
+ <!-- retention management -->
+ <nodeType name="rep:RetentionManageable" isMixin="true" hasOrderableChildNodes="false" primaryItemName="">
+ <propertyDefinition name="rep:hold" requiredType="undefined" autoCreated="false" mandatory="false" onParentVersion="IGNORE" protected="true" multiple="true" />
+ <propertyDefinition name="rep:retentionPolicy" requiredType="undefined" autoCreated="false" mandatory="false" onParentVersion="IGNORE" protected="true" multiple="false" />
+ </nodeType>
+
</nodeTypes>
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/SessionRemoveItemTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/SessionRemoveItemTest.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/SessionRemoveItemTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/SessionRemoveItemTest.java Wed Jan 28 09:50:50 2009
@@ -20,11 +20,13 @@
import org.slf4j.LoggerFactory;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.apache.jackrabbit.test.NotExecutableException;
+import org.apache.jackrabbit.test.RepositoryStub;
import javax.jcr.InvalidItemStateException;
import javax.jcr.AccessDeniedException;
import javax.jcr.RepositoryException;
import javax.jcr.Property;
+import javax.jcr.Value;
import javax.jcr.version.VersionException;
import javax.jcr.lock.LockException;
@@ -129,7 +131,8 @@
public void testRemoveLockedChildItem() throws RepositoryException, NotExecutableException {
// add a child property and a child node to test deep lock effect.
javax.jcr.Node childN = removeNode.addNode(nodeName2);
- Property childP = removeNode.setProperty(propertyName2, "propvalue2");
+ Value v = getJcrValue(superuser, RepositoryStub.PROP_PROP_VALUE2, RepositoryStub.PROP_PROP_TYPE2, "propvalue2");
+ Property childP = removeNode.setProperty(propertyName2, v);
removeNode.save();
if (!removeNode.isNodeType(mixLockable)) {
@@ -172,7 +175,8 @@
public void testRemoveCheckedInItem() throws RepositoryException, NotExecutableException {
// add a child property and a child node to test deep lock effect.
javax.jcr.Node childN = removeNode.addNode(nodeName2);
- Property childP = removeNode.setProperty(propertyName2, "propvalue2");
+ Value v = getJcrValue(superuser, RepositoryStub.PROP_PROP_VALUE2, RepositoryStub.PROP_PROP_TYPE2, "propvalue2");
+ Property childP = removeNode.setProperty(propertyName2, v);
removeNode.save();
if (!removeNode.isNodeType(mixVersionable)) {
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/AbstractRetentionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/AbstractRetentionTest.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/AbstractRetentionTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/AbstractRetentionTest.java Wed Jan 28 09:50:50 2009
@@ -16,9 +16,11 @@
*/
package org.apache.jackrabbit.api.jsr283.retention;
-import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.apache.jackrabbit.test.NotExecutableException;
+import org.apache.jackrabbit.test.RepositoryStub;
+import org.apache.jackrabbit.core.retention.RetentionPolicyImpl;
+import org.apache.jackrabbit.core.SessionImpl;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@@ -30,22 +32,38 @@
public abstract class AbstractRetentionTest extends AbstractJCRTest {
protected RetentionManager retentionMgr;
+ protected String testNodePath;
protected void setUp() throws Exception {
super.setUp();
+ // TODO: uncomment again.
+ // checkSupportedOption(Repository.OPTION_RETENTION_SUPPORTED);
+
retentionMgr = getRetentionManager(superuser);
+ testNodePath = testRootNode.getPath();
}
- protected static RetentionManager getRetentionManager(Session s) throws RepositoryException, NotExecutableException {
- // TODO: fix (Replace by Session) test as soon as jackrabbit implements 283
- if (!(s instanceof SessionImpl)) {
+ protected String getHoldName() throws RepositoryException, NotExecutableException {
+ String holdName = getProperty(RepositoryStub.PROP_HOLD_NAME);
+ if (holdName == null) {
throw new NotExecutableException();
}
- // TODO: uncomment again.
- // checkSupportedOption(Repository.OPTION_RETENTION_SUPPORTED);
+ return holdName;
+ }
+
+ protected RetentionPolicy getApplicableRetentionPolicy() throws NotExecutableException, RepositoryException {
+ return getApplicableRetentionPolicy("retentionPolicyName");
+ }
+
+ protected RetentionPolicy getApplicableRetentionPolicy(String jcrName) throws NotExecutableException, RepositoryException {
+ // TODO: move to repositoryStub/helper and adjust accordingly
+ return new RetentionPolicyImpl(jcrName, (SessionImpl)superuser);
+ }
+
+ protected static RetentionManager getRetentionManager(Session s) throws RepositoryException, NotExecutableException {
try {
- return ((SessionImpl) s).getRetentionManager();
+ return getJsr283Session(s).getRetentionManager();
} catch (UnsupportedRepositoryOperationException e) {
throw new NotExecutableException();
}
@@ -56,4 +74,13 @@
throw new NotExecutableException();
}
}
+
+ protected static org.apache.jackrabbit.api.jsr283.Session getJsr283Session(Session s) throws NotExecutableException {
+ // TODO: get rid of method once jsr 283 is released
+ if (s instanceof org.apache.jackrabbit.api.jsr283.Session) {
+ return (org.apache.jackrabbit.api.jsr283.Session) s;
+ } else {
+ throw new NotExecutableException();
+ }
+ }
}
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldEffectTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldEffectTest.java?rev=738422&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldEffectTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldEffectTest.java Wed Jan 28 09:50:50 2009
@@ -0,0 +1,225 @@
+/*
+ * 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.api.jsr283.retention;
+
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.apache.jackrabbit.test.RepositoryStub;
+
+import javax.jcr.Session;
+import javax.jcr.RepositoryException;
+import javax.jcr.Property;
+import javax.jcr.Node;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+
+/**
+ * <code>HoldEffectTest</code>...
+ */
+public class HoldEffectTest extends AbstractRetentionTest {
+
+ private Node childN;
+ private Property childP;
+ private Session otherS;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ childN = testRootNode.addNode(nodeName2);
+ Value v = getJcrValue(superuser, RepositoryStub.PROP_PROP_VALUE1, RepositoryStub.PROP_PROP_TYPE1, "test");
+ childP = testRootNode.setProperty(propertyName1, v);
+ superuser.save();
+
+ otherS = helper.getSuperuserSession();
+ }
+
+ protected void tearDown() throws Exception {
+ if (otherS != null) {
+ otherS.logout();
+ }
+ Hold[] holds = retentionMgr.getHolds(testNodePath);
+ for (int i = 0; i < holds.length; i++) {
+ retentionMgr.removeHold(testNodePath, holds[i]);
+ }
+ superuser.save();
+
+ super.tearDown();
+ }
+
+ // TODO: test importXML (session/wsp) / move (session/wsp) / copy ...
+ // TODO: test effect on child items
+
+ public void testTransientShallowHold() throws RepositoryException, NotExecutableException {
+ retentionMgr.addHold(testNodePath, getHoldName(), false);
+
+ assertNoEffect(testRootNode, nodeName3, propertyName2);
+ assertNoEffect(childN, nodeName3, propertyName2);
+ assertNoEffect(childP);
+ }
+
+ public void testTransientShallowHoldForOtherSession() throws RepositoryException, NotExecutableException {
+ retentionMgr.addHold(testNodePath, getHoldName(), false);
+
+ assertNoEffect((Node) otherS.getItem(testNodePath), nodeName3, propertyName2);
+ assertNoEffect((Node) otherS.getItem(childN.getPath()), nodeName3, propertyName2);
+ assertNoEffect((Property) otherS.getItem(childP.getPath()));
+ }
+
+ public void testTransientDeepHold() throws RepositoryException, NotExecutableException {
+ retentionMgr.addHold(testNodePath, getHoldName(), true);
+
+ assertNoEffect(testRootNode, nodeName3, propertyName2);
+ assertNoEffect(childN, nodeName3, propertyName2);
+ assertNoEffect(childP);
+ }
+
+ public void testTransientDeepHoldForOtherSession() throws RepositoryException, NotExecutableException {
+ retentionMgr.addHold(testNodePath, getHoldName(), true);
+
+ assertNoEffect((Node) otherS.getItem(testNodePath), nodeName3, propertyName2);
+ assertNoEffect((Node) otherS.getItem(childN.getPath()), nodeName3, propertyName2);
+ assertNoEffect((Property) otherS.getItem(childP.getPath()));
+ }
+
+ public void testShallowHold() throws RepositoryException, NotExecutableException {
+ retentionMgr.addHold(testNodePath, getHoldName(), false);
+ superuser.save();
+
+ // check for superuser
+ assertNoEffect(childN, nodeName3, propertyName2);
+ assertEffect(testRootNode, childN.getName(), childP.getName(), nodeName3, propertyName2);
+ }
+
+ public void testShallowHoldForOtherSession() throws RepositoryException, NotExecutableException {
+ retentionMgr.addHold(testNodePath, getHoldName(), false);
+ superuser.save();
+
+ // check for other session
+ assertNoEffect((Node) otherS.getItem(childN.getPath()), nodeName3, propertyName2);
+ assertEffect((Node) otherS.getItem(testNodePath), childN.getName(), childP.getName(), nodeName3, propertyName2);
+ }
+
+ public void testDeepHold() throws RepositoryException, NotExecutableException {
+ Node n = childN.addNode(nodeName2);
+ Value v = getJcrValue(superuser, RepositoryStub.PROP_PROP_VALUE1, RepositoryStub.PROP_PROP_TYPE1, "test");
+ Property p = childN.setProperty(propertyName1, v);
+ retentionMgr.addHold(testNodePath, getHoldName(), true);
+ superuser.save();
+
+ // check for superuser
+ assertEffect(testRootNode, childN.getName(), childP.getName(), nodeName3, propertyName2);
+ assertEffect(childN, n.getName(), p.getName(), nodeName3, propertyName2);
+ }
+
+ public void testDeepHoldForOtherSession() throws RepositoryException, NotExecutableException {
+ Node n = childN.addNode(nodeName2);
+ Value v = getJcrValue(superuser, RepositoryStub.PROP_PROP_VALUE1, RepositoryStub.PROP_PROP_TYPE1, "test");
+ Property p = childN.setProperty(propertyName1, v);
+ retentionMgr.addHold(testNodePath, getHoldName(), true);
+ superuser.save();
+
+ // check for other session
+ assertEffect((Node) otherS.getItem(testNodePath), childN.getName(), childP.getName(), nodeName3, propertyName2);
+ assertEffect((Node) otherS.getItem(childN.getPath()), n.getName(), p.getName(), nodeName3, propertyName2);
+ }
+
+ private void assertEffect(Node targetNode, String childName,
+ String propName, String childName2,
+ String propName2) throws RepositoryException {
+ Session s = targetNode.getSession();
+ try {
+ Node child = targetNode.getNode(childName);
+ child.remove();
+ s.save();
+ fail("Hold present must prevent a child node from being removed.");
+ } catch (RepositoryException e) {
+ // success
+ s.refresh(false);
+ }
+ try {
+ Property p = targetNode.getProperty(propName);
+ p.remove();
+ s.save();
+ fail("Hold present must prevent a child property from being removed.");
+ } catch (RepositoryException e) {
+ // success
+ s.refresh(false);
+ }
+ try {
+ Property p = targetNode.getProperty(propName);
+ p.setValue("test2");
+ s.save();
+ fail("Hold present must prevent the child property from being modified.");
+ } catch (RepositoryException e) {
+ // success
+ s.refresh(false);
+ }
+ try {
+ targetNode.addNode(childName2);
+ s.save();
+ fail("Hold present must prevent the target node from having new nodes added.");
+ } catch (RepositoryException e) {
+ // success
+ s.refresh(false);
+ }
+ try {
+ Value v = getJcrValue(s, RepositoryStub.PROP_PROP_VALUE2, RepositoryStub.PROP_PROP_TYPE2, "test");
+ targetNode.setProperty(propName2, v);
+ s.save();
+ fail("Hold present must prevent the target node from having new properties set.");
+ } catch (RepositoryException e) {
+ // success
+ s.refresh(false);
+ }
+
+ NodeType[] mixins = targetNode.getMixinNodeTypes();
+ if (mixins.length > 0) {
+ try {
+ targetNode.removeMixin(mixins[0].getName());
+ s.save();
+ fail("Hold present must prevent the target node from having it's mixin types changed.");
+ } catch (RepositoryException e) {
+ // success
+ s.refresh(false);
+ }
+ }
+ try {
+ targetNode.remove();
+ s.save();
+ fail("Hold present must prevent the target node from being removed.");
+ } catch (RepositoryException e) {
+ // success
+ s.refresh(false);
+ }
+ }
+
+ private void assertNoEffect(Node target, String childName, String propName) throws RepositoryException {
+ Session s = target.getSession();
+
+ Node n = target.addNode(childName);
+ Value v = getJcrValue(s, RepositoryStub.PROP_PROP_VALUE2, RepositoryStub.PROP_PROP_TYPE2, "test");
+ Property p = target.setProperty(propName, v);
+
+ n.remove();
+ p.remove();
+ }
+
+ private void assertNoEffect(Property target) throws RepositoryException {
+ Session s = target.getSession();
+ target.setValue("test3");
+ target.remove();
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldEffectTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldEffectTest.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldTest.java?rev=738422&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldTest.java Wed Jan 28 09:50:50 2009
@@ -0,0 +1,425 @@
+/*
+ * 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.api.jsr283.retention;
+
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+import javax.jcr.version.VersionException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * <code>RetentionManagerTest</code>...
+ */
+public class HoldTest extends AbstractRetentionTest {
+
+ private static boolean containsHold(Hold[] holds, Hold toTest) throws RepositoryException {
+ for (int i = 0; i < holds.length; i++) {
+ if (holds[i].getName().equals(toTest.getName()) && holds[i].isDeep() == toTest.isDeep()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void testAddHold() throws RepositoryException, NotExecutableException {
+ Hold hold = retentionMgr.addHold(testNodePath, getHoldName(), false);
+ Hold[] holds = retentionMgr.getHolds(testNodePath);
+ assertTrue("getHolds must return the hold added before.", holds.length >= 1);
+ assertTrue("getHolds doesn't return the hold added before", containsHold(holds, hold));
+ }
+
+ public void testAddHold2() throws RepositoryException, NotExecutableException {
+ Hold[] holdsBefore = retentionMgr.getHolds(testNodePath);
+ Hold hold = retentionMgr.addHold(testNodePath, getHoldName(), false);
+ assertFalse("The hold added must not have been present before.", containsHold(holdsBefore, hold));
+ }
+
+ public void testAddHoldIsTransient() throws RepositoryException, NotExecutableException {
+ Hold hold = retentionMgr.addHold(testNodePath, getHoldName(), false);
+ Hold[] holds = retentionMgr.getHolds(testNodePath);
+
+ // revert the changes made
+ superuser.refresh(false);
+ Hold[] holds2 = retentionMgr.getHolds(testNodePath);
+
+ assertEquals("Reverting transient changes must revert the hold added.",
+ holds.length -1, holds2.length);
+ assertFalse("Reverting transient changes must revert the hold added.",
+ containsHold(holds2, hold));
+ }
+
+ public void testRemoveHold() throws RepositoryException, NotExecutableException {
+ Hold hold = retentionMgr.addHold(testNodePath, getHoldName(), false);
+
+ Hold[] holds = retentionMgr.getHolds(testNodePath);
+
+ retentionMgr.removeHold(testNodePath, hold);
+ Hold[] holds2 = retentionMgr.getHolds(testNodePath);
+
+ assertEquals("RetentionManager.removeHold should removed the hold added before.",
+ holds.length -1, holds2.length);
+ assertFalse("RetentionManager.removeHold should removed the hold added before.",
+ containsHold(holds2, hold));
+ }
+
+ public void testRemoveHoldIsTransient() throws RepositoryException, NotExecutableException {
+ Hold hold = retentionMgr.addHold(testNodePath, getHoldName(), false);
+ superuser.save();
+ try {
+ Hold[] holds = retentionMgr.getHolds(testNodePath);
+
+ retentionMgr.removeHold(testNodePath, hold);
+ superuser.refresh(false);
+
+ Hold[] holds2 = retentionMgr.getHolds(testNodePath);
+ assertEquals("Reverting transient hold removal must restore the original state.",
+ Arrays.asList(holds), Arrays.asList(holds2));
+ } finally {
+ // clear the hold that was permanently added before.
+ retentionMgr.removeHold(testNodePath, hold);
+ superuser.save();
+ }
+ }
+
+ public void testRemoveHoldFromChild() throws RepositoryException, NotExecutableException {
+ String childPath = testRootNode.addNode(nodeName2, testNodeType).getPath();
+ Hold hold = retentionMgr.addHold(testNodePath, getHoldName(), false);
+
+ try {
+ retentionMgr.removeHold(childPath, hold);
+ fail("Removing hold from another node must fail");
+ } catch (RepositoryException e) {
+ // success
+ assertTrue(containsHold(retentionMgr.getHolds(testNodePath), hold));
+ }
+
+ // check again with persisted hold
+ superuser.save();
+ try {
+ retentionMgr.removeHold(childPath, hold);
+ fail("Removing hold from another node must fail");
+ } catch (RepositoryException e) {
+ // success
+ assertTrue(containsHold(retentionMgr.getHolds(testNodePath), hold));
+ } finally {
+ // clear the hold that was permanently added before.
+ retentionMgr.removeHold(testNodePath, hold);
+ superuser.save();
+ }
+ }
+
+ public void testInvalidPath() throws RepositoryException, NotExecutableException {
+ String invalidPath = testPath; // not an absolute path.
+ try {
+ retentionMgr.getHolds(invalidPath);
+ fail("Accessing holds an invalid path must throw RepositoryException.");
+ } catch (RepositoryException e) {
+ // success
+ }
+ try {
+ retentionMgr.addHold(invalidPath, getHoldName(), true);
+ fail("Adding a hold at an invalid path must throw RepositoryException.");
+ } catch (RepositoryException e) {
+ // success
+ }
+ try {
+ Hold h = retentionMgr.addHold(testNodePath, getHoldName(), true);
+ retentionMgr.removeHold(invalidPath, h);
+ fail("Removing a hold at an invalid path must throw RepositoryException.");
+ } catch (RepositoryException e) {
+ // success
+ }
+ }
+
+ public void testNonExistingNodePath() throws RepositoryException, NotExecutableException {
+ String invalidPath = testNodePath + "/nonexisting";
+ int cnt = 0;
+ while (getJsr283Session(superuser).nodeExists(invalidPath)) {
+ invalidPath += cnt++;
+ }
+
+ try {
+ retentionMgr.getHolds(invalidPath);
+ fail("Accessing holds from non-existing node must throw PathNotFoundException.");
+ } catch (PathNotFoundException e) {
+ // success
+ }
+ try {
+ retentionMgr.addHold(invalidPath, getHoldName(), true);
+ fail("Adding a hold for a non-existing node must throw PathNotFoundException.");
+ } catch (PathNotFoundException e) {
+ // success
+ }
+ try {
+ Hold h = retentionMgr.addHold(testNodePath, getHoldName(), true);
+ retentionMgr.removeHold(invalidPath, h);
+ fail("Removing a hold at a non-existing node must throw PathNotFoundException.");
+ } catch (PathNotFoundException e) {
+ // success
+ }
+ }
+
+ public void testPropertyPath() throws RepositoryException, NotExecutableException {
+ String propPath = null;
+ for (PropertyIterator it = testRootNode.getProperties(); it.hasNext();) {
+ String path = it.nextProperty().getPath();
+ if (!getJsr283Session(superuser).nodeExists(path)) {
+ propPath = path;
+ break;
+ }
+ }
+ if (propPath == null) {
+ throw new NotExecutableException();
+ }
+ try {
+ retentionMgr.getHolds(propPath);
+ fail("Accessing holds from non-existing node must throw PathNotFoundException.");
+ } catch (PathNotFoundException e) {
+ // success
+ }
+ try {
+ retentionMgr.addHold(propPath, getHoldName(), true);
+ fail("Adding a hold for a non-existing node must throw PathNotFoundException.");
+ } catch (PathNotFoundException e) {
+ // success
+ }
+ try {
+ Hold h = retentionMgr.addHold(testNodePath, getHoldName(), true);
+ retentionMgr.removeHold(propPath, h);
+ fail("Removing a hold at a non-existing node must throw PathNotFoundException.");
+ } catch (PathNotFoundException e) {
+ // success
+ }
+ }
+
+ public void testInvalidName() {
+ try {
+ String invalidName = "*.[y]";
+ retentionMgr.addHold(testNodePath, invalidName, false);
+ fail("Adding a hold with an invalid JCR name must fail.");
+ } catch (RepositoryException e) {
+ // success
+ }
+ }
+
+ public void testReadOnlySession() throws NotExecutableException, RepositoryException {
+ javax.jcr.Session s = helper.getReadOnlySession();
+ try {
+ RetentionManager rmgr = getRetentionManager(s);
+ try {
+ rmgr.getHolds(testNodePath);
+ fail("Read-only session doesn't have sufficient privileges to retrieve holds.");
+ } catch (AccessDeniedException e) {
+ // success
+ }
+ try {
+ rmgr.addHold(testNodePath, getHoldName(), false);
+ fail("Read-only session doesn't have sufficient privileges to retrieve holds.");
+ } catch (AccessDeniedException e) {
+ // success
+ }
+ } finally {
+ s.logout();
+ }
+ }
+
+ public void testAddHoldOnLockedNode() throws NotExecutableException, RepositoryException {
+ Node child = getLockedChildNode();
+ // remember current holds for clean up.
+ List holdsBefore = Arrays.asList(retentionMgr.getHolds(child.getPath()));
+
+ // get another session.
+ javax.jcr.Session otherS = helper.getSuperuserSession();
+ try {
+ RetentionManager rmgr = getRetentionManager(otherS);
+ rmgr.addHold(child.getPath(), getHoldName(), false);
+ otherS.save();
+
+ fail("Adding hold on a locked node must throw LockException.");
+ } catch (LockException e) {
+ // success
+ } finally {
+ otherS.logout();
+
+ // clear holds (in case of test failure)
+ List holds = new ArrayList(Arrays.asList(retentionMgr.getHolds(child.getPath())));
+ if (holds.removeAll(holdsBefore)) {
+ for (Iterator it = holds.iterator(); it.hasNext();) {
+ retentionMgr.removeHold(child.getPath(), (Hold) it.next());
+ }
+ }
+ superuser.save();
+ }
+ }
+
+ public void testRemoveHoldOnLockedNode() throws NotExecutableException, RepositoryException {
+ Node child = getLockedChildNode();
+ Hold h = retentionMgr.addHold(child.getPath(), getHoldName(), false);
+ testRootNode.save();
+
+ javax.jcr.Session otherS = helper.getSuperuserSession();
+ try {
+ RetentionManager rmgr = getRetentionManager(otherS);
+ Hold[] holds = rmgr.getHolds(child.getPath());
+
+ if (holds.length > 0) {
+ rmgr.removeHold(child.getPath(), holds[0]);
+ otherS.save();
+ fail("Removing a hold on a locked node must throw LockException.");
+ }
+ } catch (LockException e) {
+ // success
+ } finally {
+ otherS.logout();
+
+ // clear hold added before
+ try {
+ retentionMgr.removeHold(child.getPath(), h);
+ superuser.save();
+ } catch (RepositoryException e) {
+ // should not get here if test is correctly executed.
+ }
+ }
+ }
+
+ private Node getLockedChildNode() throws NotExecutableException, RepositoryException {
+ checkSupportedOption(superuser, Repository.OPTION_LOCKING_SUPPORTED);
+ Node child = testRootNode.addNode(nodeName2, testNodeType);
+ if (!child.isNodeType(mixLockable)) {
+ if (child.canAddMixin(mixLockable)) {
+ child.addMixin(mixLockable);
+ } else {
+ throw new NotExecutableException();
+ }
+ }
+ testRootNode.save();
+ child.lock(false, true); // session-scoped lock clean upon superuser-logout.
+ return child;
+ }
+
+ public void testAddHoldOnCheckedInNode() throws NotExecutableException, RepositoryException {
+ Node child = getVersionableChildNode();
+ child.checkout();
+ child.checkin();
+
+ // get another session.
+ javax.jcr.Session otherS = helper.getSuperuserSession();
+ try {
+ RetentionManager rmgr = getRetentionManager(otherS);
+ rmgr.addHold(child.getPath(), getHoldName(), false);
+ otherS.save();
+
+ fail("Adding hold on a checked-in node must throw VersionException.");
+ } catch (VersionException e) {
+ // success
+ } finally {
+ otherS.logout();
+
+ // clear holds (in case of test failure)
+ child.checkout();
+ Hold[] holds = retentionMgr.getHolds(child.getPath());
+ for (int i = 0; i < holds.length; i++) {
+ retentionMgr.removeHold(child.getPath(), holds[i]);
+ }
+ superuser.save();
+ }
+ }
+
+ public void testRemoveHoldOnCheckedInNode() throws NotExecutableException, RepositoryException {
+ Node vn = getVersionableChildNode();
+ vn.checkout();
+ Node n = vn.addNode(nodeName2);
+ Hold h = retentionMgr.addHold(n.getPath(), getHoldName(), false);
+ superuser.save();
+
+ // checkin on the parent node make the hold-containing node checked-in.
+ vn.checkin();
+
+ javax.jcr.Session otherS = helper.getSuperuserSession();
+ try {
+ RetentionManager rmgr = getRetentionManager(otherS);
+ Hold[] holds = rmgr.getHolds(n.getPath());
+
+ if (holds.length > 0) {
+ rmgr.removeHold(n.getPath(), holds[0]);
+ otherS.save();
+ fail("Removing a hold on a checked-in node must throw VersionException.");
+ }
+ } catch (VersionException e) {
+ // success
+ } finally {
+ otherS.logout();
+
+ // clear hold added before
+ vn.checkout();
+ try {
+ retentionMgr.removeHold(n.getPath(), h);
+ superuser.save();
+ } catch (RepositoryException e) {
+ // should not get here if test is correctly executed.
+ }
+ }
+ }
+
+ private Node getVersionableChildNode() throws NotExecutableException, RepositoryException {
+ checkSupportedOption(superuser, Repository.OPTION_VERSIONING_SUPPORTED);
+ Node child = testRootNode.addNode(nodeName2, testNodeType);
+ if (!child.isNodeType(mixVersionable)) {
+ if (child.canAddMixin(mixVersionable)) {
+ child.addMixin(mixVersionable);
+ } else {
+ throw new NotExecutableException();
+ }
+ }
+ testRootNode.save();
+ return child;
+ }
+
+ public void testHoldGetName() throws RepositoryException, NotExecutableException {
+ String holdName = getHoldName();
+ Hold h = retentionMgr.addHold(testNodePath, getHoldName(), false);
+ assertEquals("Hold.getName() must return the specified name.",holdName, h.getName());
+ }
+
+ public void testHoldGetName2() throws RepositoryException, NotExecutableException {
+ String holdName = getHoldName();
+ Hold h = retentionMgr.addHold(testNodePath, getHoldName(), true);
+ assertEquals("Hold.getName() must return the specified name.",holdName, h.getName());
+ }
+
+ public void testHoldIsDeep() throws RepositoryException, NotExecutableException {
+ String holdName = getHoldName();
+ Hold h = retentionMgr.addHold(testNodePath, getHoldName(), false);
+ assertEquals("Hold.isDeep() must reflect the specified flag.", false, h.isDeep());
+ }
+
+ public void testHoldIsDeep2() throws RepositoryException, NotExecutableException {
+ String holdName = getHoldName();
+ Hold h = retentionMgr.addHold(testNodePath, getHoldName(), true);
+ assertEquals("Hold.isDeep() must reflect the specified flag.", true, h.isDeep());
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldTest.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url