[exo-jcr-commits] exo-jcr SVN: r4832 - in jcr/trunk: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent and 14 other directories.
do-not-reply at jboss.org
do-not-reply at jboss.org
Fri Sep 2 06:32:09 EDT 2011
Author: sergiykarpenko
Date: 2011-09-02 06:32:08 -0400 (Fri, 02 Sep 2011)
New Revision: 4832
Added:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent/WorkspaceStorageCacheListener.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ACLHolder.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/BloomFilter.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ShareableSupportedWorkspaceDataManager.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorksapceDataManagerBloomFilter.java
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/MappedParametrizedObjectEntry.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent/WorkspaceStorageCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/QPath.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/QPathEntry.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/LinkedWorkspaceStorageCacheImpl.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/VersionableWorkspaceDataManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/ISPNCacheWorkspaceStorageCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/inmemory/InmemoryStorageConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCStorageConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/CQJDBCStorageConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/statistics/StatisticsJDBCStorageConnection.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/WorkspaceDataContainer.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/WorkspaceStorageConnection.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/BaseStandaloneTest.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestWorkspaceStorageCacheInClusterMode.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCache.java
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/configuration/exo-jcr-configuration.xml
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/configuration/workspace-persistence-storage.xml
Log:
EXOJCR-1412: use bloom filters to store ids of nodes with ACL (modified patch from EXOJCR-1456)
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/MappedParametrizedObjectEntry.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/MappedParametrizedObjectEntry.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/MappedParametrizedObjectEntry.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -227,6 +227,55 @@
}
/**
+ * Parse named parameter as Double.
+ *
+ * @param name
+ * parameter name
+ * @param defaultValue
+ * default Double value
+ * @return Double value
+ */
+ public Double getParameterDouble(String name, Double defaultValue)
+ {
+ for (int i = 0; i < parameters.size(); i++)
+ {
+ SimpleParameterEntry p = parameters.get(i);
+ if (p.getName().equals(name))
+ {
+ try
+ {
+ return StringNumberParser.parseDouble(p.getValue());
+ }
+ catch (NumberFormatException e)
+ {
+ //LOG.warn(name + ": unparseable Long. " + e);
+ }
+ }
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Parse named parameter as Double.
+ *
+ * @param name
+ * parameter name
+ * @return Double value
+ * @throws RepositoryConfigurationException
+ */
+ public Double getParameterDouble(String name) throws RepositoryConfigurationException
+ {
+ try
+ {
+ return StringNumberParser.parseDouble(getParameterValue(name));
+ }
+ catch (NumberFormatException e)
+ {
+ throw new RepositoryConfigurationException(name + ": unparseable Long. " + e, e);
+ }
+ }
+
+ /**
* Parse named parameter using {@link StringNumberParser.parseTime} and return time in
* milliseconds (Long value).
*
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent/WorkspaceStorageCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent/WorkspaceStorageCache.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent/WorkspaceStorageCache.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -275,16 +275,31 @@
/**
* Start buffering process.
*/
- public void beginTransaction();
+ void beginTransaction();
/**
* Sort changes and commit data to the cache.
*/
- public void commitTransaction();
+ void commitTransaction();
/**
* Forget about changes
*/
- public void rollbackTransaction();
+ void rollbackTransaction();
+ /**
+ * Adds a new listener
+ * @param listener the listener to register
+ * @throws UnsupportedOperationException in case the listeners are not supported by the
+ * implementation
+ */
+ void addListener(WorkspaceStorageCacheListener listener) throws UnsupportedOperationException;
+
+ /**
+ * Removes a listener
+ * @param listener the listener to remove
+ * @throws UnsupportedOperationException in case the listeners are not supported by the
+ * implementation
+ */
+ void removeListener(WorkspaceStorageCacheListener listener) throws UnsupportedOperationException;
}
Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent/WorkspaceStorageCacheListener.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent/WorkspaceStorageCacheListener.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/persistent/WorkspaceStorageCacheListener.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.dataflow.persistent;
+
+import org.exoplatform.services.jcr.datamodel.ItemData;
+
+/**
+ * This class allows other class to be notified when a given cache event occurs
+ *
+ * @author <a href="mailto:nfilotto at exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ *
+ */
+public interface WorkspaceStorageCacheListener
+{
+ /**
+ * Called when a cache entry corresponding to the given item has been added
+ * @param data the item corresponding to the added cache entry
+ */
+ void onCacheEntryAdded(ItemData data);
+
+ /**
+ * Called when a cache entry corresponding to the given item has been updated
+ * @param data the item corresponding to the updated cache entry
+ */
+ void onCacheEntryUpdated(ItemData data);
+}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/QPath.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/QPath.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/QPath.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -469,6 +469,34 @@
}
/**
+ * Make child path using QName and Item index. <br/>
+ *
+ * @param parent
+ * - parent QPath
+ * @param name
+ * - Item QName
+ * @param itemIndex
+ * - Item index
+ * @param id
+ * - Item id
+ * @return new QPath
+ */
+ public static QPath makeChildPath(final QPath parent, final QName name, final int itemIndex, String id)
+ {
+
+ QPathEntry[] parentEntries = parent.getEntries();
+ QPathEntry[] names = new QPathEntry[parentEntries.length + 1];
+ int index = 0;
+ for (QPathEntry pname : parentEntries)
+ {
+ names[index++] = pname;
+ }
+ names[index] = new QPathEntry(name.getNamespace(), name.getName(), itemIndex, id);
+
+ QPath path = new QPath(names);
+ return path;
+ }
+ /**
* Make child path using array of QPath entries (relative path). <br/>
*
* @param parent
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/QPathEntry.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/QPathEntry.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/QPathEntry.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -36,6 +36,8 @@
private String cachedToStringShowIndex;
+ private String id;
+
/**
* QPathEntry constructor.
*
@@ -46,10 +48,27 @@
*/
public QPathEntry(InternalQName qName, int index)
{
+ this(qName, index, null);
+ }
+
+
+ /**
+ * QPathEntry constructor.
+ *
+ * @param qName
+ * - InternalQName (full qualified name)
+ * @param index
+ * - Item index
+ * @param id
+ * - Item id
+ */
+ public QPathEntry(InternalQName qName, int index, String id)
+ {
super(qName.getNamespace(), qName.getName());
this.index = index > 0 ? index : 1;
+ this.id = id;
}
-
+
/**
* QPathEntry constructor.
*
@@ -62,8 +81,26 @@
*/
public QPathEntry(String namespace, String name, int index)
{
+ this(namespace, name, index, null);
+ }
+
+ /**
+ * QPathEntry constructor.
+ *
+ * @param namespace
+ * - namespace URI
+ * @param name
+ * - Item name
+ * @param index
+ * - Item index
+ * @param id
+ * - Item id
+ */
+ public QPathEntry(String namespace, String name, int index, String id)
+ {
super(namespace, name);
this.index = index > 0 ? index : 1;
+ this.id = id;
}
/**
@@ -89,6 +126,16 @@
InternalQName qname = InternalQName.parse(qnameString);
return new QPathEntry(qname, Integer.valueOf(indexString));
+ }
+
+ /**
+ * Return Item id, can be null since it could not be set
+ *
+ * @return the id of the item
+ */
+ public String getId()
+ {
+ return id;
}
/**
Copied: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ACLHolder.java (from rev 4787, jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ACLHolder.java)
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ACLHolder.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ACLHolder.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent;
+
+/**
+ * @author <a href="mailto:nfilotto at exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ *
+ */
+public class ACLHolder
+{
+ /**
+ * The id of the node that holds some ACL info
+ */
+ private final String id;
+
+ /**
+ * A flag indicating whether or not the node has owner set
+ */
+ private boolean owner;
+
+ /**
+ * A flag indicating whether or not the node has permissions set
+ */
+ private boolean permissions;
+
+ public ACLHolder(String id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * @return the id
+ */
+ public String getId()
+ {
+ return id;
+ }
+
+ /**
+ * @return the owner
+ */
+ public boolean hasOwner()
+ {
+ return owner;
+ }
+
+ /**
+ * @return the permissions
+ */
+ public boolean hasPermissions()
+ {
+ return permissions;
+ }
+
+ /**
+ * @param owner the owner to set
+ */
+ public void setOwner(boolean owner)
+ {
+ this.owner = owner;
+ }
+
+ /**
+ * @param permissions the permissions to set
+ */
+ public void setPermissions(boolean permissions)
+ {
+ this.permissions = permissions;
+ }
+}
Copied: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/BloomFilter.java (from rev 4787, jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/BloomFilter.java)
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/BloomFilter.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/BloomFilter.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent;
+
+import java.io.Serializable;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.BitSet;
+import java.util.Collection;
+
+/**
+ * Implementation of a Bloom-filter, as described here:
+ * http://en.wikipedia.org/wiki/Bloom_filter
+ *
+ * Inspired by the SimpleBloomFilter-class written by Ian Clarke. This
+ * implementation provides a more evenly distributed Hash-function by
+ * using a proper digest instead of the Java RNG. Many of the changes
+ * were proposed in comments in his blog:
+ * http://blog.locut.us/2008/01/12/a-decent-stand-alone-java-bloom-filter-implementation/
+ *
+ * @param <E> Object type that is to be inserted into the Bloom filter, e.g. String or Integer.
+ * @author Magnus Skjegstad <magnus at skjegstad.com>
+ */
+public class BloomFilter<E> implements Serializable {
+ private BitSet bitset;
+ private int bitSetSize;
+ private double bitsPerElement;
+ private int expectedNumberOfFilterElements; // expected (maximum) number of elements to be added
+ private int numberOfAddedElements; // number of elements actually added to the Bloom filter
+ private int k; // number of hash functions
+
+ static final Charset charset = Charset.forName("UTF-8"); // encoding used for storing hash values as strings
+
+ static final String hashName = "MD5"; // MD5 gives good enough accuracy in most circumstances. Change to SHA1 if it's needed
+ static final MessageDigest digestFunction;
+ static { // The digest method is reused between instances
+ MessageDigest tmp;
+ try {
+ tmp = java.security.MessageDigest.getInstance(hashName);
+ } catch (NoSuchAlgorithmException e) {
+ tmp = null;
+ }
+ digestFunction = tmp;
+ }
+
+ /**
+ * Constructs an empty Bloom filter. The total length of the Bloom filter will be
+ * c*n.
+ *
+ * @param c is the number of bits used per element.
+ * @param n is the expected number of elements the filter will contain.
+ * @param k is the number of hash functions used.
+ */
+ public BloomFilter(double c, int n, int k) {
+ this.expectedNumberOfFilterElements = n;
+ this.k = k;
+ this.bitsPerElement = c;
+ this.bitSetSize = (int)Math.ceil(c * n);
+ numberOfAddedElements = 0;
+ this.bitset = new BitSet(bitSetSize);
+ }
+
+ /**
+ * Constructs an empty Bloom filter. The optimal number of hash functions (k) is estimated from the total size of the Bloom
+ * and the number of expected elements.
+ *
+ * @param bitSetSize defines how many bits should be used in total for the filter.
+ * @param expectedNumberOElements defines the maximum number of elements the filter is expected to contain.
+ */
+ public BloomFilter(int bitSetSize, int expectedNumberOElements) {
+ this(bitSetSize / (double)expectedNumberOElements,
+ expectedNumberOElements,
+ (int) Math.round((bitSetSize / (double)expectedNumberOElements) * Math.log(2.0)));
+ }
+
+ /**
+ * Constructs an empty Bloom filter with a given false positive probability. The number of bits per
+ * element and the number of hash functions is estimated
+ * to match the false positive probability.
+ *
+ * @param falsePositiveProbability is the desired false positive probability.
+ * @param expectedNumberOfElements is the expected number of elements in the Bloom filter.
+ */
+ public BloomFilter(double falsePositiveProbability, int expectedNumberOfElements) {
+ this(Math.ceil(-(Math.log(falsePositiveProbability) / Math.log(2))) / Math.log(2), // c = k / ln(2)
+ expectedNumberOfElements,
+ (int)Math.ceil(-(Math.log(falsePositiveProbability) / Math.log(2)))); // k = ceil(-log_2(false prob.))
+ }
+
+ /**
+ * Construct a new Bloom filter based on existing Bloom filter data.
+ *
+ * @param bitSetSize defines how many bits should be used for the filter.
+ * @param expectedNumberOfFilterElements defines the maximum number of elements the filter is expected to contain.
+ * @param actualNumberOfFilterElements specifies how many elements have been inserted into the <code>filterData</code> BitSet.
+ * @param filterData a BitSet representing an existing Bloom filter.
+ */
+ public BloomFilter(int bitSetSize, int expectedNumberOfFilterElements, int actualNumberOfFilterElements, BitSet filterData) {
+ this(bitSetSize, expectedNumberOfFilterElements);
+ this.bitset = filterData;
+ this.numberOfAddedElements = actualNumberOfFilterElements;
+ }
+
+ /**
+ * Generates a digest based on the contents of a String.
+ *
+ * @param val specifies the input data.
+ * @param charset specifies the encoding of the input data.
+ * @return digest as long.
+ */
+ public static long createHash(String val, Charset charset) {
+ return createHash(val.getBytes(charset));
+ }
+
+ /**
+ * Generates a digest based on the contents of a String.
+ *
+ * @param val specifies the input data. The encoding is expected to be UTF-8.
+ * @return digest as long.
+ */
+ public static long createHash(String val) {
+ return createHash(val, charset);
+ }
+
+ /**
+ * Generates a digest based on the contents of an array of bytes.
+ *
+ * @param data specifies input data.
+ * @return digest as long.
+ */
+ public static long createHash(byte[] data) {
+ long h = 0;
+ byte[] res;
+
+ synchronized (digestFunction) {
+ res = digestFunction.digest(data);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ h <<= 8;
+ h |= ((int) res[i]) & 0xFF;
+ }
+ return h;
+ }
+
+ /**
+ * Compares the contents of two instances to see if they are equal.
+ *
+ * @param obj is the object to compare to.
+ * @return True if the contents of the objects are equal.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final BloomFilter<E> other = (BloomFilter<E>) obj;
+ if (this.expectedNumberOfFilterElements != other.expectedNumberOfFilterElements) {
+ return false;
+ }
+ if (this.k != other.k) {
+ return false;
+ }
+ if (this.bitSetSize != other.bitSetSize) {
+ return false;
+ }
+ if (this.bitset != other.bitset && (this.bitset == null || !this.bitset.equals(other.bitset))) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Calculates a hash code for this class.
+ * @return hash code representing the contents of an instance of this class.
+ */
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 61 * hash + (this.bitset != null ? this.bitset.hashCode() : 0);
+ hash = 61 * hash + this.expectedNumberOfFilterElements;
+ hash = 61 * hash + this.bitSetSize;
+ hash = 61 * hash + this.k;
+ return hash;
+ }
+
+
+ /**
+ * Calculates the expected probability of false positives based on
+ * the number of expected filter elements and the size of the Bloom filter.
+ * <br /><br />
+ * The value returned by this method is the <i>expected</i> rate of false
+ * positives, assuming the number of inserted elements equals the number of
+ * expected elements. If the number of elements in the Bloom filter is less
+ * than the expected value, the true probability of false positives will be lower.
+ *
+ * @return expected probability of false positives.
+ */
+ public double expectedFalsePositiveProbability() {
+ return getFalsePositiveProbability(expectedNumberOfFilterElements);
+ }
+
+ /**
+ * Calculate the probability of a false positive given the specified
+ * number of inserted elements.
+ *
+ * @param numberOfElements number of inserted elements.
+ * @return probability of a false positive.
+ */
+ public double getFalsePositiveProbability(double numberOfElements) {
+ // (1 - e^(-k * n / m)) ^ k
+ return Math.pow((1 - Math.exp(-k * (double) numberOfElements
+ / (double) bitSetSize)), k);
+
+ }
+
+ /**
+ * Get the current probability of a false positive. The probability is calculated from
+ * the size of the Bloom filter and the current number of elements added to it.
+ *
+ * @return probability of false positives.
+ */
+ public double getFalsePositiveProbability() {
+ return getFalsePositiveProbability(numberOfAddedElements);
+ }
+
+
+ /**
+ * Returns the value chosen for K.<br />
+ * <br />
+ * K is the optimal number of hash functions based on the size
+ * of the Bloom filter and the expected number of inserted elements.
+ *
+ * @return optimal k.
+ */
+ public int getK() {
+ return k;
+ }
+
+ /**
+ * Sets all bits to false in the Bloom filter.
+ */
+ public void clear() {
+ bitset.clear();
+ numberOfAddedElements = 0;
+ }
+
+ /**
+ * Adds an object to the Bloom filter. The output from the object's
+ * toString() method is used as input to the hash functions.
+ *
+ * @param element is an element to register in the Bloom filter.
+ */
+ public void add(E element) {
+ long hash;
+ String valString = element.toString();
+ for (int x = 0; x < k; x++) {
+ hash = createHash(valString + Integer.toString(x));
+ hash = hash % (long)bitSetSize;
+ bitset.set(Math.abs((int)hash), true);
+ }
+ numberOfAddedElements ++;
+ }
+
+ /**
+ * Adds all elements from a Collection to the Bloom filter.
+ * @param c Collection of elements.
+ */
+ public void addAll(Collection<? extends E> c) {
+ for (E element : c)
+ add(element);
+ }
+
+ /**
+ * Returns true if the element could have been inserted into the Bloom filter.
+ * Use getFalsePositiveProbability() to calculate the probability of this
+ * being correct.
+ *
+ * @param element element to check.
+ * @return true if the element could have been inserted into the Bloom filter.
+ */
+ public boolean contains(E element) {
+ long hash;
+ String valString = element.toString();
+ for (int x = 0; x < k; x++) {
+ hash = createHash(valString + Integer.toString(x));
+ hash = hash % (long)bitSetSize;
+ if (!bitset.get(Math.abs((int)hash)))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if all the elements of a Collection could have been inserted
+ * into the Bloom filter. Use getFalsePositiveProbability() to calculate the
+ * probability of this being correct.
+ * @param c elements to check.
+ * @return true if all the elements in c could have been inserted into the Bloom filter.
+ */
+ public boolean containsAll(Collection<? extends E> c) {
+ for (E element : c)
+ if (!contains(element))
+ return false;
+ return true;
+ }
+
+ /**
+ * Read a single bit from the Bloom filter.
+ * @param bit the bit to read.
+ * @return true if the bit is set, false if it is not.
+ */
+ public boolean getBit(int bit) {
+ return bitset.get(bit);
+ }
+
+ /**
+ * Set a single bit in the Bloom filter.
+ * @param bit is the bit to set.
+ * @param value If true, the bit is set. If false, the bit is cleared.
+ */
+ public void setBit(int bit, boolean value) {
+ bitset.set(bit, value);
+ }
+
+ /**
+ * Return the bit set used to store the Bloom filter.
+ * @return bit set representing the Bloom filter.
+ */
+ public BitSet getBitSet() {
+ return bitset;
+ }
+
+ /**
+ * Returns the number of bits in the Bloom filter. Use count() to retrieve
+ * the number of inserted elements.
+ *
+ * @return the size of the bitset used by the Bloom filter.
+ */
+ public int size() {
+ return this.bitSetSize;
+ }
+
+ /**
+ * Returns the number of elements added to the Bloom filter after it
+ * was constructed or after clear() was called.
+ *
+ * @return number of elements added to the Bloom filter.
+ */
+ public int count() {
+ return this.numberOfAddedElements;
+ }
+
+ /**
+ * Returns the expected number of elements to be inserted into the filter.
+ * This value is the same value as the one passed to the constructor.
+ *
+ * @return expected number of elements.
+ */
+ public int getExpectedNumberOfElements() {
+ return expectedNumberOfFilterElements;
+ }
+
+ /**
+ * Get expected number of bits per element when the Bloom filter is full. This value is set by the constructor
+ * when the Bloom filter is created. See also getBitsPerElement().
+ *
+ * @return expected number of bits per element.
+ */
+ public double getExpectedBitsPerElement() {
+ return this.bitsPerElement;
+ }
+
+ /**
+ * Get actual number of bits per element based on the number of elements that have currently been inserted and the length
+ * of the Bloom filter. See also getExpectedBitsPerElement().
+ *
+ * @return number of bits per element.
+ */
+ public double getBitsPerElement() {
+ return this.bitSetSize / (double)numberOfAddedElements;
+ }
+}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -19,10 +19,15 @@
package org.exoplatform.services.jcr.impl.dataflow.persistent;
import org.exoplatform.commons.utils.SecurityHelper;
+import org.exoplatform.management.annotations.Managed;
+import org.exoplatform.management.annotations.ManagedDescription;
+import org.exoplatform.services.jcr.access.AccessControlEntry;
import org.exoplatform.services.jcr.access.AccessControlList;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
import org.exoplatform.services.jcr.dataflow.persistent.MandatoryItemsPersistenceListener;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener;
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
@@ -49,6 +54,7 @@
import org.exoplatform.services.rpc.TopologyChangeEvent;
import org.exoplatform.services.rpc.TopologyChangeListener;
import org.exoplatform.services.transaction.TransactionService;
+import org.picocontainer.Startable;
import java.io.Serializable;
import java.security.PrivilegedAction;
@@ -64,6 +70,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.jcr.RepositoryException;
@@ -80,9 +87,13 @@
* @version $Id$
*/
public class CacheableWorkspaceDataManager extends WorkspacePersistentDataManager implements Suspendable,
- TopologyChangeListener
+ TopologyChangeListener, Startable, WorkspaceStorageCacheListener
{
+ private final static double ACL_BF_FALSE_PROPBABILITY_DEFAULT = 0.1d;
+
+ private final static int ACL_BF_ELEMENTS_NUMBER_DEFAULT = 1000000;
+
/**
* Items cache.
*/
@@ -98,6 +109,19 @@
*/
private final TransactionableResourceManager txResourceManager;
+ private final AtomicBoolean filtersEnabled = new AtomicBoolean();
+
+ /**
+ * Bloom filter parameters.
+ */
+ private final double bfProbability;
+
+ private final int bfElementNumber;
+
+ private volatile BloomFilter<String> filterPermissions;
+
+ private volatile BloomFilter<String> filterOwner;
+
private TransactionManager transactionManager;
/**
@@ -348,6 +372,8 @@
/**
* CacheableWorkspaceDataManager constructor.
*
+ * @param wsConfig
+ * WorkspaceEntry used to fetch bloom filter parameters
* @param dataContainer
* Workspace data container (persistent level)
* @param cache
@@ -361,11 +387,30 @@
* @param rpcService
* the service for executing commands on all nodes of cluster
*/
- public CacheableWorkspaceDataManager(WorkspaceDataContainer dataContainer, WorkspaceStorageCache cache,
- SystemDataContainerHolder systemDataContainerHolder, TransactionableResourceManager txResourceManager,
- TransactionService transactionService, RPCService rpcService)
+ public CacheableWorkspaceDataManager(WorkspaceEntry wsConfig, WorkspaceDataContainer dataContainer,
+ WorkspaceStorageCache cache, SystemDataContainerHolder systemDataContainerHolder,
+ TransactionableResourceManager txResourceManager, TransactionService transactionService, RPCService rpcService)
{
super(dataContainer, systemDataContainerHolder, txResourceManager);
+
+ bfProbability =
+ wsConfig.getContainer().getParameterDouble(WorkspaceDataContainer.ACL_BF_FALSE_PROPBABILITY,
+ ACL_BF_FALSE_PROPBABILITY_DEFAULT);
+ if (bfProbability < 0 || bfProbability > 1)
+ {
+ throw new IllegalArgumentException("Parameter " + WorkspaceDataContainer.ACL_BF_FALSE_PROPBABILITY
+ + " is invalid, must be between 0 and 1.");
+ }
+
+ bfElementNumber =
+ wsConfig.getContainer().getParameterInteger(WorkspaceDataContainer.ACL_BF_ELEMENTS_NUMBER,
+ ACL_BF_ELEMENTS_NUMBER_DEFAULT);
+ if (bfElementNumber <= 0)
+ {
+ throw new IllegalArgumentException("Parameter " + WorkspaceDataContainer.ACL_BF_ELEMENTS_NUMBER
+ + " is invalid, can not be less then 1.");
+ }
+
this.cache = cache;
this.requestCache = new ConcurrentHashMap<Integer, DataRequest>();
@@ -381,6 +426,8 @@
/**
* CacheableWorkspaceDataManager constructor.
*
+ * @param wsConfig
+ * WorkspaceEntry used to fetch bloom filter parameters
* @param dataContainer
* Workspace data container (persistent level)
* @param cache
@@ -391,16 +438,18 @@
* the resource manager used to manage the whole tx
* @param transactionService TransactionService
*/
- public CacheableWorkspaceDataManager(WorkspaceDataContainer dataContainer, WorkspaceStorageCache cache,
- SystemDataContainerHolder systemDataContainerHolder, TransactionableResourceManager txResourceManager,
- TransactionService transactionService)
+ public CacheableWorkspaceDataManager(WorkspaceEntry wsConfig, WorkspaceDataContainer dataContainer,
+ WorkspaceStorageCache cache, SystemDataContainerHolder systemDataContainerHolder,
+ TransactionableResourceManager txResourceManager, TransactionService transactionService)
{
- this(dataContainer, cache, systemDataContainerHolder, txResourceManager, transactionService, null);
+ this(wsConfig, dataContainer, cache, systemDataContainerHolder, txResourceManager, transactionService, null);
}
/**
* CacheableWorkspaceDataManager constructor.
*
+ * @param wsConfig
+ * WorkspaceEntry used to fetch bloom filter parameters
* @param dataContainer
* Workspace data container (persistent level)
* @param cache
@@ -410,11 +459,30 @@
* @param txResourceManager
* the resource manager used to manage the whole tx
*/
- public CacheableWorkspaceDataManager(WorkspaceDataContainer dataContainer, WorkspaceStorageCache cache,
- SystemDataContainerHolder systemDataContainerHolder, TransactionableResourceManager txResourceManager,
- RPCService rpcService)
+ public CacheableWorkspaceDataManager(WorkspaceEntry wsConfig, WorkspaceDataContainer dataContainer,
+ WorkspaceStorageCache cache, SystemDataContainerHolder systemDataContainerHolder,
+ TransactionableResourceManager txResourceManager, RPCService rpcService)
{
super(dataContainer, systemDataContainerHolder, txResourceManager);
+
+ bfProbability =
+ wsConfig.getContainer().getParameterDouble(WorkspaceDataContainer.ACL_BF_FALSE_PROPBABILITY,
+ ACL_BF_FALSE_PROPBABILITY_DEFAULT);
+ if (bfProbability < 0 || bfProbability > 1)
+ {
+ throw new IllegalArgumentException("Parameter " + WorkspaceDataContainer.ACL_BF_FALSE_PROPBABILITY
+ + " is invalid, must be between 0 and 1.");
+ }
+
+ bfElementNumber =
+ wsConfig.getContainer().getParameterInteger(WorkspaceDataContainer.ACL_BF_ELEMENTS_NUMBER,
+ ACL_BF_ELEMENTS_NUMBER_DEFAULT);
+ if (bfElementNumber <= 0)
+ {
+ throw new IllegalArgumentException("Parameter " + WorkspaceDataContainer.ACL_BF_ELEMENTS_NUMBER
+ + " is invalid, can not be less then 1.");
+ }
+
this.cache = cache;
this.requestCache = new ConcurrentHashMap<Integer, DataRequest>();
@@ -439,6 +507,8 @@
/**
* CacheableWorkspaceDataManager constructor.
*
+ * @param wsConfig
+ * WorkspaceEntry used to fetch bloom filter parameters
* @param dataContainer
* Workspace data container (persistent level)
* @param cache
@@ -448,15 +518,18 @@
* @param txResourceManager
* the resource manager used to manage the whole tx
*/
- public CacheableWorkspaceDataManager(WorkspaceDataContainer dataContainer, WorkspaceStorageCache cache,
- SystemDataContainerHolder systemDataContainerHolder, TransactionableResourceManager txResourceManager)
+ public CacheableWorkspaceDataManager(WorkspaceEntry wsConfig, WorkspaceDataContainer dataContainer,
+ WorkspaceStorageCache cache, SystemDataContainerHolder systemDataContainerHolder,
+ TransactionableResourceManager txResourceManager)
{
- this(dataContainer, cache, systemDataContainerHolder, txResourceManager, (RPCService)null);
+ this(wsConfig, dataContainer, cache, systemDataContainerHolder, txResourceManager, (RPCService)null);
}
/**
* CacheableWorkspaceDataManager constructor.
*
+ * @param wsConfig
+ * WorkspaceEntry used to fetch bloom filter parameters
* @param dataContainer
* Workspace data container (persistent level)
* @param cache
@@ -464,10 +537,10 @@
* @param systemDataContainerHolder
* System Workspace data container (persistent level)
*/
- public CacheableWorkspaceDataManager(WorkspaceDataContainer dataContainer, WorkspaceStorageCache cache,
- SystemDataContainerHolder systemDataContainerHolder)
+ public CacheableWorkspaceDataManager(WorkspaceEntry wsConfig, WorkspaceDataContainer dataContainer,
+ WorkspaceStorageCache cache, SystemDataContainerHolder systemDataContainerHolder)
{
- this(dataContainer, cache, systemDataContainerHolder, null, (RPCService)null);
+ this(wsConfig, dataContainer, cache, systemDataContainerHolder, null, (RPCService)null);
}
/**
@@ -712,8 +785,22 @@
* {@inheritDoc}
*/
@Override
- public ItemData getItemData(final String identifier) throws RepositoryException
+ public ItemData getItemData(String identifier) throws RepositoryException
{
+ return getItemData(identifier, true);
+ }
+
+ /**
+ * Do the same thing as getItemData(identifier), but ACL initialization can be specified.
+ * If doInitACL is true (default value for getItemData(identifier)) ACL will be initialized.
+ *
+ * @param identifier
+ * @param doInitACL
+ * @return
+ * @throws RepositoryException
+ */
+ private ItemData getItemData(final String identifier, final boolean doInitACL) throws RepositoryException
+ {
if (cache.isEnabled())
{
// 1. Try from cache
@@ -766,7 +853,14 @@
public ItemData run() throws RepositoryException
{
ItemData item = CacheableWorkspaceDataManager.super.getItemData(identifier);
- return item != null && item.isNode() ? initACL(null, (NodeData)item) : item;
+ if (item != null && item.isNode() && doInitACL)
+ {
+ return initACL(null, (NodeData)item);
+ }
+ else
+ {
+ return item;
+ }
}
});
}
@@ -2024,16 +2118,30 @@
/**
* Init ACL of the node.
- *
* @param parent
* - a parent, can be null (get item by id)
- * @param data
+ * @param node
* - an item data
* @return - an item data with ACL was initialized
* @throws RepositoryException
*/
private ItemData initACL(NodeData parent, NodeData node) throws RepositoryException
{
+ return initACL(parent, node, null);
+ }
+
+ /**
+ * @param parent
+ * - a parent, can be null (get item by id)
+ * @param node
+ * - an node data
+ * @param search
+ * - indicates what we are looking for
+ * @return - an node data with ACL was initialized
+ * @throws RepositoryException
+ */
+ private NodeData initACL(NodeData parent, NodeData node, ACLSearch search) throws RepositoryException
+ {
if (node != null)
{
AccessControlList acl = node.getACL();
@@ -2043,23 +2151,43 @@
{
// use parent ACL
node =
- new TransientNodeData(node.getQPath(), node.getIdentifier(), node.getPersistedVersion(), node
- .getPrimaryTypeName(), node.getMixinTypeNames(), node.getOrderNumber(),
+ new TransientNodeData(node.getQPath(), node.getIdentifier(), node.getPersistedVersion(),
+ node.getPrimaryTypeName(), node.getMixinTypeNames(), node.getOrderNumber(),
node.getParentIdentifier(), parent.getACL());
}
else
{
+ if (search == null)
+ {
+ search = new ACLSearch(null, null);
+ }
// use nearest ancestor ACL... case of get by id
node =
- new TransientNodeData(node.getQPath(), node.getIdentifier(), node.getPersistedVersion(), node
- .getPrimaryTypeName(), node.getMixinTypeNames(), node.getOrderNumber(),
- node.getParentIdentifier(), getNearestACAncestorAcl(node));
+ new TransientNodeData(node.getQPath(), node.getIdentifier(), node.getPersistedVersion(),
+ node.getPrimaryTypeName(), node.getMixinTypeNames(), node.getOrderNumber(),
+ node.getParentIdentifier(), getNearestACAncestorAcl(node, search));
}
}
else if (!acl.hasPermissions())
{
// use nearest ancestor permissions
- AccessControlList ancestorAcl = getNearestACAncestorAcl(node);
+ if (search == null)
+ {
+ search = new ACLSearch(acl.getOwner(), null);
+ }
+ else
+ {
+ search.setOwner(acl.getOwner());
+ if (search.found())
+ {
+ return new TransientNodeData(node.getQPath(), node.getIdentifier(), node.getPersistedVersion(),
+ node.getPrimaryTypeName(), node.getMixinTypeNames(), node.getOrderNumber(),
+ node.getParentIdentifier(), new AccessControlList(acl.getOwner(), null));
+ }
+ }
+ AccessControlList ancestorAcl =
+ parent != null && parent.getACL() != null && parent.getACL().hasPermissions() ? parent.getACL()
+ : getNearestACAncestorAcl(node, search);
node =
new TransientNodeData(node.getQPath(), node.getIdentifier(), node.getPersistedVersion(), node
@@ -2068,8 +2196,24 @@
}
else if (!acl.hasOwner())
{
+ if (search == null)
+ {
+ search = new ACLSearch(null, acl.getPermissionEntries());
+ }
+ else
+ {
+ search.setPermissions(acl.getPermissionEntries());
+ if (search.found())
+ {
+ return new TransientNodeData(node.getQPath(), node.getIdentifier(), node.getPersistedVersion(),
+ node.getPrimaryTypeName(), node.getMixinTypeNames(), node.getOrderNumber(),
+ node.getParentIdentifier(), new AccessControlList(null, acl.getPermissionEntries()));
+ }
+ }
// use nearest ancestor owner
- AccessControlList ancestorAcl = getNearestACAncestorAcl(node);
+ AccessControlList ancestorAcl =
+ parent != null && parent.getACL() != null && parent.getACL().hasOwner() ? parent.getACL()
+ : getNearestACAncestorAcl(node, search);
node =
new TransientNodeData(node.getQPath(), node.getIdentifier(), node.getPersistedVersion(), node
@@ -2088,27 +2232,281 @@
*
* @param node
* - item
+ * @param search
+ * - indicates what we are looking for
* @return - parent or null
* @throws RepositoryException
*/
- private AccessControlList getNearestACAncestorAcl(NodeData node) throws RepositoryException
+ private AccessControlList getNearestACAncestorAcl(NodeData node, ACLSearch search) throws RepositoryException
{
-
- if (node.getParentIdentifier() != null)
+ String id = node.getParentIdentifier();
+ if (id != null)
{
- NodeData parent = (NodeData)getItemData(node.getParentIdentifier());
- while (parent != null)
+ boolean filtersEnabled = this.filtersEnabled.get();
+ BloomFilter<String> filterPermissions = this.filterPermissions;
+ BloomFilter<String> filterOwner = this.filterOwner;
+ if (filtersEnabled && filterOwner != null && filterPermissions != null)
{
- if (parent.getACL() != null)
+ QPathEntry[] entries = node.getQPath().getEntries();
+ for (int i = entries.length - 2; i >= 0; i--)
{
- // has an AC parent
- return parent.getACL();
+ QPathEntry entry = entries[i];
+ String currentId = entry.getId();
+ if (currentId == null)
+ {
+ // the path doesn't contain any id so we do a normal call
+ break;
+ }
+ else if ((!search.hasOwner() && filterOwner.contains(currentId))
+ || (!search.hasPermissions() && filterPermissions.contains(currentId)))
+ {
+ id = currentId;
+ break;
+ }
+ else
+ {
+ id = currentId;
+ }
}
- // going up to the root
- parent = (NodeData)getItemData(parent.getParentIdentifier());
}
+ NodeData parent = getACL(id, search);
+ if (parent != null && parent.getACL() != null)
+ {
+ // has an AC parent
+ return parent.getACL();
+ }
}
return new AccessControlList();
}
+ /**
+ * Find Item by identifier to get the missing ACL information.
+ *
+ * @param identifier the id of the node that we are looking for to fill the ACL research
+ * @param search the ACL search describing what we are looking for
+ * @return NodeData, data by identifier
+ */
+ private NodeData getACL(String identifier, ACLSearch search) throws RepositoryException
+ {
+ final ItemData item = getItemData(identifier, false);
+ return item != null && item.isNode() ? initACL(null, (NodeData)item, search) : null;
+ }
+
+ /**
+ * Gets the list of all the ACL holders
+ * @throws RepositoryException if an error occurs
+ */
+ public List<ACLHolder> getACLHolders() throws RepositoryException
+ {
+ WorkspaceStorageConnection conn = dataContainer.openConnection();
+ try
+ {
+ return conn.getACLHolders();
+ }
+ finally
+ {
+ conn.close();
+ }
+ }
+
+ /**
+ * Reloads the bloom filters
+ * @return <code>true</code> if the filters could be reloaded successfully, <code>false</code> otherwise.
+ */
+ @Managed
+ @ManagedDescription("Reloads the bloom filters used to efficiently manage the ACLs")
+ public boolean reloadFilters()
+ {
+ return loadFilters(false);
+ }
+
+ /**
+ * Clears the bloom filters
+ */
+ protected void clear()
+ {
+ this.filterPermissions = null;
+ this.filterOwner = null;
+ }
+
+ /**
+ * @see org.picocontainer.Startable#start()
+ */
+ public void start()
+ {
+ try
+ {
+ this.cache.addListener(this);
+ }
+ catch (UnsupportedOperationException e)
+ {
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("The method addListener is not supported", e);
+ }
+ return;
+ }
+
+ loadFilters(true);
+ }
+
+ /**
+ * Loads the bloom filters
+ * @param cleanOnFail clean everything if an error occurs
+ * @return <code>true</code> if the filters could be loaded successfully, <code>false</code> otherwise.
+ */
+ protected boolean loadFilters(boolean cleanOnFail)
+ {
+ filtersEnabled.set(false);
+ this.filterPermissions = new BloomFilter<String>(bfProbability, bfElementNumber);
+ this.filterOwner = new BloomFilter<String>(bfProbability, bfElementNumber);
+ boolean fails = true;
+ List<ACLHolder> holders = null;
+ try
+ {
+ LOG.info("Getting all the ACL Holders from the persistence layer");
+ holders = getACLHolders();
+ fails = false;
+ }
+ catch (UnsupportedOperationException e)
+ {
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("The method getACLHolders is not supported", e);
+ }
+ }
+ catch (RepositoryException e)
+ {
+ LOG.error("Could not load all the ACL loaders", e);
+ }
+ if (fails)
+ {
+ if (cleanOnFail)
+ {
+ clear();
+ cache.removeListener(this);
+ }
+ return false;
+ }
+ else if (holders != null && !holders.isEmpty())
+ {
+ LOG.info("Adding all the ACL Holders found into the BloomFilters");
+ for (int i = 0, length = holders.size(); i < length; i++)
+ {
+ ACLHolder holder = holders.get(i);
+ if (holder.hasOwner())
+ {
+ filterOwner.add(holder.getId());
+ }
+ if (holder.hasPermissions())
+ {
+ filterPermissions.add(holder.getId());
+ }
+ }
+ }
+ filtersEnabled.set(true);
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stop()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onCacheEntryAdded(ItemData data)
+ {
+ onCacheEntryUpdated(data);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onCacheEntryUpdated(ItemData data)
+ {
+ if (data instanceof NodeData)
+ {
+ NodeData node = (NodeData)data;
+ AccessControlList acl = node.getACL();
+ if (acl == null)
+ {
+ return;
+ }
+ if (acl.hasOwner())
+ {
+ filterOwner.add(node.getIdentifier());
+ }
+ if (acl.hasPermissions())
+ {
+ filterPermissions.add(node.getIdentifier());
+ }
+ }
+ }
+
+ /**
+ * Defines what we are really looking for
+ */
+ private static class ACLSearch
+ {
+ private String owner;
+
+ private List<AccessControlEntry> permissions;
+
+ ACLSearch(String owner, List<AccessControlEntry> permissions)
+ {
+ this.owner = owner;
+ this.permissions = permissions;
+ }
+
+ /**
+ * @return <code>true</code> if the owner and the permission have been found, <code>false</code>
+ * otherwise
+ */
+ public boolean found()
+ {
+ return owner != null && permissions != null;
+ }
+
+ /**
+ * @param owner the owner to set
+ */
+ public void setOwner(String owner)
+ {
+ if (this.owner == null)
+ {
+ this.owner = owner;
+ }
+ }
+
+ /**
+ * @param permissions the permissions to set
+ */
+ public void setPermissions(List<AccessControlEntry> permissions)
+ {
+ if (this.permissions == null)
+ {
+ this.permissions = permissions;
+ }
+ }
+
+ /**
+ * @return the owner
+ */
+ public boolean hasOwner()
+ {
+ return owner != null;
+ }
+
+ /**
+ * @return the permissions
+ */
+ public boolean hasPermissions()
+ {
+ return permissions != null;
+ }
+ }
}
\ No newline at end of file
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/LinkedWorkspaceStorageCacheImpl.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/LinkedWorkspaceStorageCacheImpl.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/LinkedWorkspaceStorageCacheImpl.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -24,6 +24,7 @@
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener;
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
@@ -2216,4 +2217,20 @@
public void addChildNodesByPage(NodeData parent, List<NodeData> childs, int fromOrderNum)
{
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addListener(WorkspaceStorageCacheListener listener) throws UnsupportedOperationException
+ {
+ throw new UnsupportedOperationException("The cache listeners are not supported by the LinkedWorkspaceStorageCacheImpl");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeListener(WorkspaceStorageCacheListener listener) throws UnsupportedOperationException
+ {
+ throw new UnsupportedOperationException("The cache listeners are not supported by the LinkedWorkspaceStorageCacheImpl");
+ }
}
Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ShareableSupportedWorkspaceDataManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ShareableSupportedWorkspaceDataManager.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/ShareableSupportedWorkspaceDataManager.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent;
+
+import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
+import org.exoplatform.services.jcr.dataflow.SharedDataManager;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.ItemType;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.util.Calendar;
+import java.util.List;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS. Data Manager supported ACL Inheritance
+ *
+ * @author Gennady Azarenkov
+ * @version $Id: ACLInheritanceSupportedWorkspaceDataManager.java 11907 2008-03-13 15:36:21Z ksm $
+ */
+public class ShareableSupportedWorkspaceDataManager implements SharedDataManager
+{
+
+ private static Log LOG = ExoLogger.getLogger("exo.jcr.component.core.ACLInheritanceSupportedWorkspaceDataManager");
+
+ protected final CacheableWorkspaceDataManager persistentManager;
+
+ public ShareableSupportedWorkspaceDataManager(CacheableWorkspaceDataManager persistentManager)
+ {
+ this.persistentManager = persistentManager;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ // ------------ ItemDataConsumer impl ------------
+ public List<NodeData> getChildNodesData(NodeData parent) throws RepositoryException
+ {
+ return persistentManager.getChildNodesData(parent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<NodeData> getChildNodesData(NodeData parent, List<QPathEntryFilter> patternFilters) throws RepositoryException
+ {
+ return persistentManager.getChildNodesData(parent, patternFilters);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean getChildNodesDataByPage(NodeData parent, int fromOrderNum, int limit, List<NodeData> childs)
+ throws RepositoryException
+ {
+ return persistentManager.getChildNodesDataByPage(parent, fromOrderNum, limit, childs);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getLastOrderNumber(final NodeData parent) throws RepositoryException
+ {
+ return persistentManager.getLastOrderNumber(parent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getChildNodesCount(final NodeData parent) throws RepositoryException
+ {
+ return persistentManager.getChildNodesCount(parent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ItemData getItemData(NodeData parent, QPathEntry name) throws RepositoryException
+ {
+ return getItemData(parent, name, ItemType.UNKNOWN);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ItemData getItemData(NodeData parent, QPathEntry name, ItemType itemType) throws RepositoryException
+ {
+ return persistentManager.getItemData(parent, name, itemType);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ItemData getItemData(String identifier) throws RepositoryException
+ {
+ return persistentManager.getItemData(identifier);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<PropertyData> getChildPropertiesData(NodeData parent) throws RepositoryException
+ {
+ return persistentManager.getChildPropertiesData(parent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<PropertyData> getChildPropertiesData(NodeData parent, List<QPathEntryFilter> itemDataFilters)
+ throws RepositoryException
+ {
+ return persistentManager.getChildPropertiesData(parent, itemDataFilters);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<PropertyData> listChildPropertiesData(NodeData parent) throws RepositoryException
+ {
+ return persistentManager.listChildPropertiesData(parent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<PropertyData> getReferencesData(String identifier, boolean skipVersionStorage)
+ throws RepositoryException
+ {
+ return persistentManager.getReferencesData(identifier, skipVersionStorage);
+ }
+
+ // ------------ SharedDataManager ----------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ public void save(ItemStateChangesLog changes) throws InvalidItemStateException, UnsupportedOperationException,
+ RepositoryException
+ {
+ persistentManager.save(changes);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Calendar getCurrentTime()
+ {
+ return persistentManager.getCurrentTime();
+ }
+}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/VersionableWorkspaceDataManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/VersionableWorkspaceDataManager.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/VersionableWorkspaceDataManager.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -53,12 +53,12 @@
* @version $Id$
*/
-public class VersionableWorkspaceDataManager extends ACLInheritanceSupportedWorkspaceDataManager
+public class VersionableWorkspaceDataManager extends ShareableSupportedWorkspaceDataManager
{
private static Log log = ExoLogger.getLogger("exo.jcr.component.core.VersionableWorkspaceDataManager");
- private ACLInheritanceSupportedWorkspaceDataManager versionDataManager;
+ private ShareableSupportedWorkspaceDataManager versionDataManager;
public VersionableWorkspaceDataManager(CacheableWorkspaceDataManager persistentManager)
{
@@ -71,7 +71,7 @@
public void setSystemDataManager(DataManager systemDataManager)
{
- this.versionDataManager = (ACLInheritanceSupportedWorkspaceDataManager)systemDataManager;
+ this.versionDataManager = (ShareableSupportedWorkspaceDataManager)systemDataManager;
}
/**
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -404,8 +404,6 @@
{
// force writeLock on next read
cache.withFlags(Flag.FORCE_WRITE_LOCK);
-
- setCacheLocalMode();
Object existingObject = cache.get(key);
// if found value is really set! add to it.
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/ISPNCacheWorkspaceStorageCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/ISPNCacheWorkspaceStorageCache.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/ISPNCacheWorkspaceStorageCache.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -28,6 +28,7 @@
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener;
import org.exoplatform.services.jcr.datamodel.IllegalPathException;
import org.exoplatform.services.jcr.datamodel.InternalQName;
import org.exoplatform.services.jcr.datamodel.ItemData;
@@ -53,6 +54,9 @@
import org.exoplatform.services.transaction.ActionNonTxAware;
import org.infinispan.Cache;
import org.infinispan.lifecycle.ComponentStatus;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
+import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
import java.io.File;
import java.io.IOException;
@@ -66,6 +70,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -99,6 +104,11 @@
private final boolean enabled;
protected final BufferedISPNCache cache;
+
+ /**
+ * The list of all the listeners
+ */
+ private final List<WorkspaceStorageCacheListener> listeners = new CopyOnWriteArrayList<WorkspaceStorageCacheListener>();
private final CacheActionNonTxAware<Void, Void> commitTransaction = new CacheActionNonTxAware<Void, Void>()
{
@@ -462,6 +472,7 @@
// do n't nothing
}
this.cache = new BufferedISPNCache(parentCache, allowLocalChanges);
+ cache.addListener(new CacheEventListener());
}
/**
@@ -1560,6 +1571,45 @@
}
/**
+ * {@inheritDoc}
+ */
+ public void addListener(WorkspaceStorageCacheListener listener)
+ {
+ listeners.add(listener);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeListener(WorkspaceStorageCacheListener listener)
+ {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Called when a cache entry corresponding to the given node has item updated
+ * @param data the item corresponding to the updated cache entry
+ */
+ private void onCacheEntryUpdated(ItemData data)
+ {
+ if (data == null || data instanceof NullItemData)
+ {
+ return;
+ }
+ for (WorkspaceStorageCacheListener listener : listeners)
+ {
+ try
+ {
+ listener.onCacheEntryUpdated(data);
+ }
+ catch (Exception e)
+ {
+ LOG.warn("The method onCacheEntryUpdated fails for the listener " + listener.getClass(), e);
+ }
+ }
+ }
+
+ /**
* Actions that are not supposed to be called within a transaction
*
* Created by The eXo Platform SAS
@@ -1577,4 +1627,20 @@
return ISPNCacheWorkspaceStorageCache.this.getTransactionManager();
}
}
+
+ @SuppressWarnings("rawtypes")
+ @Listener
+ public class CacheEventListener
+ {
+
+ @CacheEntryModified
+ public void cacheEntryModified(CacheEntryModifiedEvent evt)
+ {
+ if (!evt.isPre() && evt.getKey() instanceof CacheId)
+ {
+ final ItemData value = (ItemData)evt.getValue();
+ onCacheEntryUpdated(value);
+ }
+ }
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -546,11 +546,30 @@
{
CompressedChangesBuffer changesContainer = getChangesBufferSafe();
changesContainer.add(new PutKeyValueContainer(fqn, key, value, parentCache, changesContainer.getHistoryIndex(),
- local.get(), useExpiration, expirationTimeOut));
+ local.get(), useExpiration, expirationTimeOut, false));
return parentCache.get(fqn, key);
}
+
+ protected Object putWithNotification(Fqn fqn, Serializable key, Object value)
+ {
+ CompressedChangesBuffer changesContainer = getChangesBufferSafe();
+ changesContainer.add(new PutKeyValueContainer(fqn, key, value, parentCache, changesContainer.getHistoryIndex(),
+ local.get(), useExpiration, expirationTimeOut, true));
+ return parentCache.get(fqn, key);
+ }
+
+ protected Object putWithNotification(Fqn fqn, Serializable key, Object value, boolean putIfAbsent)
+ {
+ if (putIfAbsent)
+ {
+ putIfAbsent(fqn, key, value, true);
+ return null;
+ }
+ return putWithNotification(fqn, key, value);
+ }
+
/**
* in case putIfAbsent is set to <code>true</code> this method will
* call cache.putIfAbsent(Fqn fqn, Serializable key, Object value)
@@ -571,13 +590,18 @@
*/
protected Object putIfAbsent(Fqn fqn, Serializable key, Object value)
{
+ return putIfAbsent(fqn, key, value, false);
+ }
+
+ protected Object putIfAbsent(Fqn fqn, Serializable key, Object value, boolean eventNotification)
+ {
CompressedChangesBuffer changesContainer = getChangesBufferSafe();
changesContainer.add(new PutIfAbsentKeyValueContainer(fqn, key, value, parentCache, changesContainer.getHistoryIndex(),
- local.get(), useExpiration, expirationTimeOut));
+ local.get(), useExpiration, expirationTimeOut, eventNotification));
return null;
}
- public Object putInBuffer(Fqn fqn, Serializable key, Object value)
+ public Object putInBuffer(Fqn fqn, Serializable key, Object value, boolean eventNotification)
{
CompressedChangesBuffer changesContainer = getChangesBufferSafe();
@@ -585,7 +609,7 @@
Object prevObject = getObjectFromChangesContainer(changesContainer, fqn, key);
changesContainer.add(new PutKeyValueContainer(fqn, key, value, parentCache, changesContainer.getHistoryIndex(),
- local.get(), useExpiration, expirationTimeOut));
+ local.get(), useExpiration, expirationTimeOut, eventNotification));
if (prevObject != null)
{
@@ -691,9 +715,17 @@
{
CompressedChangesBuffer changesContainer = getChangesBufferSafe();
changesContainer.add(new RemoveNodeContainer(fqn, parentCache, changesContainer.getHistoryIndex(), local.get(),
- useExpiration, expirationTimeOut));
+ useExpiration, expirationTimeOut, false));
return true;
}
+
+ protected boolean removeNode(Fqn fqn, boolean eventNotification)
+ {
+ CompressedChangesBuffer changesContainer = getChangesBufferSafe();
+ changesContainer.add(new RemoveNodeContainer(fqn, parentCache, changesContainer.getHistoryIndex(), local.get(),
+ useExpiration, expirationTimeOut, eventNotification));
+ return true;
+ }
/* (non-Javadoc)
* @see org.jboss.cache.Cache#removeNode(java.lang.String)
@@ -829,9 +861,11 @@
protected final boolean useExpiration;
protected final long timeOut;
+
+ protected final boolean eventNotification;
public ChangesContainer(Fqn fqn, ChangesType changesType, Cache<Serializable, Object> cache, int historicalIndex,
- boolean localMode, boolean useExpiration, long timeOut)
+ boolean localMode, boolean useExpiration, long timeOut, boolean eventNotification)
{
super();
this.fqn = fqn;
@@ -841,6 +875,7 @@
this.localMode = localMode;
this.useExpiration = useExpiration;
this.timeOut = timeOut;
+ this.eventNotification = eventNotification;
}
/**
@@ -882,14 +917,16 @@
return result == 0 ? historicalIndex - o.getHistoricalIndex() : result;
}
- protected void setCacheLocalMode()
+ protected void setOptionOverrides()
{
cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(localMode);
+ cache.getInvocationContext().getOptionOverrides().setSuppressEventNotification(!eventNotification);
}
public final void putExpiration(Fqn efqn)
{
- setCacheLocalMode();
+ cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(localMode);
+ cache.getInvocationContext().getOptionOverrides().setSuppressEventNotification(true);
cache.put(efqn, ExpirationAlgorithmConfig.EXPIRATION_KEY, new Long(System.currentTimeMillis() + timeOut));
}
@@ -911,7 +948,7 @@
public PutObjectContainer(Fqn fqn, Map<? extends Serializable, ? extends Object> data,
Cache<Serializable, Object> cache, int historicalIndex, boolean local, boolean useExpiration, long timeOut)
{
- super(fqn, ChangesType.PUT, cache, historicalIndex, local, useExpiration, timeOut);
+ super(fqn, ChangesType.PUT, cache, historicalIndex, local, useExpiration, timeOut, false);
this.data = data;
}
@@ -919,13 +956,13 @@
@Override
public void apply()
{
- setCacheLocalMode();
- cache.put(fqn, data);
-
if (useExpiration)
{
putExpiration(fqn);
}
+
+ setOptionOverrides();
+ cache.put(fqn, data);
}
}
@@ -939,9 +976,9 @@
private final Object value;
public PutIfAbsentKeyValueContainer(Fqn fqn, Serializable key, Object value, Cache<Serializable, Object> cache,
- int historicalIndex, boolean local, boolean useExpiration, long timeOut)
+ int historicalIndex, boolean local, boolean useExpiration, long timeOut, boolean eventNotification)
{
- super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut);
+ super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut, eventNotification);
this.key = key;
this.value = value;
}
@@ -960,7 +997,7 @@
putExpiration(fqn);
}
- setCacheLocalMode();
+ setOptionOverrides();
cache.put(fqn, key, value);
}
@@ -981,9 +1018,9 @@
private final Object value;
public PutKeyValueContainer(Fqn fqn, Serializable key, Object value, Cache<Serializable, Object> cache,
- int historicalIndex, boolean local, boolean useExpiration, long timeOut)
+ int historicalIndex, boolean local, boolean useExpiration, long timeOut, boolean eventNotification)
{
- super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut);
+ super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut, eventNotification);
this.key = key;
this.value = value;
}
@@ -996,7 +1033,7 @@
putExpiration(fqn);
}
- setCacheLocalMode();
+ setOptionOverrides();
cache.put(fqn, key, value);
}
}
@@ -1016,7 +1053,7 @@
public AddToListContainer(Fqn fqn, Serializable key, Object value, Cache<Serializable, Object> cache,
boolean forceModify, int historicalIndex, boolean local, boolean useExpiration, long timeOut)
{
- super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut);
+ super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut, false);
this.key = key;
this.value = value;
this.forceModify = forceModify;
@@ -1045,7 +1082,7 @@
putExpiration(fqn);
}
- setCacheLocalMode();
+ setOptionOverrides();
cache.put(fqn, key, newSet);
}
else if (existingObject != null)
@@ -1057,6 +1094,7 @@
{
// to prevent consistency issue since we don't have the list in the local cache, we are in cluster env
// and we are in a non local mode, we clear the list in order to enforce other cluster nodes to reload it from the db
+ setOptionOverrides();
cache.put(fqn, key, null);
}
}
@@ -1082,7 +1120,7 @@
public AddToPatternListContainer(Fqn fqn, Serializable patternKey, Serializable listKey, ItemData value,
Cache<Serializable, Object> cache, int historicalIndex, boolean local, boolean useExpiration, long timeOut)
{
- super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut);
+ super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut, false);
this.patternKey = patternKey;
this.listKey = listKey;
this.value = value;
@@ -1095,12 +1133,12 @@
{
// to prevent consistency issue since we don't have the list in the local cache, we are in cluster env
// and we are in a non local mode, we remove all the patterns in order to enforce other cluster nodes to reload them from the db
+ setOptionOverrides();
cache.removeNode(fqn);
return;
}
// force writeLock on next read
cache.getInvocationContext().getOptionOverrides().setForceWriteLock(true);
-
Iterator<Object> patternNames = cache.getChildrenNames(fqn).iterator();
while (patternNames.hasNext())
{
@@ -1126,7 +1164,14 @@
continue;
}
Set<String> newSet = new HashSet<String>((Set<String>)setObject);
- newSet.add(value.getIdentifier());
+ newSet.add(value.getIdentifier());
+
+ if (useExpiration)
+ {
+ putExpiration(fqn);
+ }
+
+ setOptionOverrides();
cache.put(patternFqn, listKey, newSet);
}
}
@@ -1151,7 +1196,7 @@
public RemoveFromListContainer(Fqn fqn, Serializable key, Object value, Cache<Serializable, Object> cache,
int historicalIndex, boolean local, boolean useExpiration, long timeOut)
{
- super(fqn, ChangesType.REMOVE_KEY, cache, historicalIndex, local, useExpiration, timeOut);
+ super(fqn, ChangesType.REMOVE_KEY, cache, historicalIndex, local, useExpiration, timeOut, false);
this.key = key;
this.value = value;
}
@@ -1161,8 +1206,6 @@
{
// force writeLock on next read
cache.getInvocationContext().getOptionOverrides().setForceWriteLock(true);
- // object found by FQN and key;
- setCacheLocalMode();
Object existingObject = cache.get(getFqn(), key);
// if found value is really set! add to it.
if (existingObject instanceof Set)
@@ -1175,7 +1218,7 @@
putExpiration(fqn);
}
- setCacheLocalMode();
+ setOptionOverrides();
cache.put(fqn, key, newSet);
}
}
@@ -1201,7 +1244,7 @@
public RemoveFromPatternListContainer(Fqn fqn, Serializable patternKey, Serializable listKey, ItemData value,
Cache<Serializable, Object> cache, int historicalIndex, boolean local, boolean useExpiration, long timeOut)
{
- super(fqn, ChangesType.REMOVE_KEY, cache, historicalIndex, local, useExpiration, timeOut);
+ super(fqn, ChangesType.REMOVE_KEY, cache, historicalIndex, local, useExpiration, timeOut, false);
this.patternKey = patternKey;
this.listKey = listKey;
this.value = value;
@@ -1212,9 +1255,6 @@
{
// force writeLock on next read
cache.getInvocationContext().getOptionOverrides().setForceWriteLock(true);
- // object found by FQN and key;
- setCacheLocalMode();
-
Iterator<Object> patternNames = cache.getChildrenNames(fqn).iterator();
while (patternNames.hasNext())
{
@@ -1240,6 +1280,13 @@
}
Set<String> newSet = new HashSet<String>((Set<String>)setObject);
newSet.remove(value.getIdentifier());
+
+ if (useExpiration)
+ {
+ putExpiration(fqn);
+ }
+
+ setOptionOverrides();
cache.put(patternFqn, listKey, newSet);
}
}
@@ -1262,14 +1309,14 @@
public RemoveKeyContainer(Fqn fqn, Serializable key, Cache<Serializable, Object> cache, int historicalIndex,
boolean local, boolean useExpiration, long timeOut)
{
- super(fqn, ChangesType.REMOVE_KEY, cache, historicalIndex, local, useExpiration, timeOut);
+ super(fqn, ChangesType.REMOVE_KEY, cache, historicalIndex, local, useExpiration, timeOut, false);
this.key = key;
}
@Override
public void apply()
{
- setCacheLocalMode();
+ setOptionOverrides();
cache.remove(fqn, key);
}
@@ -1284,13 +1331,19 @@
public RemoveNodeContainer(Fqn fqn, Cache<Serializable, Object> cache, int historicalIndex, boolean local,
boolean useExpiration, long timeOut)
{
- super(fqn, ChangesType.REMOVE, cache, historicalIndex, local, useExpiration, timeOut);
+ this(fqn, cache, historicalIndex, local, useExpiration, timeOut, false);
}
+ public RemoveNodeContainer(Fqn fqn, Cache<Serializable, Object> cache, int historicalIndex, boolean local,
+ boolean useExpiration, long timeOut, boolean eventNotification)
+ {
+ super(fqn, ChangesType.REMOVE, cache, historicalIndex, local, useExpiration, timeOut, eventNotification);
+ }
+
@Override
public void apply()
{
- setCacheLocalMode();
+ setOptionOverrides();
cache.removeNode(fqn);
}
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -29,6 +29,7 @@
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener;
import org.exoplatform.services.jcr.datamodel.IllegalPathException;
import org.exoplatform.services.jcr.datamodel.InternalQName;
import org.exoplatform.services.jcr.datamodel.ItemData;
@@ -62,6 +63,8 @@
import org.jboss.cache.config.EvictionRegionConfig;
import org.jboss.cache.eviction.ExpirationAlgorithmConfig;
import org.jboss.cache.jmx.JmxRegistrationManager;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
import org.picocontainer.Startable;
import java.io.File;
@@ -78,6 +81,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -186,7 +190,12 @@
protected final Fqn<String> childNodesByPatternList;
protected final Fqn<String> rootFqn;
-
+
+ /**
+ * The list of all the listeners
+ */
+ private final List<WorkspaceStorageCacheListener> listeners = new CopyOnWriteArrayList<WorkspaceStorageCacheListener>();
+
private final CacheActionNonTxAware<Void, Void> commitTransaction = new CacheActionNonTxAware<Void, Void>()
{
@Override
@@ -680,7 +689,8 @@
createResidentNode(childPropsByPatternList);
createResidentNode(childNodesByPatternList);
createResidentNode(itemsRoot);
-
+ this.cache.addCacheListener(new CacheEventListener());
+
if (jmxManager != null)
{
SecurityHelper.doPrivilegedAction(new PrivilegedAction<Void>()
@@ -733,6 +743,7 @@
if (!cacheRoot.hasChild(fqn))
{
cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
+ cache.getInvocationContext().getOptionOverrides().setSuppressEventNotification(true);
cacheRoot.addChild(fqn).setResident(true);
}
else
@@ -1501,8 +1512,8 @@
}
// add in ITEMS
- return (ItemData) cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node,
- modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
+ return (ItemData)cache.putWithNotification(makeItemFqn(node.getIdentifier()), ITEM_DATA, node,
+ modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
}
/**
@@ -1570,7 +1581,8 @@
}
// add in ITEMS
// NullNodeData must never be returned inside internal cache operations.
- ItemData returnedData = (ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ ItemData returnedData =
+ (ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA, node, modifyListsOfChild != ModifyChildOption.NOT_MODIFY);
return (returnedData instanceof NullItemData) ? null : returnedData;
}
@@ -1623,8 +1635,8 @@
// add in ITEMS
// NullItemData must never be returned inside internal cache operations.
ItemData returnedData =
- (ItemData) cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop,
- modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
+ (ItemData)cache.putWithNotification(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop,
+ modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
return (returnedData instanceof NullItemData) ? null : (PropertyData) returnedData;
}
@@ -1690,7 +1702,7 @@
}
// remove from ITEMS
- cache.removeNode(makeItemFqn(item.getIdentifier()));
+ cache.removeNode(makeItemFqn(item.getIdentifier()), true);
}
/**
@@ -1700,7 +1712,7 @@
*/
protected void updateMixin(NodeData node)
{
- NodeData prevData = (NodeData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ NodeData prevData = (NodeData)cache.putWithNotification(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
// prevent update NullNodeData
if (prevData != null && !(prevData instanceof NullItemData))
{
@@ -1832,7 +1844,7 @@
.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode
.getParentIdentifier(), inheritACL ? acl : prevNode.getACL()); // TODO check ACL
// update this node
- cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
+ cache.putWithNotification(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
}
else
{
@@ -1850,7 +1862,7 @@
TransientPropertyData newProp =
new TransientPropertyData(newPath, prevProp.getIdentifier(), prevProp.getPersistedVersion(), prevProp
.getType(), prevProp.getParentIdentifier(), prevProp.isMultiValued(), prevProp.getValues());
- cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp);
+ cache.putWithNotification(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp);
}
}
}
@@ -1885,7 +1897,7 @@
TransientPropertyData newProp =
new TransientPropertyData(newPath, prevProp.getIdentifier(), prevProp.getPersistedVersion(), prevProp
.getType(), prevProp.getParentIdentifier(), prevProp.isMultiValued(), prevProp.getValues());
- cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp);
+ cache.putWithNotification(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp);
}
// update child nodes
@@ -1901,7 +1913,7 @@
.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode
.getParentIdentifier(), inheritACL ? acl : prevNode.getACL()); // TODO check ACL
// update this node
- cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
+ cache.putWithNotification(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
// update childs recursive
updateTreePath(newNode.getIdentifier(), newNode.getQPath(), inheritACL ? acl : null);
}
@@ -1932,7 +1944,7 @@
prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode
.getParentIdentifier(), acl);
// update this node
- cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
+ cache.putWithNotification(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
// update childs recursive
updateChildsACL(newNode.getIdentifier(), acl);
}
@@ -2079,8 +2091,46 @@
createResidentNode(itemsRoot);
}
}
+ /**
+ * {@inheritDoc}
+ */
+ public void addListener(WorkspaceStorageCacheListener listener)
+ {
+ listeners.add(listener);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeListener(WorkspaceStorageCacheListener listener)
+ {
+ listeners.remove(listener);
+ }
/**
+ * Called when a cache entry corresponding to the given node has item updated
+ * @param data the item corresponding to the updated cache entry
+ */
+ private void onCacheEntryUpdated(ItemData data)
+ {
+ if (data == null || data instanceof NullItemData)
+ {
+ return;
+ }
+ for (WorkspaceStorageCacheListener listener : listeners)
+ {
+ try
+ {
+ listener.onCacheEntryUpdated(data);
+ }
+ catch (Exception e)
+ {
+ LOG.warn("The method onCacheEntryUpdated fails for the listener " + listener.getClass(), e);
+ }
+ }
+ }
+
+ /**
* Actions that are not supposed to be called within a transaction
*
* Created by The eXo Platform SAS
@@ -2098,4 +2148,20 @@
return JBossCacheWorkspaceStorageCache.this.getTransactionManager();
}
}
+
+ @org.jboss.cache.notifications.annotation.CacheListener
+ @SuppressWarnings("unchecked")
+ public class CacheEventListener
+ {
+
+ @NodeModified
+ public void nodeModified(NodeModifiedEvent ne)
+ {
+ if (!ne.isPre() && ne.getFqn().isChildOf(itemsRoot))
+ {
+ final Map<Serializable, Object> data = ne.getData();
+ onCacheEntryUpdated((ItemData)(data == null ? null : data.get(ITEM_DATA)));
+ }
+ }
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/inmemory/InmemoryStorageConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/inmemory/InmemoryStorageConnection.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/inmemory/InmemoryStorageConnection.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -26,6 +26,7 @@
import org.exoplatform.services.jcr.datamodel.QPathEntry;
import org.exoplatform.services.jcr.datamodel.ValueData;
import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.ACLHolder;
import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
@@ -289,6 +290,15 @@
throw new UnsupportedOperationException();
}
+
+ /**
+ * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getACLHolders()
+ */
+ public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException,
+ UnsupportedOperationException
+ {
+ throw new UnsupportedOperationException();
+ }
class MapKey
{
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCStorageConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCStorageConnection.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCStorageConnection.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -37,6 +37,7 @@
import org.exoplatform.services.jcr.datamodel.ValueData;
import org.exoplatform.services.jcr.impl.Constants;
import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.ACLHolder;
import org.exoplatform.services.jcr.impl.dataflow.persistent.ByteArrayPersistedValueData;
import org.exoplatform.services.jcr.impl.dataflow.persistent.CleanableFilePersistedValueData;
import org.exoplatform.services.jcr.impl.dataflow.persistent.StreamPersistedValueData;
@@ -1222,6 +1223,15 @@
throw new RepositoryException(e);
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException,
+ UnsupportedOperationException
+ {
+ throw new UnsupportedOperationException("This method is not supported by the old JDBCWorkspaceDataContainer, use CQJDBCWorkspaceDataContainer instead.");
+ }
/**
* {@inheritDoc}
@@ -1494,7 +1504,7 @@
}
QPathEntry qpe =
- new QPathEntry(InternalQName.parse(parent.getString(COLUMN_NAME)), parent.getInt(COLUMN_INDEX));
+ new QPathEntry(InternalQName.parse(parent.getString(COLUMN_NAME)), parent.getInt(COLUMN_INDEX), caid);
qrpath.add(qpe);
caid = parent.getString(COLUMN_PARENTID);
}
@@ -2207,7 +2217,7 @@
if (parentPath != null)
{
// get by parent and name
- qpath = QPath.makeChildPath(parentPath, qname, cindex);
+ qpath = QPath.makeChildPath(parentPath, qname, cindex, cid);
parentCid = cpid;
}
else
@@ -2221,7 +2231,7 @@
}
else
{
- qpath = QPath.makeChildPath(traverseQPath(cpid), qname, cindex);
+ qpath = QPath.makeChildPath(traverseQPath(cpid), qname, cindex, cid);
parentCid = cpid;
}
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/CQJDBCStorageConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/CQJDBCStorageConnection.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/CQJDBCStorageConnection.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -20,6 +20,7 @@
import org.exoplatform.services.jcr.access.AccessControlEntry;
import org.exoplatform.services.jcr.access.AccessControlList;
+import org.exoplatform.services.jcr.core.ExtendedPropertyType;
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData;
@@ -33,6 +34,7 @@
import org.exoplatform.services.jcr.datamodel.ValueData;
import org.exoplatform.services.jcr.impl.Constants;
import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.ACLHolder;
import org.exoplatform.services.jcr.impl.dataflow.persistent.StreamPersistedValueData;
import org.exoplatform.services.jcr.impl.storage.JCRInvalidItemStateException;
import org.exoplatform.services.jcr.impl.storage.jdbc.JDBCStorageConnection;
@@ -133,6 +135,13 @@
*/
protected String UPDATE_VALUE;
+ /**
+ * FIND_ACL_HOLDERS.
+ */
+ protected String FIND_ACL_HOLDERS;
+
+ protected PreparedStatement findACLHolders;
+
protected PreparedStatement findNodesByParentIdCQ;
protected PreparedStatement findPropertiesByParentIdCQ;
@@ -177,7 +186,64 @@
{
super(dbConnection, readOnly, containerName, valueStorageProvider, maxBufferSize, swapDirectory, swapCleaner);
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException,
+ UnsupportedOperationException
+ {
+ checkIfOpened();
+ ResultSet resultSet = null;
+ try
+ {
+ // query will return all the ACL holder
+ resultSet = findACLHolders();
+ Map<String, ACLHolder> mHolders = new HashMap<String, ACLHolder>();
+
+ while (resultSet.next())
+ {
+ String cpid = resultSet.getString(COLUMN_PARENTID);
+ ACLHolder holder = mHolders.get(cpid);
+ if (holder == null)
+ {
+ holder = new ACLHolder(cpid);
+ mHolders.put(cpid, holder);
+ }
+ int cptype = resultSet.getInt(COLUMN_PTYPE);
+ if (cptype == ExtendedPropertyType.PERMISSION)
+ {
+ holder.setPermissions(true);
+ }
+ else
+ {
+ holder.setOwner(true);
+ }
+ }
+ return new ArrayList<ACLHolder>(mHolders.values());
+ }
+ catch (SQLException e)
+ {
+ throw new RepositoryException(e);
+ }
+ finally
+ {
+ if (resultSet != null)
+ {
+ try
+ {
+ resultSet.close();
+ }
+ catch (SQLException e)
+ {
+ LOG.error("Can't close the ResultSet: " + e);
+ }
+ }
+ }
+ }
+
/**
* {@inheritDoc}
*/
@@ -928,7 +994,7 @@
if (parentPath != null)
{
// get by parent and name
- qpath = QPath.makeChildPath(parentPath, qname, cindex);
+ qpath = QPath.makeChildPath(parentPath, qname, cindex, cid);
parentCid = cpid;
}
else
@@ -942,7 +1008,7 @@
}
else
{
- qpath = QPath.makeChildPath(traverseQPath(cpid), qname, cindex);
+ qpath = QPath.makeChildPath(traverseQPath(cpid), qname, cindex, cid);
parentCid = cpid;
}
}
@@ -1094,13 +1160,13 @@
}
QPathEntry qpe1 =
- new QPathEntry(InternalQName.parse(result.getString(COLUMN_NAME)), result.getInt(COLUMN_INDEX));
+ new QPathEntry(InternalQName.parse(result.getString(COLUMN_NAME)), result.getInt(COLUMN_INDEX), result.getString(COLUMN_ID));
boolean isChild = caid.equals(result.getString(COLUMN_ID));
caid = result.getString(COLUMN_PARENTID);
if (result.next())
{
QPathEntry qpe2 =
- new QPathEntry(InternalQName.parse(result.getString(COLUMN_NAME)), result.getInt(COLUMN_INDEX));
+ new QPathEntry(InternalQName.parse(result.getString(COLUMN_NAME)), result.getInt(COLUMN_INDEX), result.getString(COLUMN_ID));
if (isChild)
{
// The child is the first result then we have the parent
@@ -1166,6 +1232,11 @@
try
{
+ if (findACLHolders != null)
+ {
+ findACLHolders.close();
+ }
+
if (findNodesByParentIdCQ != null)
{
findNodesByParentIdCQ.close();
@@ -1222,6 +1293,8 @@
}
}
+ protected abstract ResultSet findACLHolders() throws SQLException;
+
protected abstract ResultSet findItemQPathByIdentifierCQ(String identifier) throws SQLException;
protected abstract ResultSet findChildNodesByParentIdentifierCQ(String parentIdentifier) throws SQLException;
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -217,6 +217,10 @@
+ " P.NAME='[http://www.exoplatform.com/jcr/exo/1.0]owner' or"
+ " P.NAME='[http://www.exoplatform.com/jcr/exo/1.0]permissions')"
+ " and V.PROPERTY_ID=P.ID order by I.N_ORDER_NUM, I.ID";
+
+ FIND_ACL_HOLDERS = "select I.PARENT_ID, I.P_TYPE" +
+ " from JCR_MITEM I" +
+ " where I.I_CLASS=2 and (I.NAME='[http://www.exoplatform.com/jcr/exo/1.0]owner' or I.NAME='[http://www.exoplatform.com/jcr/exo/1.0]permissions')";
}
/**
@@ -1009,4 +1013,18 @@
{
return PATTERN_ESCAPE_STRING;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ResultSet findACLHolders() throws SQLException
+ {
+ if (findACLHolders == null)
+ {
+ findACLHolders = dbConnection.prepareStatement(FIND_ACL_HOLDERS);
+ }
+
+ return findACLHolders.executeQuery();
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -222,6 +222,10 @@
+ " P.NAME='[http://www.exoplatform.com/jcr/exo/1.0]owner' or"
+ " P.NAME='[http://www.exoplatform.com/jcr/exo/1.0]permissions')"
+ " and V.PROPERTY_ID=P.ID order by I.N_ORDER_NUM, I.ID";
+
+ FIND_ACL_HOLDERS = "select I.PARENT_ID, I.P_TYPE" +
+ " from JCR_SITEM I" +
+ " where I.I_CLASS=2 and I.CONTAINER_NAME=? and (I.NAME='[http://www.exoplatform.com/jcr/exo/1.0]owner' or I.NAME='[http://www.exoplatform.com/jcr/exo/1.0]permissions')";
}
/**
@@ -922,4 +926,24 @@
{
return PATTERN_ESCAPE_STRING;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ResultSet findACLHolders() throws SQLException
+ {
+ if (findACLHolders == null)
+ {
+ findACLHolders = dbConnection.prepareStatement(FIND_ACL_HOLDERS);
+ }
+ else
+ {
+ findACLHolders.clearParameters();
+ }
+
+ findACLHolders.setString(1, containerName);
+
+ return findACLHolders.executeQuery();
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/statistics/StatisticsJDBCStorageConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/statistics/StatisticsJDBCStorageConnection.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/statistics/StatisticsJDBCStorageConnection.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -23,6 +23,7 @@
import org.exoplatform.services.jcr.datamodel.QPathEntry;
import org.exoplatform.services.jcr.datamodel.ValueData;
import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.ACLHolder;
import org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer;
import org.exoplatform.services.jcr.statistics.JCRStatisticsManager;
import org.exoplatform.services.jcr.statistics.Statistics;
@@ -142,6 +143,12 @@
* <code>getLastOrderNumber(NodeData parent)</code>
*/
private static final String GET_LAST_ORDER_NUMBER_DESCR = "getLastOrderNumber";
+
+ /**
+ * The description of the statistics corresponding to the method
+ * <code>getACLHolders()</code>
+ */
+ private static final String GET_ACL_HOLDERS = "getACLHolders";
/**
* The description of the statistics corresponding to the method
@@ -208,6 +215,7 @@
LIST_CHILD_PROPERTIES_DATA_DESCR));
ALL_STATISTICS.put(GET_REFERENCES_DATA_DESCR, new Statistics(GLOBAL_STATISTICS, GET_REFERENCES_DATA_DESCR));
ALL_STATISTICS.put(GET_VALUE_DESCR, new Statistics(GLOBAL_STATISTICS, GET_VALUE_DESCR));
+ ALL_STATISTICS.put(GET_ACL_HOLDERS, new Statistics(GLOBAL_STATISTICS, GET_ACL_HOLDERS));
// Write Methods
// Commit
ALL_STATISTICS.put(COMMIT_DESCR, new Statistics(GLOBAL_STATISTICS, COMMIT_DESCR));
@@ -669,4 +677,23 @@
s.end();
}
}
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException,
+ UnsupportedOperationException
+ {
+ Statistics s = ALL_STATISTICS.get(GET_ACL_HOLDERS);
+ try
+ {
+ s.begin();
+ return wcs.getACLHolders();
+ }
+ finally
+ {
+ s.end();
+ }
+ }
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/WorkspaceDataContainer.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/WorkspaceDataContainer.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/WorkspaceDataContainer.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -60,6 +60,10 @@
public final static String CHECK_SNS_NEW_CONNECTION = "check-sns-new-connection";
+ public final static String ACL_BF_FALSE_PROPBABILITY = "acl-bloomfilter-false-positive-probability";
+
+ public final static String ACL_BF_ELEMENTS_NUMBER = "acl-bloomfilter-elements-number";
+
/**
* [G.A] do we need it here or in WorkspaceDataManager better??
*
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/WorkspaceStorageConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/WorkspaceStorageConnection.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/WorkspaceStorageConnection.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -25,6 +25,7 @@
import org.exoplatform.services.jcr.datamodel.QPathEntry;
import org.exoplatform.services.jcr.datamodel.ValueData;
import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.ACLHolder;
import java.util.List;
@@ -421,4 +422,17 @@
* @return boolean, true if connection is open and ready, false - otherwise
*/
boolean isOpened();
+
+ /**
+ * Returns all the nodes that hold some ACL info like owner or permissions
+ *
+ * @return a list of all the ACL holders for this workspace
+ * @throws RepositoryException
+ * if some exception occured
+ * @throws IllegalStateException
+ * if connection is closed
+ * @throws UnsupportedOperationException
+ * if operation is not supported
+ */
+ List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException, UnsupportedOperationException;
}
Modified: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/BaseStandaloneTest.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/BaseStandaloneTest.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/BaseStandaloneTest.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -25,14 +25,23 @@
import org.exoplatform.services.jcr.core.CredentialsImpl;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.core.WorkspaceContainerFacade;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.ItemType;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.datamodel.ValueData;
import org.exoplatform.services.jcr.impl.core.ItemImpl;
import org.exoplatform.services.jcr.impl.core.NodeImpl;
import org.exoplatform.services.jcr.impl.core.RepositoryImpl;
import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.ACLHolder;
import org.exoplatform.services.jcr.impl.dataflow.serialization.ReaderSpoolFileHolder;
import org.exoplatform.services.jcr.impl.util.io.FileCleaner;
import org.exoplatform.services.jcr.impl.util.io.FileCleanerHolder;
import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
+import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
@@ -43,10 +52,12 @@
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
+import javax.jcr.InvalidItemStateException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
@@ -509,4 +520,259 @@
assertTrue(finded);
}
}
+
+ /**
+ * Test WorkspaceDataContainer.
+ * Does nothing, must be extended in tests.
+ *
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 18.08.2011 skarpenko $
+ */
+ public class TestWorkspaceDataContainer implements WorkspaceDataContainer
+ {
+ @Override
+ public String getInfo()
+ {
+ return null;
+ }
+
+ @Override
+ public String getName()
+ {
+ return null;
+ }
+
+ @Override
+ public String getUniqueName()
+ {
+ return null;
+ }
+
+ @Override
+ public String getStorageVersion()
+ {
+ return null;
+ }
+
+ @Override
+ public Calendar getCurrentTime()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isSame(WorkspaceDataContainer another)
+ {
+ return false;
+ }
+
+ @Override
+ public WorkspaceStorageConnection openConnection() throws RepositoryException
+ {
+ return null;
+ }
+
+ @Override
+ public WorkspaceStorageConnection openConnection(boolean readOnly) throws RepositoryException
+ {
+ return null;
+ }
+
+ @Override
+ public WorkspaceStorageConnection reuseConnection(WorkspaceStorageConnection original) throws RepositoryException
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isCheckSNSNewConnection()
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Test WorkspaceStorageConnection.
+ * Does nothing, must be extended in tests.
+ *
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 18.08.2011 skarpenko $
+ */
+ public class TestWorkspaceStorageConnection implements WorkspaceStorageConnection
+ {
+
+ @Override
+ public ItemData getItemData(NodeData parentData, QPathEntry name) throws RepositoryException,
+ IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public ItemData getItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException,
+ IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public ItemData getItemData(String identifier) throws RepositoryException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public List<NodeData> getChildNodesData(NodeData parent) throws RepositoryException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public List<NodeData> getChildNodesData(NodeData parent, List<QPathEntryFilter> pattern)
+ throws RepositoryException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public int getChildNodesCount(NodeData parent) throws RepositoryException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public int getLastOrderNumber(NodeData parent) throws RepositoryException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public List<PropertyData> getChildPropertiesData(NodeData parent) throws RepositoryException,
+ IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public List<PropertyData> getChildPropertiesData(NodeData parent, List<QPathEntryFilter> pattern)
+ throws RepositoryException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public List<PropertyData> listChildPropertiesData(NodeData parent) throws RepositoryException,
+ IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public List<PropertyData> getReferencesData(String nodeIdentifier) throws RepositoryException,
+ IllegalStateException, UnsupportedOperationException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void add(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void add(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void update(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void update(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void rename(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void delete(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void delete(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void commit() throws IllegalStateException, RepositoryException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void rollback() throws IllegalStateException, RepositoryException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public void close() throws IllegalStateException, RepositoryException
+ {
+ }
+
+ @Override
+ public boolean isOpened()
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ @Override
+ public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException,
+ UnsupportedOperationException
+ {
+ throw new UnsupportedOperationException("TestWorkspaceStorageConnection: operation is unsupported.");
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getValue(java.lang.String, int, int)
+ */
+ @Override
+ public ValueData getValue(String propertyId, int orderNumb, int persistedVersion) throws IllegalStateException,
+ RepositoryException
+ {
+ return null;
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getChildNodesDataByPage(org.exoplatform.services.jcr.datamodel.NodeData, int, int, java.util.List)
+ */
+ @Override
+ public boolean getChildNodesDataByPage(NodeData parent, int fromOrderNum, int limit, List<NodeData> childs)
+ throws RepositoryException
+ {
+ return false;
+ }
+
+ }
+
}
Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorksapceDataManagerBloomFilter.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorksapceDataManagerBloomFilter.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorksapceDataManagerBloomFilter.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent;
+
+import org.exoplatform.commons.utils.QName;
+import org.exoplatform.services.jcr.JcrImplBaseTest;
+import org.exoplatform.services.jcr.access.AccessControlEntry;
+import org.exoplatform.services.jcr.access.AccessControlList;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.core.WorkspaceContainerFacade;
+import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.QPath;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.impl.storage.SystemDataContainerHolder;
+import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 18.08.2011 skarpenko $
+ *
+ */
+public class TestCacheableWorksapceDataManagerBloomFilter extends JcrImplBaseTest
+{
+ private MyWorkspaceDataContainer dataContainer;
+
+ private CacheableWorkspaceDataManager mgr;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ dataContainer = new MyWorkspaceDataContainer();
+ WorkspaceStorageCache cache = new MyWorkspaceStorageCache();
+ WorkspaceContainerFacade wsc = repository.getWorkspaceContainer("ws");
+ WorkspaceEntry wconf = (WorkspaceEntry)wsc.getComponent(WorkspaceEntry.class);
+ mgr =
+ new CacheableWorkspaceDataManager(wconf, dataContainer, cache, new SystemDataContainerHolder(dataContainer));
+ }
+
+ protected void tearDown() throws Exception
+ {
+ dataContainer.clear();
+ dataContainer = null;
+ mgr.clear();
+ mgr = null;
+ super.tearDown();
+ }
+
+ public void testGetItemWithACL() throws Exception
+ {
+ QPath path;
+ dataContainer.add(new PersistedNodeData("2", path = new QPath(new QPathEntry[]{new QPathEntry("", "2", 1, "2")}),
+ "3", 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("1", path = QPath.makeChildPath(path, new QName("", "1"), 1, "1"), "2",
+ 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ mgr.reloadFilters();
+ mgr.getItemData("1");
+ assertEquals(1, dataContainer.getTotalCalls());
+ dataContainer.clear();
+ }
+
+ public void testGetItemWithoutACL() throws Exception
+ {
+ QPath path;
+ dataContainer.add(new PersistedNodeData("3", path = new QPath(new QPathEntry[]{new QPathEntry("", "3", 1, "3")}),
+ "4", 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("2", path = QPath.makeChildPath(path, new QName("", "2"), 1, "2"), "3",
+ 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("1", path = QPath.makeChildPath(path, new QName("", "1"), 1, "1"), "2",
+ 1, 1, null, null, null));
+ mgr.reloadFilters();
+ mgr.getItemData("1");
+ assertEquals(2, dataContainer.getTotalCalls());
+ dataContainer.clear();
+ }
+
+ public void testGetItemParentWithSingleOwner() throws Exception
+ {
+ QPath path;
+ dataContainer.add(new PersistedNodeData("4", path = new QPath(new QPathEntry[]{new QPathEntry("", "4", 1, "4")}),
+ "5", 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("3", path = QPath.makeChildPath(path, new QName("", "3"), 1, "3"), "4",
+ 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("2", path = QPath.makeChildPath(path, new QName("", "2"), 1, "2"), "3",
+ 1, 1, null, null, new AccessControlList("owner", null)));
+ dataContainer.add(new PersistedNodeData("1", path = QPath.makeChildPath(path, new QName("", "1"), 1, "1"), "2",
+ 1, 1, null, null, null));
+ mgr.reloadFilters();
+ mgr.getItemData("1");
+ assertEquals(3, dataContainer.getTotalCalls());
+ dataContainer.clear();
+ }
+
+ public void testGetItemParentWithSinglePermission() throws Exception
+ {
+ QPath path;
+ dataContainer.add(new PersistedNodeData("4", path = new QPath(new QPathEntry[]{new QPathEntry("", "4", 1, "4")}),
+ "5", 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("3", path = QPath.makeChildPath(path, new QName("", "3"), 1, "3"), "4",
+ 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("2", path = QPath.makeChildPath(path, new QName("", "2"), 1, "2"), "3",
+ 1, 1, null, null, new AccessControlList(null, new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("1", path = QPath.makeChildPath(path, new QName("", "1"), 1, "1"), "2",
+ 1, 1, null, null, null));
+ mgr.reloadFilters();
+ mgr.getItemData("1");
+ assertEquals(3, dataContainer.getTotalCalls());
+ dataContainer.clear();
+ }
+
+ public void testGetItemParentsWithCrossEmptyACL() throws Exception
+ {
+ QPath path;
+ dataContainer.add(new PersistedNodeData("4", path = new QPath(new QPathEntry[]{new QPathEntry("", "4", 1, "4")}),
+ "5", 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("3", path = QPath.makeChildPath(path, new QName("", "3"), 1, "3"), "4",
+ 1, 1, null, null, new AccessControlList(null, new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("2", path = QPath.makeChildPath(path, new QName("", "2"), 1, "2"), "3",
+ 1, 1, null, null, new AccessControlList("owner", null)));
+ dataContainer.add(new PersistedNodeData("1", path = QPath.makeChildPath(path, new QName("", "1"), 1, "1"), "2",
+ 1, 1, null, null, null));
+ mgr.reloadFilters();
+ mgr.getItemData("1");
+ assertEquals(3, dataContainer.getTotalCalls());
+ dataContainer.clear();
+ }
+
+ public void testGetItemParentsWithCrossEmptyACL2() throws Exception
+ {
+ QPath path;
+ dataContainer.add(new PersistedNodeData("4", path = new QPath(new QPathEntry[]{new QPathEntry("", "4", 1, "4")}),
+ "5", 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("3", path = QPath.makeChildPath(path, new QName("", "3"), 1, "3"), "4",
+ 1, 1, null, null, new AccessControlList("owner", null)));
+ dataContainer.add(new PersistedNodeData("2", path = QPath.makeChildPath(path, new QName("", "2"), 1, "2"), "3",
+ 1, 1, null, null, new AccessControlList(null, new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("1", path = QPath.makeChildPath(path, new QName("", "1"), 1, "1"), "2",
+ 1, 1, null, null, null));
+ mgr.reloadFilters();
+ mgr.getItemData("1");
+ assertEquals(3, dataContainer.getTotalCalls());
+ dataContainer.clear();
+ }
+
+ public void testGetItemParentsWithSameOwnerlessACL() throws Exception
+ {
+ QPath path;
+ dataContainer.add(new PersistedNodeData("4", path = new QPath(new QPathEntry[]{new QPathEntry("", "4", 1, "4")}),
+ "5", 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("3", path = QPath.makeChildPath(path, new QName("", "3"), 1, "3"), "4",
+ 1, 1, null, null, new AccessControlList("owner", null)));
+ dataContainer.add(new PersistedNodeData("2", path = QPath.makeChildPath(path, new QName("", "2"), 1, "2"), "3",
+ 1, 1, null, null, new AccessControlList(null, new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("1", path = QPath.makeChildPath(path, new QName("", "1"), 1, "1"), "2",
+ 1, 1, null, null, new AccessControlList(null, new ArrayList<AccessControlEntry>())));
+ mgr.reloadFilters();
+ mgr.getItemData("1");
+ assertEquals(2, dataContainer.getTotalCalls());
+ dataContainer.clear();
+ }
+
+ public void testGetItemParentsWithSamePermissionlessACL() throws Exception
+ {
+ QPath path;
+ dataContainer.add(new PersistedNodeData("4", path = new QPath(new QPathEntry[]{new QPathEntry("", "4", 1, "4")}),
+ "5", 1, 1, null, null, new AccessControlList("owner", new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("3", path = QPath.makeChildPath(path, new QName("", "3"), 1, "3"), "4",
+ 1, 1, null, null, new AccessControlList(null, new ArrayList<AccessControlEntry>())));
+ dataContainer.add(new PersistedNodeData("2", path = QPath.makeChildPath(path, new QName("", "2"), 1, "2"), "3",
+ 1, 1, null, null, new AccessControlList("owner", null)));
+ dataContainer.add(new PersistedNodeData("1", path = QPath.makeChildPath(path, new QName("", "1"), 1, "1"), "2",
+ 1, 1, null, null, new AccessControlList("owner", null)));
+ mgr.reloadFilters();
+ mgr.getItemData("1");
+ assertEquals(2, dataContainer.getTotalCalls());
+ dataContainer.clear();
+ }
+
+ class MyWorkspaceDataContainer extends TestWorkspaceDataContainer
+ {
+
+ protected Map<String, NodeData> nodesById = new HashMap<String, NodeData>();
+
+ protected List<ACLHolder> holders = new ArrayList<ACLHolder>();
+
+ private int totalCalls;
+
+ protected synchronized void incrementCalls()
+ {
+ totalCalls++;
+ }
+
+ public WorkspaceStorageConnection openConnection() throws RepositoryException
+ {
+ return new MyWorkspaceStorageConnection(this);
+ }
+
+ public WorkspaceStorageConnection openConnection(boolean readOnly) throws RepositoryException
+ {
+ return openConnection();
+ }
+
+ public void clear()
+ {
+ nodesById.clear();
+ holders.clear();
+ totalCalls = 0;
+ }
+
+ public void add(NodeData node)
+ {
+ nodesById.put(node.getIdentifier(), node);
+ AccessControlList acl = node.getACL();
+ if (acl != null)
+ {
+ ACLHolder holder = new ACLHolder(node.getIdentifier());
+ holder.setOwner(acl.hasOwner());
+ holder.setPermissions(acl.hasPermissions());
+ holders.add(holder);
+ }
+ }
+
+ /**
+ * @return the totalCalls
+ */
+ public int getTotalCalls()
+ {
+ return totalCalls;
+ }
+
+ }
+
+ class MyWorkspaceStorageConnection extends TestWorkspaceStorageConnection
+ {
+ private final MyWorkspaceDataContainer container;
+
+ public MyWorkspaceStorageConnection(MyWorkspaceDataContainer myWorkspaceDataContainer)
+ {
+ container = myWorkspaceDataContainer;
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.impl.dataflow.persistent.CacheableWorkspaceDataManager#getItemData(java.lang.String)
+ */
+ @Override
+ public ItemData getItemData(String identifier) throws RepositoryException
+ {
+ container.incrementCalls();
+ return container.nodesById.get(identifier);
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.impl.dataflow.persistent.CacheableWorkspaceDataManager#getACLHolders()
+ */
+ @Override
+ public List<ACLHolder> getACLHolders() throws RepositoryException
+ {
+ return container.holders;
+ }
+ }
+
+ class MyWorkspaceStorageCache extends LinkedWorkspaceStorageCacheImpl
+ {
+ public MyWorkspaceStorageCache() throws RepositoryConfigurationException
+ {
+ super("", false, 0, 0, 0, 0, false, false, 0, false);
+ }
+
+ public boolean isEnabled()
+ {
+ return false;
+ }
+ }
+
+}
Modified: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -16,12 +16,14 @@
*/
package org.exoplatform.services.jcr.impl.dataflow.persistent;
-import junit.framework.TestCase;
-
+import org.exoplatform.services.jcr.JcrImplBaseTest;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.core.WorkspaceContainerFacade;
import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener;
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
@@ -52,7 +54,7 @@
* nicolas.filotto at exoplatform.com
* 29 mars 2010
*/
-public class TestCacheableWorkspaceDataManager extends TestCase
+public class TestCacheableWorkspaceDataManager extends JcrImplBaseTest
{
private static final int READER = 100;
@@ -66,13 +68,16 @@
private MyWorkspaceStorageConnection con;
@Override
- protected void setUp() throws Exception
+ public void setUp() throws Exception
{
super.setUp();
this.con = new MyWorkspaceStorageConnection();
this.wdc = new MyWorkspaceDataContainer(con);
+ WorkspaceContainerFacade wsc = repository.getWorkspaceContainer("ws");
+ WorkspaceEntry wconf = (WorkspaceEntry)wsc.getComponent(WorkspaceEntry.class);
this.cwdm =
- new CacheableWorkspaceDataManager(wdc, new MyWorkspaceStorageCache(), new SystemDataContainerHolder(wdc));
+ new CacheableWorkspaceDataManager(wconf, wdc, new MyWorkspaceStorageCache(),
+ new SystemDataContainerHolder(wdc));
}
@Override
@@ -439,6 +444,20 @@
{
}
+ /**
+ * @see org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache#addListener(org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener)
+ */
+ public void addListener(WorkspaceStorageCacheListener listener) throws UnsupportedOperationException
+ {
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache#removeListener(org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCacheListener)
+ */
+ public void removeListener(WorkspaceStorageCacheListener listener) throws UnsupportedOperationException
+ {
+ }
+
}
private static class MyWorkspaceStorageConnection implements WorkspaceStorageConnection
@@ -611,6 +630,15 @@
return false;
}
+ /**
+ * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getACLHolders()
+ */
+ public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException,
+ UnsupportedOperationException
+ {
+ return null;
+ }
+
};
private static class MyWorkspaceDataContainer extends WorkspaceDataContainerBase
Modified: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestWorkspaceStorageCacheInClusterMode.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestWorkspaceStorageCacheInClusterMode.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestWorkspaceStorageCacheInClusterMode.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -21,6 +21,8 @@
import org.exoplatform.commons.utils.QName;
import org.exoplatform.services.jcr.JcrImplBaseTest;
import org.exoplatform.services.jcr.access.AccessControlList;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.core.WorkspaceContainerFacade;
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
@@ -72,10 +74,12 @@
{
MyWorkspaceStorageConnection con = new MyWorkspaceStorageConnection();
WorkspaceDataContainer wdc = new MyWorkspaceDataContainer(con);
+ WorkspaceContainerFacade wsc = repository.getWorkspaceContainer("ws");
+ WorkspaceEntry wconf = (WorkspaceEntry)wsc.getComponent(WorkspaceEntry.class);
CacheableWorkspaceDataManager cwdmNode1 =
- new CacheableWorkspaceDataManager(wdc, cache1 = getCacheImpl(), new SystemDataContainerHolder(wdc));
+ new CacheableWorkspaceDataManager(wconf, wdc, cache1 = getCacheImpl(), new SystemDataContainerHolder(wdc));
CacheableWorkspaceDataManager cwdmNode2 =
- new CacheableWorkspaceDataManager(wdc, cache2 = getCacheImpl(), new SystemDataContainerHolder(wdc));
+ new CacheableWorkspaceDataManager(wconf, wdc, cache2 = getCacheImpl(), new SystemDataContainerHolder(wdc));
NodeData parentNode = new PersistedNodeData("parent-id", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node")), Constants.ROOT_UUID, 1, 0,
Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
// Test getChildNodesData
@@ -329,10 +333,12 @@
// testConsistency
con = new MyWorkspaceStorageConnection(true);
wdc = new MyWorkspaceDataContainer(con);
+ wsc = repository.getWorkspaceContainer("ws");
+ wconf = (WorkspaceEntry)wsc.getComponent(WorkspaceEntry.class);
cwdmNode1 =
- new CacheableWorkspaceDataManager(wdc, cache1, new SystemDataContainerHolder(wdc));
+ new CacheableWorkspaceDataManager(wconf, wdc, cache1, new SystemDataContainerHolder(wdc));
cwdmNode2 =
- new CacheableWorkspaceDataManager(wdc, cache2, new SystemDataContainerHolder(wdc));
+ new CacheableWorkspaceDataManager(wconf, wdc, cache2, new SystemDataContainerHolder(wdc));
parentNode = new PersistedNodeData("parent2-id", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent2-node")), Constants.ROOT_UUID, 1, 0,
Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
// Test getChildNodesData
@@ -962,6 +968,15 @@
return false;
}
+
+ /**
+ * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getACLHolders()
+ */
+ public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException,
+ UnsupportedOperationException
+ {
+ return null;
+ }
};
private static class MyWorkspaceDataContainer extends WorkspaceDataContainerBase
Modified: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCache.java 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCache.java 2011-09-02 10:32:08 UTC (rev 4832)
@@ -22,6 +22,7 @@
import org.exoplatform.services.jcr.config.CacheEntry;
import org.exoplatform.services.jcr.config.SimpleParameterEntry;
import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.core.WorkspaceContainerFacade;
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
@@ -35,6 +36,7 @@
import org.exoplatform.services.jcr.datamodel.ValueData;
import org.exoplatform.services.jcr.impl.Constants;
import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.ACLHolder;
import org.exoplatform.services.jcr.impl.dataflow.persistent.CacheableWorkspaceDataManager;
import org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspaceStorageCacheBaseCase;
import org.exoplatform.services.jcr.impl.storage.SystemDataContainerHolder;
@@ -83,8 +85,10 @@
{
MyWorkspaceStorageConnection con = new MyWorkspaceStorageConnection();
WorkspaceDataContainer wdc = new MyWorkspaceDataContainer(con);
+ WorkspaceContainerFacade wsc = repository.getWorkspaceContainer("ws");
+ WorkspaceEntry wconf = (WorkspaceEntry)wsc.getComponent(WorkspaceEntry.class);
final CacheableWorkspaceDataManager cwdm =
- new CacheableWorkspaceDataManager(wdc, getCacheImpl(), new SystemDataContainerHolder(wdc));
+ new CacheableWorkspaceDataManager(wconf, wdc, getCacheImpl(), new SystemDataContainerHolder(wdc));
String idNode = "foo1";
executeConcurrentReadNWrite(con, cwdm, Mode.READ_FIRST, idNode);
assertNotNull(cwdm.getItemData(idNode));
@@ -327,6 +331,17 @@
return false;
}
+
+ /**
+ * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getACLHolders()
+ */
+ @Override
+ public List<ACLHolder> getACLHolders() throws RepositoryException, IllegalStateException,
+ UnsupportedOperationException
+ {
+ return null;
+ }
+
};
private static class MyWorkspaceDataContainer extends WorkspaceDataContainerBase
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/configuration/exo-jcr-configuration.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/configuration/exo-jcr-configuration.xml 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/configuration/exo-jcr-configuration.xml 2011-09-02 10:32:08 UTC (rev 4832)
@@ -262,11 +262,7 @@
operation but in same time Observation'll not notified, has
default value true</entry>
</row>
- </tbody>
- </tgroup>
- <tgroup cols="2">
- <tbody>
<row>
<entry>lazy-node-iterator-page-size</entry>
@@ -274,6 +270,20 @@
can be retrieved from storage per request. The default value is
100</entry>
</row>
+
+ <row>
+ <entry>acl-bloomfilter-false-positive-probability</entry>
+
+ <entry>ACL Bloom-filter desired false positive probability. Range
+ [0..1]. Default value 0.1d.</entry>
+ </row>
+
+ <row>
+ <entry>acl-bloomfilter-elements-number</entry>
+
+ <entry>Expected number of ACL-elements in the Bloom-filter.
+ Default value 1000000.</entry>
+ </row>
</tbody>
</tgroup>
</table>
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/configuration/workspace-persistence-storage.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/configuration/workspace-persistence-storage.xml 2011-09-02 09:58:10 UTC (rev 4831)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/configuration/workspace-persistence-storage.xml 2011-09-02 10:32:08 UTC (rev 4832)
@@ -24,6 +24,8 @@
<property name="max-buffer-size" value="200K"/>
<property name="swap-directory" value="target/temp/swap/ws"/>
<property name="lazy-node-iterator-page-size" value="50"/>
+ <property name="acl-bloomfilter-false-positive-probability" value="0.1d"/>
+ <property name="acl-bloomfilter-elements-number" value="1000000"/>
</properties></programlisting>
<para>Properties are Container specific parameters:</para>
@@ -51,6 +53,26 @@
child nodes iterator settings. Defines size of page, the number of nodes
that are retrieved from persistent storage at once.</para>
+ <para><emphasis
+ role="bold">acl-bloomfilter-false-positive-probability</emphasis>: ACL
+ Bloom-filter settings. ACL Bloom-filter desired false positive probability.
+ Range [0..1]. Default value 0.1d.</para>
+
+ <para><emphasis role="bold">acl-bloomfilter-elements-number</emphasis>: ACL
+ Bloom-filter settings. Expected number of ACL-elements in the Bloom-filter.
+ Default value 1000000.</para>
+
+ <note>
+ <para>Bloom-filter used to avoid read nodes that definitely do not have
+ ACL. <emphasis
+ role="bold">acl-bloomfilter-false-positive-probability</emphasis> and
+ <emphasis role="bold">acl-bloomfilter-elements-number</emphasis> used to
+ configure such filters.</para>
+
+ <para>More about Bloom filters you can read here <ulink
+ url="http://en.wikipedia.org/wiki/Bloom_filter">http://en.wikipedia.org/wiki/Bloom_filter</ulink>.</para>
+ </note>
+
<para>eXo JCR has an RDB (JDBC) based, production ready <emphasis
role="bold">Workspace Data Container</emphasis>.</para>
More information about the exo-jcr-commits
mailing list