You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2009/11/25 15:04:50 UTC

svn commit: r884108 [3/10] - in /jackrabbit/sandbox/JCR-1456: ./ jackrabbit-api/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/ jackrabbit-core/ jackrabbit-core/src...

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java Wed Nov 25 14:04:38 2009
@@ -16,16 +16,17 @@
  */
 package org.apache.jackrabbit.core.query.lucene;
 
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.Sort;
-import org.apache.lucene.index.IndexReader;
-import org.apache.jackrabbit.core.query.lucene.constraint.EvaluationContext;
+import java.io.IOException;
+
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.query.lucene.constraint.EvaluationContext;
 import org.apache.jackrabbit.core.state.ItemStateManager;
 import org.apache.jackrabbit.spi.Name;
-
-import java.io.IOException;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Sort;
 
 /**
  * <code>JackrabbitIndexSearcher</code> implements an index searcher with
@@ -112,6 +113,19 @@
         return hits;
     }
 
+    //---------------------------< IndexSearcher >------------------------------
+
+    @Override
+    public int docFreq(Term term) throws IOException {
+        // provide a fixed document frequency for fields that are not fulltext
+        // indexed. correct frequency is only useful for fulltext queries.
+        if (FieldNames.isFulltextField(term.field())) {
+            return super.docFreq(term);
+        } else {
+            return 1;
+        }
+    }
+
     //------------------------< EvaluationContext >-----------------------------
 
     /**

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitParser.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitParser.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitParser.java Wed Nov 25 14:04:38 2009
@@ -26,11 +26,12 @@
 import org.apache.tika.exception.TikaException;
 import org.apache.tika.metadata.Metadata;
 import org.apache.tika.parser.AutoDetectParser;
+import org.apache.tika.parser.ParseContext;
 import org.apache.tika.parser.Parser;
 import org.apache.tika.parser.html.HtmlParser;
 import org.apache.tika.parser.image.ImageParser;
 import org.apache.tika.parser.microsoft.OfficeParser;
-import org.apache.tika.parser.opendocument.OpenOfficeParser;
+import org.apache.tika.parser.odf.OpenDocumentParser;
 import org.apache.tika.parser.pdf.PDFParser;
 import org.apache.tika.parser.rtf.RTFParser;
 import org.apache.tika.parser.txt.TXTParser;
@@ -136,7 +137,7 @@
                 parsers.put("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", parser);
             } else if (name.equals(
                     "org.apache.jackrabbit.extractor.OpenOfficeTextExtractor")) {
-                Parser parser = new OpenOfficeParser();
+                Parser parser = new OpenDocumentParser();
                 parsers.put("application/vnd.oasis.opendocument.database", parser);
                 parsers.put("application/vnd.oasis.opendocument.formula", parser);
                 parsers.put("application/vnd.oasis.opendocument.graphics", parser);
@@ -181,10 +182,17 @@
      * Delegates the call to the configured {@link AutoDetectParser}.
      */
     public void parse(
-            InputStream stream, ContentHandler handler, Metadata metadata)
+            InputStream stream, ContentHandler handler,
+            Metadata metadata, ParseContext context)
             throws IOException, SAXException, TikaException {
         waitIfBlocked();
-        parser.parse(stream, handler, metadata);
+        parser.parse(stream, handler, metadata, context);
+    }
+
+    public void parse(
+            InputStream stream, ContentHandler handler, Metadata metadata)
+            throws IOException, SAXException, TikaException {
+        parser.parse(stream, handler, metadata, new ParseContext());
     }
 
     /**

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java Wed Nov 25 14:04:38 2009
@@ -452,6 +452,17 @@
                     and.add(new NameQuery(nameTest, indexFormatVersion, nsMappings), Occur.MUST);
                     context = and;
                 }
+                // apply predicates
+                Object[] predicates = steps[0].acceptOperands(this, context);
+                BooleanQuery andQuery = new BooleanQuery();
+                for (Object predicate : predicates) {
+                    andQuery.add((Query) predicate, Occur.MUST);
+                }
+                if (andQuery.clauses().size() > 0) {
+                    andQuery.add(context, Occur.MUST);
+                    context = andQuery;
+                }
+
                 LocationStepQueryNode[] tmp = new LocationStepQueryNode[steps.length - 1];
                 System.arraycopy(steps, 1, tmp, 0, steps.length - 1);
                 steps = tmp;

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java Wed Nov 25 14:04:38 2009
@@ -57,7 +57,8 @@
             return null;
         }
         int doc = scorer.doc();
-        NodeId id = new NodeId(reader.document(doc).get(FieldNames.UUID));
+        NodeId id = new NodeId(reader.document(
+                doc, FieldSelectors.UUID).get(FieldNames.UUID));
         return new ScoreNode(id, scorer.score(), doc);
     }
 

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java Wed Nov 25 14:04:38 2009
@@ -16,40 +16,41 @@
  */
 package org.apache.jackrabbit.core.query.lucene;
 
+import java.io.IOException;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.ItemStateManager;
 import org.apache.jackrabbit.core.state.NoSuchItemStateException;
 import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.ChildNodeEntry;
-import org.apache.jackrabbit.util.Timer;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.PathFactory;
-import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
-import org.apache.jackrabbit.spi.commons.conversion.PathResolver;
 import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.spi.commons.conversion.PathResolver;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.apache.jackrabbit.util.Timer;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.store.Directory;
-
-import javax.jcr.RepositoryException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Arrays;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Calendar;
-import java.text.DateFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A <code>MultiIndex</code> consists of a {@link VolatileIndex} and multiple
@@ -255,7 +256,7 @@
         this.redoLog = redoLogFactory.createRedoLog(this);
 
         // initialize IndexMerger
-        merger = new IndexMerger(this, handler.getIndexMergerPoolSize());
+        merger = new IndexMerger(this, handler.getContext().getExecutor());
         merger.setMaxMergeDocs(handler.getMaxMergeDocs());
         merger.setMergeFactor(handler.getMergeFactor());
         merger.setMinMergeDocs(handler.getMinMergeDocs());

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java Wed Nov 25 14:04:38 2009
@@ -16,17 +16,17 @@
  */
 package org.apache.jackrabbit.core.query.lucene;
 
+import java.io.IOException;
+
+import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager;
 import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.IndexDeletionPolicy;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
-import org.apache.lucene.index.IndexDeletionPolicy;
+import org.apache.lucene.search.Similarity;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.IndexInput;
 import org.apache.lucene.store.IndexOutput;
-import org.apache.lucene.search.Similarity;
-import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager;
-
-import java.io.IOException;
 
 /**
  * Implements a lucene index which is based on a
@@ -79,7 +79,7 @@
         this.indexDelPolicy = new IndexDeletionPolicyImpl(this,
                 generationMaxAge * 1000);
         if (isExisting()) {
-            IndexMigration.migrate(this, directoryManager);
+            IndexMigration.migrate(this, directoryManager, '\uFFFF');
         }
     }
 

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java Wed Nov 25 14:04:38 2009
@@ -290,9 +290,11 @@
         MultiColumnQueryHits result = null;
         try {
             long time = System.currentTimeMillis();
+            long r1 = IOCounters.getReads();
             result = executeQuery(maxResultSize);
-            log.debug("query executed in {} ms",
-                    System.currentTimeMillis() - time);
+            long r2 = IOCounters.getReads();
+            log.debug("query executed in {} ms ({})",
+                    System.currentTimeMillis() - time, r2 - r1);
             // set selector names
             selectorNames = result.getSelectorNames();
 
@@ -306,8 +308,9 @@
 
             time = System.currentTimeMillis();
             collectScoreNodes(result, resultNodes, maxResultSize);
-            log.debug("retrieved ScoreNodes in {} ms",
-                    System.currentTimeMillis() - time);
+            long r3 = IOCounters.getReads();
+            log.debug("retrieved ScoreNodes in {} ms ({})",
+                    System.currentTimeMillis() - time, r3 - r2);
 
             // update numResults
             numResults = result.getSize();

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java Wed Nov 25 14:04:38 2009
@@ -16,32 +16,42 @@
  */
 package org.apache.jackrabbit.core.query.lucene;
 
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.Weight;
-import org.apache.lucene.search.Searcher;
-import org.apache.lucene.search.Scorer;
-import org.apache.lucene.search.Explanation;
-import org.apache.lucene.search.Similarity;
-import org.apache.lucene.search.ConstantScoreRangeQuery;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.TermEnum;
-import org.apache.lucene.index.TermDocs;
-
 import java.io.IOException;
-import java.util.BitSet;
-import java.util.Map;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.Similarity;
+import org.apache.lucene.search.Weight;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
- * Implements a lucene range query.
+ * Implements a variant of the lucene class {@link org.apache.lucene.search.RangeQuery}.
+ * This class does not rewrite to basic {@link org.apache.lucene.search.TermQuery}
+ * but will calculate the matching documents itself. That way a
+ * <code>TooManyClauses</code> can be avoided.
  */
 public class RangeQuery extends Query implements Transformable {
 
     /**
+     * Logger instance for this class.
+     */
+    private static final Logger log = LoggerFactory.getLogger(RangeQuery.class);
+
+    /**
      * The lower term. May be <code>null</code> if <code>upperTerm</code> is not
      * <code>null</code>.
      */
@@ -65,6 +75,12 @@
     private int transform = TRANSFORM_NONE;
 
     /**
+     * The rewritten range query or <code>null</code> if the range spans more
+     * than {@link org.apache.lucene.search.BooleanQuery#maxClauseCount} terms.
+     */
+    private Query stdRangeQuery;
+
+    /**
      * Creates a new RangeQuery. The lower or the upper term may be
      * <code>null</code>, but not both!
      *
@@ -113,8 +129,9 @@
     }
 
     /**
-     * Rewrites this query into a {@link ConstantScoreRangeQuery} if
-     * {@link #transform} is {@link #TRANSFORM_NONE}.
+     * Tries to rewrite this query into a standard lucene RangeQuery.
+     * This rewrite might fail with a TooManyClauses exception. If that
+     * happens, we use our own implementation.
      *
      * @param reader the index reader.
      * @return the rewritten query or this query if rewriting is not possible.
@@ -122,9 +139,16 @@
      */
     public Query rewrite(IndexReader reader) throws IOException {
         if (transform == TRANSFORM_NONE) {
-            return new ConstantScoreRangeQuery(lowerTerm.field(),
-                    lowerTerm.text(), upperTerm.text(), inclusive,
-                    inclusive).rewrite(reader);
+            Query stdRangeQueryImpl
+                    = new org.apache.lucene.search.RangeQuery(lowerTerm, upperTerm, inclusive);
+            try {
+                stdRangeQuery = stdRangeQueryImpl.rewrite(reader);
+                return stdRangeQuery;
+            } catch (BooleanQuery.TooManyClauses e) {
+                log.debug("Too many terms to enumerate, using custom RangeQuery");
+                // failed, use own implementation
+                return this;
+            }
         } else {
             // always use our implementation when we need to transform the
             // term enum
@@ -169,7 +193,9 @@
      * {@inheritDoc}
      */
     public void extractTerms(Set terms) {
-        // cannot extract terms
+        if (stdRangeQuery != null) {
+            stdRangeQuery.extractTerms(terms);
+        }
     }
 
     /**

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java Wed Nov 25 14:04:38 2009
@@ -170,11 +170,6 @@
     public static final int DEFAULT_TERM_INFOS_INDEX_DIVISOR = 1;
 
     /**
-     * The default value for {@link #indexMergerPoolSize}.
-     */
-    public static final int DEFAULT_INDEX_MERGER_POOL_SIZE = 2;
-
-    /**
      * The path factory.
      */
     protected static final PathFactory PATH_FACTORY = PathFactoryImpl.getInstance();
@@ -447,11 +442,6 @@
     private boolean initializeHierarchyCache = true;
 
     /**
-     * The number of worker threads for merging index segments.
-     */
-    private int indexMergerPoolSize = DEFAULT_INDEX_MERGER_POOL_SIZE;
-
-    /**
      * The name of the redo log factory class implementation.
      */
     private String redoLogFactoryClass = DefaultRedoLogFactory.class.getName();
@@ -1103,7 +1093,7 @@
         indexer.setIndexingConfiguration(indexingConfig);
         indexer.setIndexFormatVersion(indexFormatVersion);
         Document doc = indexer.createDoc();
-        mergeAggregatedNodeIndexes(node, doc);
+        mergeAggregatedNodeIndexes(node, doc, indexFormatVersion);
         return doc;
     }
 
@@ -1321,8 +1311,11 @@
      *
      * @param state the node state on which <code>doc</code> was created.
      * @param doc the lucene document with index fields from <code>state</code>.
+     * @param ifv the current index format version.
      */
-    protected void mergeAggregatedNodeIndexes(NodeState state, Document doc) {
+    protected void mergeAggregatedNodeIndexes(NodeState state,
+                                              Document doc,
+                                              IndexFormatVersion ifv) {
         if (indexingConfig != null) {
             AggregateRule[] aggregateRules = indexingConfig.getAggregateRules();
             if (aggregateRules == null) {
@@ -1337,7 +1330,7 @@
                     if (aggregates != null) {
                         ruleMatched = true;
                         for (NodeState aggregate : aggregates) {
-                            Document aDoc = createDocument(aggregate, getNamespaceMappings(), index.getIndexFormatVersion());
+                            Document aDoc = createDocument(aggregate, getNamespaceMappings(), ifv);
                             // transfer fields to doc if there are any
                             Fieldable[] fulltextFields = aDoc.getFieldables(FieldNames.FULLTEXT);
                             if (fulltextFields != null) {
@@ -1355,7 +1348,7 @@
                         for (PropertyState propState : propStates) {
                             String namePrefix = FieldNames.createNamedValue(getNamespaceMappings().translateName(propState.getName()), "");
                             NodeState parent = (NodeState) ism.getItemState(propState.getParentId());
-                            Document aDoc = createDocument(parent, getNamespaceMappings(), getIndex().getIndexFormatVersion());
+                            Document aDoc = createDocument(parent, getNamespaceMappings(), ifv);
                             try {
                                 // find the right fields to transfer
                                 Fieldable[] fields = aDoc.getFieldables(FieldNames.PROPERTIES);
@@ -2224,26 +2217,6 @@
     }
 
     /**
-     * @return the current size of the index merger pool.
-     */
-    public int getIndexMergerPoolSize() {
-        return indexMergerPoolSize;
-    }
-
-    /**
-     * Sets a new value for the index merger pool size.
-     *
-     * @param indexMergerPoolSize the number of worker threads.
-     * @throws IllegalArgumentException if the size is less than or equal 0.
-     */
-    public void setIndexMergerPoolSize(int indexMergerPoolSize) {
-        if (indexMergerPoolSize <= 0) {
-            throw new IllegalArgumentException("must be greater than 0");
-        }
-        this.indexMergerPoolSize = indexMergerPoolSize;
-    }
-
-    /**
      * @return the maximum age in seconds for outdated generations of
      * {@link IndexInfos}.
      */

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java Wed Nov 25 14:04:38 2009
@@ -16,18 +16,18 @@
  */
 package org.apache.jackrabbit.core.query.lucene;
 
-import org.apache.lucene.search.Sort;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.Query;
-import org.apache.lucene.search.TopFieldDocCollector;
 import org.apache.lucene.search.ScoreDoc;
-import org.apache.lucene.index.IndexReader;
-import org.apache.jackrabbit.core.id.NodeId;
-import org.slf4j.LoggerFactory;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.TopFieldDocCollector;
 import org.slf4j.Logger;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.ArrayList;
+import org.slf4j.LoggerFactory;
 
 /**
  * Wraps a lucene query result and adds a close method that allows to release
@@ -77,9 +77,9 @@
     private int hitIndex = -1;
 
     /**
-     * The score nodes.
+     * The score docs.
      */
-    private final List<ScoreNode> scoreNodes = new ArrayList<ScoreNode>();
+    private final List<ScoreDoc> scoreDocs = new ArrayList<ScoreDoc>();
 
     /**
      * The total number of hits.
@@ -130,12 +130,16 @@
         if (++hitIndex >= size) {
             // no more score nodes
             return null;
-        } else if (hitIndex >= scoreNodes.size()) {
+        } else if (hitIndex >= scoreDocs.size()) {
             // refill at least numHits or twice hitIndex
             this.numHits = Math.max(this.numHits, hitIndex * 2);
             getHits();
         }
-        return scoreNodes.get(hitIndex);
+        ScoreDoc doc = scoreDocs.get(hitIndex);
+        String uuid = reader.document(doc.doc,
+                FieldSelectors.UUID).get(FieldNames.UUID);
+        NodeId id = new NodeId(uuid);
+        return new ScoreNode(id, doc.score, doc.doc);
     }
 
     /**
@@ -155,12 +159,10 @@
         searcher.search(query, collector);
         this.size = collector.getTotalHits();
         ScoreDoc[] docs = collector.topDocs().scoreDocs;
-        for (int i = scoreNodes.size(); i < docs.length; i++) {
-            String uuid = reader.document(docs[i].doc).get(FieldNames.UUID);
-            NodeId id = new NodeId(uuid);
-            scoreNodes.add(new ScoreNode(id, docs[i].score, docs[i].doc));
+        for (int i = scoreDocs.size(); i < docs.length; i++) {
+            scoreDocs.add(docs[i]);
         }
-        log.debug("getHits() {}/{}", scoreNodes.size(), numHits);
+        log.debug("getHits() {}/{}", scoreDocs.size(), numHits);
         // double hits for next round
         numHits *= 2;
     }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/directory/FSDirectoryManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/directory/FSDirectoryManager.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/directory/FSDirectoryManager.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/directory/FSDirectoryManager.java Wed Nov 25 14:04:38 2009
@@ -16,18 +16,19 @@
  */
 package org.apache.jackrabbit.core.query.lucene.directory;
 
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+
+import org.apache.jackrabbit.core.query.lucene.IOCounters;
+import org.apache.jackrabbit.core.query.lucene.SearchIndex;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.FSDirectory;
-import org.apache.lucene.store.NativeFSLockFactory;
-import org.apache.lucene.store.IndexOutput;
 import org.apache.lucene.store.IndexInput;
+import org.apache.lucene.store.IndexOutput;
 import org.apache.lucene.store.Lock;
 import org.apache.lucene.store.LockFactory;
-import org.apache.jackrabbit.core.query.lucene.SearchIndex;
-
-import java.io.IOException;
-import java.io.File;
-import java.io.FileFilter;
+import org.apache.lucene.store.NativeFSLockFactory;
 
 /**
  * <code>FSDirectoryManager</code> implements a directory manager for
@@ -185,7 +186,8 @@
         }
 
         public IndexInput openInput(String name) throws IOException {
-            return directory.openInput(name);
+            IndexInput in = directory.openInput(name);
+            return new IndexInputLogWrapper(in);
         }
 
         public void close() throws IOException {
@@ -194,7 +196,8 @@
 
         public IndexInput openInput(String name, int bufferSize)
                 throws IOException {
-            return directory.openInput(name, bufferSize);
+            IndexInput in = directory.openInput(name, bufferSize);
+            return new IndexInputLogWrapper(in);
         }
 
         public Lock makeLock(String name) {
@@ -221,4 +224,49 @@
             return this.getClass().getName() + "@" + directory;
         }
     }
+
+    /**
+     * Implements an index input wrapper that logs the number of time bytes
+     * are read from storage.
+     */
+    private static final class IndexInputLogWrapper extends IndexInput {
+
+        private IndexInput in;
+
+        IndexInputLogWrapper(IndexInput in) {
+            this.in = in;
+        }
+
+        public byte readByte() throws IOException {
+            return in.readByte();
+        }
+
+        public void readBytes(byte[] b, int offset, int len) throws IOException {
+            IOCounters.incrRead();
+            in.readBytes(b, offset, len);
+        }
+
+        public void close() throws IOException {
+            in.close();
+        }
+
+        public long getFilePointer() {
+            return in.getFilePointer();
+        }
+
+        public void seek(long pos) throws IOException {
+            in.seek(pos);
+        }
+
+        public long length() {
+            return in.length();
+        }
+
+        @Override
+        public Object clone() {
+            IndexInputLogWrapper clone = (IndexInputLogWrapper) super.clone();
+            clone.in = (IndexInput) in.clone();
+            return clone;
+        }
+    }
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java Wed Nov 25 14:04:38 2009
@@ -82,13 +82,14 @@
 
         // start listening to added/changed or removed holds and retention policies.
         Workspace wsp = session.getWorkspace();
-        // register eventlistener to be informed about new/removed holds and retention plcs.
+        // register event listener to be informed about new/removed holds and
+        // retention policies.
         int types = Event.PROPERTY_ADDED | Event.PROPERTY_REMOVED | Event.PROPERTY_CHANGED;
         String[] ntFilter = new String[] {session.getJCRName(RetentionManagerImpl.REP_RETENTION_MANAGEABLE)};
         wsp.getObservationManager().addEventListener(this, types, "/", true, null, ntFilter, false);
 
         // populate the retentionMap and the holdMap with the effective
-        // holds and retention plcs present within the content.
+        // holds and retention policies present within the content.
         try {
             readRetentionFile();
         } catch (FileSystemException e) {
@@ -253,7 +254,7 @@
                 return true;
             } else if (checkParent && !nodePath.denotesRoot() &&
                     element.hasPath(nodePath.getAncestor(1))) {
-                // hold present on the parent node whithout checking for being
+                // hold present on the parent node without checking for being
                 // a deep hold.
                 // this required for removal of a node that can be inhibited
                 // by a hold on the node itself, by a hold on the parent or

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/JackrabbitSecurityManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/JackrabbitSecurityManager.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/JackrabbitSecurityManager.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/JackrabbitSecurityManager.java Wed Nov 25 14:04:38 2009
@@ -52,11 +52,12 @@
      *
      * @param creds
      * @param subject
+     * @param workspaceName The name of the workspace to login.
      * @return A new <code>AuthContext</code> for the given <code>creds</code>
      * and <code>subject</code>.
      * @throws RepositoryException
      */
-    AuthContext getAuthContext(Credentials creds, Subject subject) throws RepositoryException;
+    AuthContext getAuthContext(Credentials creds, Subject subject, String workspaceName) throws RepositoryException;
 
     /**
      * Retrieve the <code>AccessManager</code> for the given <code>session</code>.
@@ -95,8 +96,9 @@
      * the specified subject.
      *
      * @param subject
+     * @param workspaceName
      * @return userID to be displayed upon {@link Session#getUserID()}.
      * @throws RepositoryException
      */
-    String getUserID(Subject subject) throws RepositoryException;
+    String getUserID(Subject subject, String workspaceName) throws RepositoryException;
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/SimpleJBossAccessManager.java Wed Nov 25 14:04:38 2009
@@ -109,7 +109,7 @@
 
     public boolean isGranted(ItemId id, int permissions) throws RepositoryException {
         // system has always all permissions
-        // anonymous has only READ premissions
+        // anonymous has only READ permissions
         return system || (anonymous && ((permissions & (WRITE | REMOVE)) == 0));
     }
 
@@ -131,7 +131,7 @@
 
     private boolean internalIsGranted(int permissions) {
         /* system has always all permissions,
-           anonymous has only READ premissions */
+           anonymous has only READ permissions */
         return system || (anonymous && Permission.READ == permissions);
     }
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java Wed Nov 25 14:04:38 2009
@@ -86,7 +86,7 @@
      * credentials should be taken as is and the user requesting access
      * has already been authenticated outside of this LoginModule.
      *
-     * @see #getTrustedCredentialsAttributeName()
+     * @see #getPreAuthAttributeName()
      */
     private String preAuthAttributeName;
 
@@ -247,7 +247,7 @@
      * If the option is missing, the system default prinvipal provider will
      * be used.<p/>
      *
-     * <b>3) Verfication</b><br>
+     * <b>3) Verification</b><br>
      * There are four cases, how the User-ID can be verfied:
      * The login is anonymous, preauthenticated or the login is the result of
      * an impersonation request (see {@link javax.jcr.Session#impersonate(Credentials)}
@@ -410,8 +410,8 @@
      * @see javax.security.auth.spi.LoginModule#logout()
      */
     public boolean logout() throws LoginException {
-        Set thisPrincipals = subject.getPrincipals();
-        Set thisCredentials = subject.getPublicCredentials(SimpleCredentials.class);
+        Set<Principal> thisPrincipals = subject.getPrincipals();
+        Set<SimpleCredentials> thisCredentials = subject.getPublicCredentials(SimpleCredentials.class);
         if (thisPrincipals == null || thisCredentials == null
                 || thisPrincipals.isEmpty() || thisCredentials.isEmpty()) {
             return false;
@@ -758,7 +758,7 @@
      * <p>
      * This base class implementation returns <code>true</code> if the
      * <code>creds</code> object is a SimpleCredentials instance and the
-     * configured {@link #getTrustedCredentialsAttributeName() trusted
+     * configured {@link #getPreAuthAttributeName() trusted
      * credentials property} is set to a non-<code>null</code> value in the
      * credentials attributes.
      * <p>

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AuthContextProvider.java Wed Nov 25 14:04:38 2009
@@ -32,18 +32,11 @@
 import java.util.Properties;
 
 /**
- * A AuthContextProvider selects how the current request for login is handled.
- * It selects the mechanism and set-up according configuration.<br>
- * The handler selects if the JAAS-configuration
- * {@link javax.security.auth.login.Configuration} is taken or the fall-back as
- * configured via {@link org.apache.jackrabbit.core.config.RepositoryConfig}.<p>
- * This implementaion selects JAAS under the following condition:
- * <ul>
- * <li>a JAAS Login-{@link javax.security.auth.login.Configuration} is available
- * <li>the configuration contains the configured application name
- * </ul>
- * If the conditions are not met <b>AND</b> a LoginModule is configured in
- * {@link org.apache.jackrabbit.core.config.RepositoryConfig}, that one is taken.
+ * <code>AuthContextProvider</code> defines how the current request for login is
+ * handled. By default the {@link org.apache.jackrabbit.core.config.RepositoryConfig
+ * local repository configuration} takes precedence over JAAS configuration.
+ * If no local configuration is present a JAAS configuration must be provided
+ * otherwise {@link #getAuthContext} fails with <code>RepositoryException</code>.
  */
 public class AuthContextProvider {
 

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/CryptedSimpleCredentials.java Wed Nov 25 14:04:38 2009
@@ -113,9 +113,8 @@
     }
 
     /**
-     * Compair this instance with an instance of SimpleCredentials.
-     * If one the other Credentials' Password is plain-text treies to encode
-     * it with the current Digest.
+     * Compares this instance with the given <code>SimpleCredentials</code> and
+     * returns <code>true</code> if both match.
      *
      * @param credentials
      * @return true if {@link SimpleCredentials#getUserID() UserID} and
@@ -126,7 +125,7 @@
     public boolean matches(SimpleCredentials credentials)
             throws NoSuchAlgorithmException, UnsupportedEncodingException {
 
-        if (getUserID().matches(credentials.getUserID())) {
+        if (getUserID().equalsIgnoreCase(credentials.getUserID())) {
             String toMatch = new String(credentials.getPassword());
             String algr = getAlgorithm(toMatch);
 
@@ -148,7 +147,7 @@
     private static String crypt(String pwd, String algorithm)
             throws NoSuchAlgorithmException, UnsupportedEncodingException {
 
-        StringBuffer password = new StringBuffer();
+        StringBuilder password = new StringBuilder();
         password.append("{").append(algorithm).append("}");
         password.append(Text.digest(algorithm, pwd.getBytes("UTF-8")));
         return password.toString();

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AbstractACLTemplate.java Wed Nov 25 14:04:38 2009
@@ -19,14 +19,19 @@
 import java.security.Principal;
 import java.util.Collections;
 import java.util.Map;
+import java.util.List;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
+import javax.jcr.UnsupportedRepositoryOperationException;
 import javax.jcr.security.AccessControlException;
 import javax.jcr.security.Privilege;
+import javax.jcr.security.AccessControlEntry;
 
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * <code>AbstractACLTemplate</code>...
@@ -34,6 +39,8 @@
 public abstract class AbstractACLTemplate implements JackrabbitAccessControlList,
         AccessControlConstants {
 
+    private static Logger log = LoggerFactory.getLogger(AbstractACLTemplate.class);
+
     /**
      * Path of the node this ACL template has been created for.
      */
@@ -65,6 +72,17 @@
                                             boolean isAllow,
                                             Map<String, Value> restrictions) throws AccessControlException;
 
+    /**
+     * Return the list of entries, if they are held in a orderable list.
+     *
+     * @return the list of entries.
+     * @throws UnsupportedRepositoryOperationException If the implementation
+     * does not held the entries in a list.
+     * @throws RepositoryException
+     * @see #orderBefore(AccessControlEntry, AccessControlEntry)
+     */
+    protected abstract List<? extends AccessControlEntry> getEntries() throws UnsupportedRepositoryOperationException, RepositoryException;
+
     //--------------------------------------< JackrabbitAccessControlPolicy >---
     /**
      * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy#getPath()
@@ -82,6 +100,34 @@
         return addEntry(principal, privileges, isAllow, Collections.<String, Value>emptyMap());
     }
 
+    /**
+     *
+     * @param srcEntry The access control entry to be moved within the list.
+     * @param destEntry The entry before which the <code>srcEntry</code> will be moved.
+     * @throws AccessControlException
+     * @throws UnsupportedRepositoryOperationException
+     * @throws RepositoryException
+     */
+    public void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry) throws AccessControlException, UnsupportedRepositoryOperationException, RepositoryException {
+        if (srcEntry.equals(destEntry)) {
+            log.debug("srcEntry equals destEntry -> no reordering required.");
+            return;
+        }
+
+        List entries = getEntries();
+        int index = (destEntry == null) ? entries.size()-1 : entries.indexOf(destEntry);
+        if (index < 0) {
+            throw new AccessControlException("destEntry not contained in this AccessControlList");
+        } else {
+            if (entries.remove(srcEntry)) {
+                // re-insert the srcEntry at the new position.
+                entries.add(index, srcEntry);
+            } else {
+                // src entry not contained in this list.
+                throw new AccessControlException("srcEntry not contained in this AccessControlList");
+            }
+        }
+    }
 
     //--------------------------------------------------< AccessControlList >---
     /**

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/AccessControlProviderFactoryImpl.java Wed Nov 25 14:04:38 2009
@@ -74,7 +74,7 @@
         Map props;
         if (config != null && config.getAccessControlProviderConfig() != null) {
             BeanConfig bc = config.getAccessControlProviderConfig();
-            prov = (AccessControlProvider) bc.newInstance();
+            prov = bc.newInstance(AccessControlProvider.class);
             props = bc.getParameters();
         } else {
             log.debug("No ac-provider configuration for workspace " + workspaceName + " -> using defaults.");
@@ -87,7 +87,7 @@
                 prov = new ACLProvider();
             }
             log.debug("Default provider for workspace " + workspaceName + " = " + prov.getClass().getName());
-            props = Collections.EMPTY_MAP;
+            props = Collections.emptyMap();
         }
 
         prov.init(systemSession, props);

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/UnmodifiableAccessControlList.java Wed Nov 25 14:04:38 2009
@@ -130,12 +130,16 @@
         return accessControlEntries.length;
     }
 
-    public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow) throws AccessControlException, RepositoryException {
-        throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getApplicablePolicies in order to obtain an modifiable ACL.");
+    public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow) throws AccessControlException {
+        throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL.");
     }
 
-    public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow, Map<String, Value> restrictions) throws AccessControlException, RepositoryException {
-        throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getApplicablePolicies in order to obtain an modifiable ACL.");
+    public boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow, Map<String, Value> restrictions) throws AccessControlException {
+        throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicies in order to obtain an modifiable ACL.");
+    }
+
+    public void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry) throws AccessControlException {
+        throw new AccessControlException("Unmodifiable ACL. Use AccessControlManager#getPolicy or #getApplicablePolicy in order to obtain a modifiable ACL.");
     }
 
     public String getPath() {

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/WorkspaceAccessManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/WorkspaceAccessManager.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/WorkspaceAccessManager.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/WorkspaceAccessManager.java Wed Nov 25 14:04:38 2009
@@ -31,10 +31,10 @@
     /**
      * Initialize this <code>WorkspaceAccessManager</code>.
      *
-     * @param securitySession The security session.
+     * @param systemSession Session used to initialize this instance.
      * @throws RepositoryException if an error occurs.
      */
-    void init(Session securitySession) throws RepositoryException;
+    void init(Session systemSession) throws RepositoryException;
 
     /**
      * Dispose this <code>WorkspaceAccessManager</code> and its resources.

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLProvider.java Wed Nov 25 14:04:38 2009
@@ -17,14 +17,15 @@
 package org.apache.jackrabbit.core.security.authorization.acl;
 
 import java.security.Principal;
+import java.security.acl.Group;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Iterator;
 
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.NodeIterator;
@@ -33,8 +34,6 @@
 import javax.jcr.Value;
 import javax.jcr.observation.Event;
 import javax.jcr.observation.EventIterator;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
 import javax.jcr.security.AccessControlEntry;
 import javax.jcr.security.AccessControlList;
 import javax.jcr.security.AccessControlManager;
@@ -53,15 +52,14 @@
 import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions;
 import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
 import org.apache.jackrabbit.core.security.authorization.AccessControlEditor;
-import org.apache.jackrabbit.core.security.authorization.AccessControlEntryIterator;
 import org.apache.jackrabbit.core.security.authorization.CompiledPermissions;
 import org.apache.jackrabbit.core.security.authorization.Permission;
 import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
 import org.apache.jackrabbit.core.security.authorization.UnmodifiableAccessControlList;
-import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
 import org.apache.jackrabbit.util.Text;
+import org.apache.commons.collections.iterators.IteratorChain;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -103,15 +101,9 @@
      */
     private NodeId rootNodeId;
 
-    /**
-     * Flag indicating whether or not this provider should be create the default
-     * ACLs upon initialization.
-     */
-    private boolean initializedWithDefaults;
-
     //-------------------------------------------------< AccessControlUtils >---
     /**
-     * @see AbstractAccessControlProvider#isAcItem(Path)
+     * @see org.apache.jackrabbit.core.security.authorization.AccessControlUtils#isAcItem(Path)
      */
     public boolean isAcItem(Path absPath) throws RepositoryException {
         Path.Element[] elems = absPath.getElements();
@@ -125,7 +117,7 @@
 
     /**
      * Test if the given node is itself a rep:ACL or a rep:ACE node.
-     * @see AbstractAccessControlProvider#isAcItem(ItemImpl)
+     * @see org.apache.jackrabbit.core.security.authorization.AccessControlUtils#isAcItem(ItemImpl)
      */
     public boolean isAcItem(ItemImpl item) throws RepositoryException {
         NodeImpl n = ((item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent());
@@ -136,6 +128,7 @@
     /**
      * @see org.apache.jackrabbit.core.security.authorization.AccessControlProvider#init(Session, Map)
      */
+    @Override
     public void init(Session systemSession, Map configuration) throws RepositoryException {
         super.init(systemSession, configuration);
 
@@ -144,7 +137,8 @@
         NodeImpl root = (NodeImpl) session.getRootNode();
         rootNodeId = root.getNodeId();
         systemEditor = new ACLEditor(systemSession, this);
-        initializedWithDefaults = !configuration.containsKey(PARAM_OMIT_DEFAULT_PERMISSIONS);
+        // TODO: replace by configurable default policy (see JCR-2331)
+        boolean initializedWithDefaults = !configuration.containsKey(PARAM_OMIT_DEFAULT_PERMISSIONS);
         if (initializedWithDefaults && !isAccessControlled(root)) {
             initRootACL(session, systemEditor);
         }
@@ -208,8 +202,21 @@
         }
     }
 
-    //------------------------------------------------------------< private >---
+    //----------------------------------------------------------< protected >---
+    /**
+     * Retrieve an iterator of <code>AccessControlEntry</code> to be evaluated
+     * upon {@link AbstractCompiledPermissions#buildResult}.
+     *
+     * @param node Target node.
+     * @param principalNames List of principal names.
+     * @return an iterator of <code>AccessControlEntry</code>.
+     * @throws RepositoryException If an error occurs.
+     */
+    protected Iterator<AccessControlEntry> retrieveResultEntries(NodeImpl node, List<String> principalNames) throws RepositoryException {
+        return new Entries(node, principalNames).iterator();
+    }
 
+    //------------------------------------------------------------< private >---
     /**
      * Returns the given <code>targetNode</code> unless the node itself stores
      * access control information in which case it's nearest non-ac-parent is
@@ -280,27 +287,25 @@
                 PrincipalManager pMgr = session.getPrincipalManager();
                 AccessControlManager acMgr = session.getAccessControlManager();
 
-                log.debug("... Privilege.ALL for administrators.");
-                Principal administrators;
                 String pName = SecurityConstants.ADMINISTRATORS_NAME;
                 if (pMgr.hasPrincipal(pName)) {
-                    administrators = pMgr.getPrincipal(pName);
+                    Principal administrators = pMgr.getPrincipal(pName);
+                    log.debug("... Privilege.ALL for administrators.");
+                    Privilege[] privs = new Privilege[]{acMgr.privilegeFromName(Privilege.JCR_ALL)};
+                    acl.addAccessControlEntry(administrators, privs);
                 } else {
-                    log.warn("Administrators principal group is missing.");
-                    administrators = new PrincipalImpl(pName);
+                    log.info("Administrators principal group is missing -> omitting initialization of default permissions.");
                 }
-                Privilege[] privs = new Privilege[]{acMgr.privilegeFromName(Privilege.JCR_ALL)};
-                acl.addAccessControlEntry(administrators, privs);
 
                 Principal everyone = pMgr.getEveryone();
                 log.debug("... Privilege.READ for everyone.");
-                privs = new Privilege[]{acMgr.privilegeFromName(Privilege.JCR_READ)};
+                Privilege[] privs = new Privilege[]{acMgr.privilegeFromName(Privilege.JCR_READ)};
                 acl.addAccessControlEntry(everyone, privs);
 
                 editor.setPolicy(rootPath, acl);
                 session.save();
             } else {
-                log.warn("No applicable ACL available for the root node -> skip initialization of the root node's ACL.");
+                log.info("No applicable ACL available for the root node -> skip initialization of the root node's ACL.");
             }
         } catch (RepositoryException e) {
             log.error("Failed to set-up minimal access control for root node of workspace " + session.getWorkspace().getName());
@@ -331,13 +336,6 @@
     private class AclPermissions extends AbstractCompiledPermissions implements SynchronousEventListener {
 
         private final List<String> principalNames;
-        private final String jcrReadPrivilegeName;
-
-        /**
-         * flag indicating that there is not 'deny READ'.
-         * -> simplify {@link #grants(Path, int)} in case of permissions == READ
-         */
-        private boolean readAllowed;
 
         private AclPermissions(Set<Principal> principals) throws RepositoryException {
             this(principals, true);
@@ -348,17 +346,9 @@
             for (Principal princ : principals) {
                 principalNames.add(princ.getName());
             }
-            jcrReadPrivilegeName = session.getAccessControlManager().privilegeFromName(Privilege.JCR_READ).getName();
 
             if (listenToEvents) {
                 /*
-                 Determine if there is any 'denyRead' entry (since the default
-                 is that everyone can READ everywhere -> makes evaluation for
-                 the most common check (can-read) easy.
-                */
-                readAllowed = isReadAllowed(principalNames);
-
-                /*
                  Make sure this AclPermission recalculates the permissions if
                  any ACL concerning it is modified. interesting events are:
                  - new ACE-entry for any of the principals (NODE_ADDED)
@@ -376,56 +366,11 @@
             }
         }
 
-        /**
-         * If this provider defines read-permission for everyone (defined upon
-         * init with default values), search if there is any ACE that defines
-         * permissions for any of the principals AND denies-READ. Otherwise
-         * this shortcut is not possible.
-         *
-         * @param principalnames names of the principals
-         * @return true if read is allowed everywhere.
-         */
-        private boolean isReadAllowed(Collection<String> principalnames) {
-            boolean isReadAllowed = false;
-            if (initializedWithDefaults) {
-                try {
-                    QueryManager qm = session.getWorkspace().getQueryManager();
-                    StringBuffer stmt = new StringBuffer("/jcr:root");
-                    stmt.append("//element(*,");
-                    stmt.append(resolver.getJCRName(NT_REP_DENY_ACE));
-                    stmt.append(")[(");
-
-                    // where the rep:principalName property exactly matches any of
-                    // the given principalsNames
-                    int i = 0;
-                    for (String principalname : principalnames) {
-                        stmt.append("@").append(resolver.getJCRName(P_PRINCIPAL_NAME)).append(" eq ");
-                        stmt.append("'").append(principalname).append("'");
-                        if (++i < principalnames.size()) {
-                            stmt.append(" or ");
-                        }
-                    }
-                    // AND rep:privileges contains the READ privilege
-                    stmt.append(") and @");
-                    stmt.append(resolver.getJCRName(P_PRIVILEGES));
-                    stmt.append(" = '").append(jcrReadPrivilegeName).append("']");
-
-                    Query q = qm.createQuery(stmt.toString(), Query.XPATH);
-
-                    NodeIterator it = q.execute().getNodes();
-                    isReadAllowed =  !it.hasNext();
-                } catch (RepositoryException e) {
-                    log.error(e.toString());
-                    // unable to determine... -> no shortcut upon grants
-                }
-            }
-            return isReadAllowed;
-        }
-
         //------------------------------------< AbstractCompiledPermissions >---
         /**
          * @see AbstractCompiledPermissions#buildResult(Path)
          */
+        @Override
         protected Result buildResult(Path absPath) throws RepositoryException {
             boolean existingNode = false;
             NodeImpl node = null;
@@ -456,14 +401,14 @@
 
             // retrieve all ACEs at path or at the direct ancestor of path that
             // apply for the principal names.
-            AccessControlEntryIterator entries = new Entries(getNode(node), principalNames).iterator();
+            Iterator<AccessControlEntry> entries = retrieveResultEntries(getNode(node), principalNames);
             // build a list of ACEs that are defined locally at the node
-            List localACEs;
+            List<AccessControlEntry> localACEs;
             if (existingNode && isAccessControlled(node)) {
                 NodeImpl aclNode = node.getNode(N_POLICY);
                 localACEs = Arrays.asList(systemEditor.getACL(aclNode).getAccessControlEntries());
             } else {
-                localACEs = Collections.EMPTY_LIST;
+                localACEs = Collections.emptyList();
             }
             /*
              Calculate privileges and permissions:
@@ -520,22 +465,6 @@
             super.close();
         }
 
-        /**
-         *
-         * @param absPath absolute path
-         * @param permissions permission bits
-         * @return <code>true</code> if the permissions are granted
-         * @throws RepositoryException
-         * @see CompiledPermissions#grants(Path, int)
-         */
-        public boolean grants(Path absPath, int permissions) throws RepositoryException {
-            if (permissions == Permission.READ && readAllowed && !isAcItem(absPath)) {
-                return true;
-            } else {
-                return super.grants(absPath, permissions);
-            }
-        }
-
         //--------------------------------------------------< EventListener >---
         /**
          * @see javax.jcr.observation.EventListener#onEvent(EventIterator)
@@ -556,16 +485,6 @@
                             NodeImpl n = (NodeImpl) session.getNode(path);
                             if (n.isNodeType(NT_REP_ACE) &&
                                     principalNames.contains(n.getProperty(P_PRINCIPAL_NAME).getString())) {
-                                // and reset the readAllowed flag, if the new
-                                // ACE denies READ.
-                                if (readAllowed && n.isNodeType(NT_REP_DENY_ACE)) {
-                                    Value[] vs = n.getProperty(P_PRIVILEGES).getValues();
-                                    for (Value v : vs) {
-                                        if (jcrReadPrivilegeName.equals(v.getString())) {
-                                            readAllowed = false;
-                                        }
-                                    }
-                                }
                                 clearCache = true;
                             }
                             break;
@@ -573,7 +492,6 @@
                         case Event.NODE_REMOVED:
                             // can't find out if the removed ACL/ACE node was
                             // relevant for the principals
-                            readAllowed = isReadAllowed(principalNames);
                             clearCache = true;
                             break;
                         case Event.PROPERTY_ADDED:
@@ -594,7 +512,6 @@
                                 }
                                 if (principalName != null &&
                                         principalNames.contains(principalName)) {
-                                    readAllowed = isReadAllowed(principalNames);
                                     clearCache = true;
                                 }
                             }
@@ -624,13 +541,12 @@
      */
     private class Entries {
 
-        private final Map<String, List<AccessControlEntry>> principalNamesToEntries;
+        private final Collection<String> principalNames;
+        private final List<AccessControlEntry> userAces = new ArrayList();
+        private final List<AccessControlEntry> groupAces = new ArrayList();
 
         private Entries(NodeImpl node, Collection<String> principalNames) throws RepositoryException {
-            principalNamesToEntries = new LinkedHashMap<String, List<AccessControlEntry>>();
-            for (String name : principalNames) {
-                principalNamesToEntries.put(name, new ArrayList<AccessControlEntry>());
-            }
+            this.principalNames = principalNames;
             collectEntries(node);
         }
 
@@ -640,22 +556,80 @@
             if (isAccessControlled(node)) {
                 // build acl for the access controlled node
                 NodeImpl aclNode = node.getNode(N_POLICY);
-                ACLTemplate.collectEntries(aclNode, principalNamesToEntries);
+                //collectEntries(aclNode, principalNamesToEntries);
+                collectEntriesFromAcl(aclNode);
             }
-            // then, recursively look for access controlled parents up the hierarchy.
+            // recursively look for access controlled parents up the hierarchy.
             if (!rootNodeId.equals(node.getId())) {
                 NodeImpl parentNode = (NodeImpl) node.getParent();
                 collectEntries(parentNode);
             }
         }
 
-        private AccessControlEntryIterator iterator() {
-            List<AccessControlEntry> entries = new ArrayList<AccessControlEntry>();
-            for (List<AccessControlEntry> list: principalNamesToEntries.values()) {
-                entries.addAll(list);
+        /**
+         * Separately collect the entries defined for the user and group
+         * principals.
+         *
+         * @param aclNode acl node
+         * @throws RepositoryException if an error occurs
+         */
+        private void collectEntriesFromAcl(NodeImpl aclNode) throws RepositoryException {
+            SessionImpl sImpl = (SessionImpl) aclNode.getSession();
+            PrincipalManager principalMgr = sImpl.getPrincipalManager();
+            AccessControlManager acMgr = sImpl.getAccessControlManager();
+
+            // first collect aces present on the given aclNode.
+            List<AccessControlEntry> gaces = new ArrayList<AccessControlEntry>();
+            List<AccessControlEntry> uaces = new ArrayList<AccessControlEntry>();
+
+            NodeIterator itr = aclNode.getNodes();
+            while (itr.hasNext()) {
+                NodeImpl aceNode = (NodeImpl) itr.nextNode();
+                String principalName = aceNode.getProperty(AccessControlConstants.P_PRINCIPAL_NAME).getString();
+                // only process aceNode if 'principalName' is contained in the given set
+                if (principalNames.contains(principalName)) {
+                    Principal princ = principalMgr.getPrincipal(principalName);
+                    if (princ == null) {
+                        log.warn("Principal with name " + principalName + " unknown to PrincipalManager -> Ignored from AC evaluation.");
+                        continue;
+                    }
+
+                    Value[] privValues = aceNode.getProperty(AccessControlConstants.P_PRIVILEGES).getValues();
+                    Privilege[] privs = new Privilege[privValues.length];
+                    for (int i = 0; i < privValues.length; i++) {
+                        privs[i] = acMgr.privilegeFromName(privValues[i].getString());
+                    }
+                    // create a new ACEImpl (omitting validation check)
+                    AccessControlEntry ace = new ACLTemplate.Entry(
+                            princ,
+                            privs,
+                            aceNode.isNodeType(AccessControlConstants.NT_REP_GRANT_ACE),
+                            sImpl.getValueFactory());
+                    // add it to the proper list (e.g. separated by principals)
+                    /**
+                     * NOTE: access control entries must be collected in reverse
+                     * order in order to assert proper evaluation.
+                     */
+                    if (princ instanceof Group) {
+                        gaces.add(0, ace);
+                    } else {
+                        uaces.add(0, ace);
+                    }
+                }
+            }
+
+            // add the lists of aces to the overall lists that contain the entries
+            // throughout the hierarchy.
+            if (!gaces.isEmpty()) {
+                groupAces.addAll(gaces);
+            }
+            if (!uaces.isEmpty()) {
+                userAces.addAll(uaces);
             }
-            return new AccessControlEntryIterator(entries);
         }
-    }
 
+        private Iterator<AccessControlEntry> iterator() {
+            return new IteratorChain(userAces.iterator(), groupAces.iterator());
+        }
+    }
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLTemplate.java Wed Nov 25 14:04:38 2009
@@ -19,7 +19,6 @@
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -48,9 +47,11 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Implementation of the {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlList} interface that
- * is detached from the effective access control content. Consequently, any
- * modifications applied to this ACL only take effect, if the policy gets
+ * Implementation of the
+ * {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlList}
+ * interface that is detached from the effective access control content.
+ * Consequently, any modifications applied to this ACL only take effect, if
+ * the policy gets
  * {@link javax.jcr.security.AccessControlManager#setPolicy(String, javax.jcr.security.AccessControlPolicy) reapplied}
  * to the <code>AccessControlManager</code> and the changes are saved.
  */
@@ -59,11 +60,10 @@
     private static final Logger log = LoggerFactory.getLogger(ACLTemplate.class);
 
     /**
-     * Map containing the entries of this ACL Template using the principal
-     * name as key. The value represents a List containing maximal one grant
-     * and one deny ACE per principal.
+     * List containing the entries of this ACL Template with maximal one
+     * grant and one deny ACE per principal.
      */
-    private final Map<String, List<Entry>> entries = new LinkedHashMap<String, List<Entry>>();
+    private final List<Entry> entries = new ArrayList<Entry>();
 
     /**
      * The principal manager used for validation checks
@@ -140,102 +140,54 @@
         }
     }
 
-    /**
-     * Separately collect the entries defined for the principals with the
-     * specified names and return a map consisting of principal name key
-     * and a list of ACEs as value.
-     *
-     * @param aclNode acl node
-     * @param princToEntries Map of key = principalName and value = ArrayList
-     * to be filled with ACEs matching the principal names.
-     * @throws RepositoryException if an error occurs
-     */
-    static void collectEntries(NodeImpl aclNode, Map<String, List<AccessControlEntry>> princToEntries)
-            throws RepositoryException {
-        SessionImpl sImpl = (SessionImpl) aclNode.getSession();
-        PrincipalManager principalMgr = sImpl.getPrincipalManager();
-        AccessControlManager acMgr = sImpl.getAccessControlManager();
-
-        NodeIterator itr = aclNode.getNodes();
-        while (itr.hasNext()) {
-            NodeImpl aceNode = (NodeImpl) itr.nextNode();
-            String principalName = aceNode.getProperty(AccessControlConstants.P_PRINCIPAL_NAME).getString();
-            // only process aceNode if 'principalName' is contained in the given set
-            if (princToEntries.containsKey(principalName)) {
-                Principal princ = principalMgr.getPrincipal(principalName);
-                if (princ == null) {
-                    log.warn("Principal with name " + principalName + " unknown to PrincipalManager.");
-                    princ = new PrincipalImpl(principalName);
-                }
-
-                Value[] privValues = aceNode.getProperty(AccessControlConstants.P_PRIVILEGES).getValues();
-                Privilege[] privs = new Privilege[privValues.length];
-                for (int i = 0; i < privValues.length; i++) {
-                    privs[i] = acMgr.privilegeFromName(privValues[i].getString());
-                }
-                // create a new ACEImpl (omitting validation check)
-                Entry ace = new Entry(
-                        princ,
-                        privs,
-                        aceNode.isNodeType(AccessControlConstants.NT_REP_GRANT_ACE),
-                        sImpl.getValueFactory());
-                // add it to the proper list (e.g. separated by principals)
-                princToEntries.get(principalName).add(ace);
-            }
-        }
-    }
-
-    private List<? extends AccessControlEntry> internalGetEntries() {
-        List<Entry> l = new ArrayList<Entry>();
-        for (List<Entry> o : entries.values()) {
-            l.addAll(o);
-        }
-        return l;
-    }
-
     private List<Entry> internalGetEntries(Principal principal) {
         String principalName = principal.getName();
-        if (entries.containsKey(principalName)) {
-            return entries.get(principalName);
-        } else {
-            return new ArrayList<Entry>(2);
+        List entriesPerPrincipal = new ArrayList(2);
+        for (Entry entry : entries) {
+            if (principalName.equals(entry.getPrincipal().getName())) {
+                entriesPerPrincipal.add(entry);
+            }
         }
+        return entriesPerPrincipal;
     }
 
     private synchronized boolean internalAdd(Entry entry) throws AccessControlException {
         Principal principal = entry.getPrincipal();
-        List<Entry> l = internalGetEntries(principal);
-        if (l.isEmpty()) {
-            // simple case: just add the new entry
-            l.add(entry);
-            entries.put(principal.getName(), l);
+        List<Entry> entriesPerPrincipal = internalGetEntries(principal);
+        if (entriesPerPrincipal.isEmpty()) {
+            // simple case: just add the new entry at the end of the list.
+            entries.add(entry);
             return true;
         } else {
-            if (l.contains(entry)) {
+            if (entriesPerPrincipal.contains(entry)) {
                 // the same entry is already contained -> no modification
                 return false;
             }
             // check if need to adjust existing entries
+            int updateIndex = -1;
             Entry complementEntry = null;
-            Entry[] entries = l.toArray(new Entry[l.size()]);
-            for (int i = 0; i < entries.length; i++) {
-                if (entry.isAllow() == entries[i].isAllow()) {
-                    int existingPrivs = entries[i].getPrivilegeBits();
+
+            for (Entry e : entriesPerPrincipal) {
+                if (entry.isAllow() == e.isAllow()) {
+                    int existingPrivs = e.getPrivilegeBits();
                     if ((existingPrivs | ~entry.getPrivilegeBits()) == -1) {
                         // all privileges to be granted/denied are already present
                         // in the existing entry -> not modified
                         return false;
                     }
 
+                    // remember the index of the existing entry to be updated later on.
+                    updateIndex = entries.indexOf(e);
+
                     // remove the existing entry and create a new that includes
                     // both the new privileges and the existing ones.
-                    l.remove(i);
-                    int mergedBits = entries[i].getPrivilegeBits() | entry.getPrivilegeBits();
+                    entries.remove(e);
+                    int mergedBits = e.getPrivilegeBits() | entry.getPrivilegeBits();
                     Privilege[] mergedPrivs = privilegeRegistry.getPrivileges(mergedBits);
                     // omit validation check.
                     entry = new Entry(entry.getPrincipal(), mergedPrivs, entry.isAllow(), valueFactory);
                 } else {
-                    complementEntry = entries[i];
+                    complementEntry = e;
                 }
             }
 
@@ -243,22 +195,34 @@
             // grant/deny the same privileges -> remove privileges that are now
             // denied/granted.
             if (complementEntry != null) {
+
                 int complPrivs = complementEntry.getPrivilegeBits();
                 int resultPrivs = Permission.diff(complPrivs, entry.getPrivilegeBits());
+
                 if (resultPrivs == PrivilegeRegistry.NO_PRIVILEGE) {
-                    l.remove(complementEntry);
+                    // remove the complement entry as the new entry covers
+                    // all privileges granted by the existing entry.
+                    entries.remove(complementEntry);
+                    updateIndex--;
+                    
                 } else if (resultPrivs != complPrivs) {
-                    l.remove(complementEntry);
-                    // omit validation check
+                    // replace the existing entry having the privileges adjusted
+                    int index = entries.indexOf(complementEntry);
+                    entries.remove(complementEntry);
                     Entry tmpl = new Entry(entry.getPrincipal(),
                             privilegeRegistry.getPrivileges(resultPrivs),
                             !entry.isAllow(), valueFactory);
-                    l.add(tmpl);
+                    entries.add(index, tmpl);
                 } /* else: does not need to be modified.*/
             }
 
-            // finally add the new entry at the end.
-            l.add(entry);
+            // finally update the existing entry or add the new entry passed
+            // to this method at the end.
+            if (updateIndex < 0) {
+                entries.add(entry);
+            } else {
+                entries.add(updateIndex, entry);
+            }
             return true;
         }
     }
@@ -281,12 +245,19 @@
         }
     }
 
+    /**
+     * @see org.apache.jackrabbit.core.security.authorization.AbstractACLTemplate#getEntries()
+     */
+    protected List<? extends AccessControlEntry> getEntries() {
+        return entries;
+    }
+
     //--------------------------------------------------< AccessControlList >---
     /**
      * @see javax.jcr.security.AccessControlList#getAccessControlEntries()
      */
     public AccessControlEntry[] getAccessControlEntries() throws RepositoryException {
-        List<? extends AccessControlEntry> l = internalGetEntries();
+        List<? extends AccessControlEntry> l = getEntries();
         return l.toArray(new AccessControlEntry[l.size()]);
     }
 
@@ -298,11 +269,8 @@
         if (!(ace instanceof Entry)) {
             throw new AccessControlException("Invalid AccessControlEntry implementation " + ace.getClass().getName() + ".");
         }
-        List l = internalGetEntries(ace.getPrincipal());
-        if (l.remove(ace)) {
-            if (l.isEmpty()) {
-                entries.remove(ace.getPrincipal().getName());
-            }
+        if (entries.contains(ace)) {
+            entries.remove(ace);
         } else {
             throw new AccessControlException("AccessControlEntry " + ace + " cannot be removed from ACL defined at " + getPath());
         }
@@ -339,7 +307,7 @@
      * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlList#size()
      */
     public int size() {
-        return internalGetEntries().size();
+        return getEntries().size();
     }
 
     /**

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/combined/CombinedProvider.java Wed Nov 25 14:04:38 2009
@@ -81,6 +81,7 @@
     /**
      * @see AccessControlProvider#close()
      */
+    @Override
     public void close() {
         for (AccessControlProvider provider : providers) {
             provider.close();
@@ -91,6 +92,7 @@
     /**
      * @see AccessControlProvider#init(javax.jcr.Session, java.util.Map)
      */
+    @Override
     public void init(Session systemSession, Map configuration) throws RepositoryException {
         super.init(systemSession, configuration);
 
@@ -207,6 +209,7 @@
         /**
          * @see AbstractCompiledPermissions#buildResult(Path)
          */
+        @Override
         protected Result buildResult(Path absPath) throws RepositoryException {
             Result res = null;
             for (AbstractCompiledPermissions acp : cPermissions) {
@@ -219,6 +222,7 @@
         /**
          * @see AbstractCompiledPermissions#getResult(Path)
          */
+        @Override
         public Result getResult(Path absPath) throws RepositoryException {
             // TODO: missing caching
             return buildResult(absPath);
@@ -228,10 +232,11 @@
         /**
          * @see CompiledPermissions#close()
          */
+        @Override
         public synchronized void close() {
             // close all c-permissions retained in the list and clear the list.
-            for (Iterator it = cPermissions.iterator(); it.hasNext();) {
-                CompiledPermissions cp = (CompiledPermissions) it.next();
+            for (Iterator<AbstractCompiledPermissions> it = cPermissions.iterator(); it.hasNext();) {
+                CompiledPermissions cp = it.next();
                 cp.close();
                 it.remove();
             }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java?rev=884108&r1=884107&r2=884108&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLProvider.java Wed Nov 25 14:04:38 2009
@@ -99,6 +99,7 @@
     /**
      * @see org.apache.jackrabbit.core.security.authorization.AccessControlProvider#init(javax.jcr.Session, java.util.Map)
      */
+    @Override
     public void init(Session systemSession, Map configuration) throws RepositoryException {
         super.init(systemSession, configuration);
 
@@ -113,6 +114,7 @@
         }
 
         editor = new ACLEditor(session, resolver.getQPath(acRoot.getPath()));
+        // TODO: replace by configurable default policy (see JCR-2331)
         if (!configuration.containsKey(PARAM_OMIT_DEFAULT_PERMISSIONS)) {
             try {
                 log.debug("Install initial permissions: ...");
@@ -126,15 +128,14 @@
                 AccessControlManager acMgr = session.getAccessControlManager();
 
                 // initial default permissions for the administrators group                
-                Principal administrators;
                 String pName = SecurityConstants.ADMINISTRATORS_NAME;
                 if (pMgr.hasPrincipal(pName)) {
-                    administrators = pMgr.getPrincipal(pName);
+                    Principal administrators = pMgr.getPrincipal(pName);
                     installDefaultPermissions(administrators,
                         new Privilege[] {acMgr.privilegeFromName(Privilege.JCR_ALL)},
                         restrictions, editor);
                 } else {
-                    log.warn("Administrators principal group is missing -> Not adding default permissions.");
+                    log.info("Administrators principal group is missing -> Not adding default permissions.");
                 }
 
                 // initialize default permissions for the everyone group
@@ -276,6 +277,7 @@
         /**
          * @see AbstractCompiledPermissions#buildResult(Path)
          */
+        @Override
         protected synchronized Result buildResult(Path absPath) throws RepositoryException {
             if (!absPath.isAbsolute()) {
                 throw new RepositoryException("Absolute path expected.");
@@ -355,6 +357,7 @@
         /**
          * @see CompiledPermissions#close()
          */
+        @Override
         public void close() {
             try {
                 observationMgr.removeEventListener(this);