[exo-jcr-commits] exo-jcr SVN: r3914 - in jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr: impl/core/query and 3 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Wed Feb 2 11:15:14 EST 2011


Author: tolusha
Date: 2011-02-02 11:15:14 -0500 (Wed, 02 Feb 2011)
New Revision: 3914

Added:
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NodeDataIndexing.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/Indexable.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/NodeDataIndexingIterator.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/JdbcNodeDataIndexingIterator.java
Modified:
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeIndexer.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainer.java
Log:
EXOJCR-1104: re-indexing mechanism for RDBMS

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NodeDataIndexing.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NodeDataIndexing.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NodeDataIndexing.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -0,0 +1,147 @@
+/*
+ * 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.datamodel;
+
+import org.exoplatform.services.jcr.access.AccessControlList;
+import org.exoplatform.services.jcr.dataflow.ItemDataVisitor;
+
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * Date: 1 02 2011
+ * 
+ * @author <a href="mailto:anatoliy.bazko at exoplatform.com.ua">Anatoliy Bazko</a>
+ * @version $Id: NodeDataIndexing.java 34360 2010-11-11 11:11:11Z tolusha $
+ */
+public class NodeDataIndexing implements NodeData
+{
+   private final NodeData nodeData;
+
+   private final List<PropertyData> properties;
+
+   /**
+    * Constructor NodeDataIndexing.
+    */
+   public NodeDataIndexing(NodeData nodeData)
+   {
+      this(nodeData, null);
+   }
+
+   /**
+    * Constructor NodeDataIndexing.
+    */
+   public NodeDataIndexing(NodeData nodeData, List<PropertyData> properties)
+   {
+      this.nodeData = nodeData;
+      this.properties = properties;
+   }
+
+   /**
+    * 
+    * @return
+    */
+   public List<PropertyData> getChildPropertiesData()
+   {
+      return properties;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public QPath getQPath()
+   {
+      return nodeData.getQPath();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public String getIdentifier()
+   {
+      return nodeData.getIdentifier();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public int getPersistedVersion()
+   {
+      return nodeData.getPersistedVersion();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public String getParentIdentifier()
+   {
+      return nodeData.getParentIdentifier();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public boolean isNode()
+   {
+      return nodeData.isNode();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void accept(ItemDataVisitor visitor) throws RepositoryException
+   {
+      nodeData.accept(visitor);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public int getOrderNumber()
+   {
+      return nodeData.getOrderNumber();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public InternalQName getPrimaryTypeName()
+   {
+      return nodeData.getPrimaryTypeName();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public InternalQName[] getMixinTypeNames()
+   {
+      return nodeData.getMixinTypeNames();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public AccessControlList getACL()
+   {
+      throw new UnsupportedOperationException("getACL() method is not supported");
+   }
+}

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/Indexable.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/Indexable.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/Indexable.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -0,0 +1,35 @@
+/*
+ * 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.core.query;
+
+import java.io.IOException;
+
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * Date: 1 02 2011
+ * 
+ * @author <a href="mailto:anatoliy.bazko at exoplatform.com.ua">Anatoliy Bazko</a>
+ * @version $Id: Indexing.java 34360 2010-11-11 11:11:11Z tolusha $
+ */
+public interface Indexable
+{
+   NodeDataIndexingIterator getNodeDataIndexingIterator() throws IOException;
+}

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/NodeDataIndexingIterator.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/NodeDataIndexingIterator.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/NodeDataIndexingIterator.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -0,0 +1,58 @@
+/*
+ * 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.core.query;
+
+import org.exoplatform.services.jcr.datamodel.NodeDataIndexing;
+
+import java.io.IOException;
+import java.util.NoSuchElementException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * Date: 1 02 2011
+ * 
+ * @author <a href="mailto:anatoliy.bazko at exoplatform.com.ua">Anatoliy Bazko</a>
+ * @version $Id: IndexingDataIterator.java 34360 2010-11-11 11:11:11Z tolusha $
+ */
+public interface NodeDataIndexingIterator
+{
+
+   /**
+    * Returns <tt>true</tt> if the iteration has more elements. (In other
+    * words, returns <tt>true</tt> if <tt>next</tt> would return an element
+    * rather than throwing an exception.)
+    *
+    * @return <tt>true</tt> if the iterator has more elements.
+    */
+   boolean hasNext();
+
+   /**
+    * Returns the next element in the iteration.
+    *
+    * @return the next element in the iteration.
+    * @exception NoSuchElementException iteration has no more elements.
+    */
+   NodeDataIndexing next() throws IOException;
+
+   /**
+    * Closes the iterator and releases all resources.
+    */
+   void close() throws IOException;
+}

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java	2011-02-02 13:49:51 UTC (rev 3913)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -17,6 +17,7 @@
 package org.exoplatform.services.jcr.impl.core.query;
 
 import org.exoplatform.services.document.DocumentReaderService;
+import org.exoplatform.services.jcr.core.WorkspaceContainerFacade;
 import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
 import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.impl.core.NamespaceRegistryImpl;
@@ -73,6 +74,11 @@
    private final LuceneVirtualTableResolver virtualTableResolver;
 
    /**
+    * Workspace container.
+    */
+   private final WorkspaceContainerFacade container;
+
+   /**
     * Creates a new context instance.
     * 
     * @param fs
@@ -95,11 +101,12 @@
     *            id of the node that should be excluded from indexing. Any
     *            descendant of that node is also excluded from indexing.
     */
-   public QueryHandlerContext(ItemDataConsumer stateMgr, IndexingTree indexingTree,
+   public QueryHandlerContext(WorkspaceContainerFacade container, ItemDataConsumer stateMgr, IndexingTree indexingTree,
       NodeTypeDataManager nodeTypeDataManager, NamespaceRegistryImpl nsRegistry, QueryHandler parentHandler,
       String indexDirectory, DocumentReaderService extractor, boolean createInitialIndex,
       LuceneVirtualTableResolver virtualTableResolver)
    {
+      this.container = container;
       this.stateMgr = stateMgr;
       this.indexingTree = indexingTree;
       this.nodeTypeDataManager = nodeTypeDataManager;
@@ -114,6 +121,14 @@
    }
 
    /**
+    * @return the workspace container
+    */
+   public WorkspaceContainerFacade getContainer()
+   {
+      return container;
+   }
+
+   /**
     * @return the virtualTableResolver
     */
    public LuceneVirtualTableResolver getVirtualTableResolver()

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java	2011-02-02 13:49:51 UTC (rev 3913)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -24,10 +24,13 @@
 import org.exoplatform.commons.utils.PrivilegedFileHelper;
 import org.exoplatform.container.configuration.ConfigurationManager;
 import org.exoplatform.services.document.DocumentReaderService;
+import org.exoplatform.services.jcr.RepositoryService;
 import org.exoplatform.services.jcr.config.QueryHandlerEntry;
 import org.exoplatform.services.jcr.config.QueryHandlerParams;
 import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.config.RepositoryEntry;
 import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.core.WorkspaceContainerFacade;
 import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
 import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.dataflow.ItemState;
@@ -154,6 +157,18 @@
    protected IndexerChangesFilter changesFilter;
 
    /**
+    * The Repository name.
+    */
+   protected final String repositoryName;
+
+   /**
+    * The Repository name.
+    */
+   protected final String workspaceName;
+
+   protected final RepositoryService rService;
+
+   /**
     * The unique name of the related workspace
     */
    protected final String wsId;
@@ -191,6 +206,10 @@
    /**
     * Creates a new <code>SearchManager</code>.
     * 
+    * @param rEntry
+    *            repository configuration
+    * @param rService
+    *            repository service            
     * @param config
     *            the search configuration.
     * @param nsReg
@@ -212,17 +231,23 @@
     * @throws RepositoryConfigurationException
     */
 
-   public SearchManager(WorkspaceEntry wsConfig, QueryHandlerEntry config, NamespaceRegistryImpl nsReg,
-      NodeTypeDataManager ntReg, WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
+   public SearchManager(WorkspaceEntry wsConfig, RepositoryEntry rEntry, RepositoryService rService,
+      QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
+      WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
       DocumentReaderService extractor, ConfigurationManager cfm, final RepositoryIndexSearcherHolder indexSearcherHolder)
       throws RepositoryException, RepositoryConfigurationException
    {
-      this(wsConfig, config, nsReg, ntReg, itemMgr, parentSearchManager, extractor, cfm, indexSearcherHolder, null);
+      this(wsConfig, rEntry, rService, config, nsReg, ntReg, itemMgr, parentSearchManager, extractor, cfm,
+         indexSearcherHolder, null);
    }
 
    /**
     * Creates a new <code>SearchManager</code>.
     * 
+    * @param rEntry
+    *            repository configuration
+    * @param rService
+    *            repository service  
     * @param config
     *            the search configuration.
     * @param nsReg
@@ -246,12 +271,16 @@
     * @throws RepositoryConfigurationException
     */
 
-   public SearchManager(WorkspaceEntry wsConfig, QueryHandlerEntry config, NamespaceRegistryImpl nsReg,
-      NodeTypeDataManager ntReg, WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
+   public SearchManager(WorkspaceEntry wsConfig, RepositoryEntry rEntry, RepositoryService rService,
+      QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
+      WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
       DocumentReaderService extractor, ConfigurationManager cfm,
       final RepositoryIndexSearcherHolder indexSearcherHolder, RPCService rpcService) throws RepositoryException,
       RepositoryConfigurationException
    {
+      this.repositoryName = rEntry.getName();
+      this.workspaceName = wsConfig.getName();
+      this.rService = rService;
       this.rpcService = rpcService;
       this.wsId = wsConfig.getUniqueName();
       this.extractor = extractor;
@@ -660,10 +689,19 @@
    protected QueryHandlerContext createQueryHandlerContext(QueryHandler parentHandler)
       throws RepositoryConfigurationException
    {
+      WorkspaceContainerFacade container;
+      try
+      {
+         container = rService.getRepository(repositoryName).getWorkspaceContainer(workspaceName);
+      }
+      catch (RepositoryException e)
+      {
+         throw new RepositoryConfigurationException(e);
+      }
 
       QueryHandlerContext context =
-         new QueryHandlerContext(itemMgr, indexingTree, nodeTypeDataManager, nsReg, parentHandler, getIndexDirectory(),
-            extractor, true, virtualTableResolver);
+         new QueryHandlerContext(container, itemMgr, indexingTree, nodeTypeDataManager, nsReg, parentHandler,
+            getIndexDirectory(), extractor, true, virtualTableResolver);
       return context;
    }
 

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java	2011-02-02 13:49:51 UTC (rev 3913)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -18,8 +18,10 @@
 
 import org.exoplatform.container.configuration.ConfigurationManager;
 import org.exoplatform.services.document.DocumentReaderService;
+import org.exoplatform.services.jcr.RepositoryService;
 import org.exoplatform.services.jcr.config.QueryHandlerEntry;
 import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.config.RepositoryEntry;
 import org.exoplatform.services.jcr.config.WorkspaceEntry;
 import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
 import org.exoplatform.services.jcr.datamodel.NodeData;
@@ -58,11 +60,12 @@
 
    public static final String INDEX_DIR_SUFFIX = "system";
 
-   public SystemSearchManager(WorkspaceEntry wsConfig, QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
+   public SystemSearchManager(WorkspaceEntry wsConfig, RepositoryEntry rEntry, RepositoryService rService,
+      QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
       WorkspacePersistentDataManager itemMgr, DocumentReaderService service, ConfigurationManager cfm,
       RepositoryIndexSearcherHolder indexSearcherHolder) throws RepositoryException, RepositoryConfigurationException
    {
-      super(wsConfig, config, nsReg, ntReg, itemMgr, null, service, cfm, indexSearcherHolder);
+      super(wsConfig, rEntry, rService, config, nsReg, ntReg, itemMgr, null, service, cfm, indexSearcherHolder);
    }
 
    @Override
@@ -103,16 +106,6 @@
       }
    }
 
-   @Override
-   protected QueryHandlerContext createQueryHandlerContext(QueryHandler parentHandler)
-      throws RepositoryConfigurationException
-   {
-      QueryHandlerContext context =
-         new QueryHandlerContext(itemMgr, indexingTree, nodeTypeDataManager, nsReg, parentHandler, getIndexDirectory(),
-            extractor, true, virtualTableResolver);
-      return context;
-   }
-
    /**
     * {@inheritDoc}
     */

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java	2011-02-02 13:49:51 UTC (rev 3913)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -24,11 +24,14 @@
 import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.datamodel.ItemData;
 import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.NodeDataIndexing;
 import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.core.query.Indexable;
 import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
 import org.exoplatform.services.jcr.impl.core.query.IndexerIoModeHandler;
 import org.exoplatform.services.jcr.impl.core.query.IndexerIoModeListener;
 import org.exoplatform.services.jcr.impl.core.query.IndexingTree;
+import org.exoplatform.services.jcr.impl.core.query.NodeDataIndexingIterator;
 import org.exoplatform.services.jcr.impl.core.query.lucene.directory.DirectoryManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -400,8 +403,19 @@
             long count = 0;
             // traverse and index workspace
             executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
+
             // NodeData rootState = (NodeData) stateMgr.getItemData(rootId);
-            count = createIndex(indexingTree.getIndexingRoot(), stateMgr, count);
+
+            // check if we have deal with JDBC indexing mechanism
+            Indexable indexableComponent = (Indexable)handler.getContext().getContainer().getComponent(Indexable.class);
+            if (indexableComponent == null)
+            {
+               count = createIndex(indexingTree.getIndexingRoot(), stateMgr, count);
+            }
+            else
+            {
+               count = createIndex(indexableComponent, indexingTree.getIndexingRoot(), stateMgr, count);
+            }
             executeAndLog(new Commit(getTransactionId()));
             log.info("Created initial index for {} nodes", new Long(count));
             releaseMultiReader();
@@ -1035,6 +1049,20 @@
     */
    Document createDocument(NodeData node) throws RepositoryException
    {
+      return createDocument(new NodeDataIndexing(node));
+   }
+
+   /**
+    * Returns a lucene Document for the <code>node</code>.
+    * 
+    * @param node
+    *            the node to index wrapped into NodeDataIndexing
+    * @return the index document.
+    * @throws RepositoryException
+    *             if an error occurs while reading from the workspace.
+    */
+   Document createDocument(NodeDataIndexing node) throws RepositoryException
+   {
       return handler.createDocument(node, nsMappings, version);
    }
 
@@ -1395,6 +1423,7 @@
          return count;
       }
       executeAndLog(new AddNode(getTransactionId(), node.getIdentifier()));
+
       if (++count % 100 == 0)
       {
 
@@ -1426,6 +1455,69 @@
    }
 
    /**
+    * Recursively creates an index starting with the NodeState
+    * <code>node</code>.
+    * 
+    * @param indexableComponent
+    *          the component which responsible for quick indexing
+    * @param rootNode
+    *            the current NodeState.
+    * @param path
+    *            the path of the current node.
+    * @param stateMgr
+    *            the shared item state manager.
+    * @param count
+    *            the number of nodes already indexed.
+    * @return the number of nodes indexed so far.
+    * @throws IOException
+    *             if an error occurs while writing to the index.
+    * @throws ItemStateException
+    *             if an node state cannot be found.
+    * @throws RepositoryException
+    *             if any other error occurs
+    */
+   private long createIndex(Indexable indexableComponent, NodeData rootNode, ItemDataConsumer stateMgr, long count)
+      throws IOException, RepositoryException
+   {
+      NodeDataIndexingIterator iterator = indexableComponent.getNodeDataIndexingIterator();
+      try
+      {
+         while (iterator.hasNext())
+         {
+            NodeDataIndexing node = iterator.next();
+
+            if (indexingTree.isExcluded(node))
+            {
+               continue;
+            }
+
+            if (!node.getQPath().isDescendantOf(rootNode.getQPath()) && !node.getQPath().equals(rootNode.getQPath()))
+            {
+               continue;
+            }
+
+            executeAndLog(new AddNode(getTransactionId(), node));
+
+            if (++count % 100 == 0)
+            {
+               log.info("indexing... {} ({})", node.getQPath().getAsString(), new Long(count));
+            }
+            if (count % 10 == 0)
+            {
+               checkIndexingQueue(true);
+            }
+            checkVolatileCommit();
+         }
+      }
+      finally
+      {
+         iterator.close();
+      }
+
+      return count;
+   }
+
+   /**
     * Attempts to delete all files recorded in {@link #deletable}.
     */
    private void attemptDelete()
@@ -1946,6 +2038,11 @@
       private Document doc;
 
       /**
+       * The node to add.
+       */
+      private NodeDataIndexing node;
+
+      /**
        * Creates a new AddNode action.
        * 
        * @param transactionId
@@ -1964,6 +2061,20 @@
        * 
        * @param transactionId
        *            the id of the transaction that executes this action.
+       * @param uuid
+       *            the uuid of the node to add.
+       */
+      AddNode(long transactionId, NodeDataIndexing node)
+      {
+         this(transactionId, node.getIdentifier());
+         this.node = node;
+      }
+
+      /**
+       * Creates a new AddNode action.
+       * 
+       * @param transactionId
+       *            the id of the transaction that executes this action.
        * @param doc
        *            the document to add.
        */
@@ -2006,7 +2117,14 @@
          {
             try
             {
-               doc = index.createDocument(uuid);
+               if (node != null)
+               {
+                  doc = index.createDocument(node);
+               }
+               else
+               {
+                  doc = index.createDocument(uuid);
+               }
             }
             catch (RepositoryException e)
             {

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeIndexer.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeIndexer.java	2011-02-02 13:49:51 UTC (rev 3913)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeIndexer.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -29,7 +29,7 @@
 import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.datamodel.InternalQName;
 import org.exoplatform.services.jcr.datamodel.ItemType;
-import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.NodeDataIndexing;
 import org.exoplatform.services.jcr.datamodel.PropertyData;
 import org.exoplatform.services.jcr.datamodel.QPathEntry;
 import org.exoplatform.services.jcr.datamodel.ValueData;
@@ -75,7 +75,7 @@
    /**
     * The <code>NodeState</code> of the node to index
     */
-   protected final NodeData node;
+   protected final NodeDataIndexing node;
 
    /**
     * The persistent item state provider
@@ -130,7 +130,7 @@
     * @param mappings      internal namespace mappings.
     * @param extractor     content extractor
     */
-   public NodeIndexer(NodeData node, ItemDataConsumer stateProvider, NamespaceMappings mappings,
+   public NodeIndexer(NodeDataIndexing node, ItemDataConsumer stateProvider, NamespaceMappings mappings,
       DocumentReaderService extractor)
    {
       this.node = node;
@@ -219,9 +219,15 @@
          // unknown uri<->prefix mappings
       }
 
-      for (final PropertyData prop : stateProvider.listChildPropertiesData(node))
+      List<PropertyData> props = node.getChildPropertiesData();
+      if (props == null)
       {
+         props = stateProvider.listChildPropertiesData(node);
+      }
 
+      for (final PropertyData prop : props)
+      {
+
          // add each property to the _PROPERTIES_SET for searching
          // beginning with V2
          if (indexFormatVersion.getVersion() >= IndexFormatVersion.V2.getVersion())

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java	2011-02-02 13:49:51 UTC (rev 3913)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -45,6 +45,7 @@
 import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.datamodel.ItemData;
 import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.NodeDataIndexing;
 import org.exoplatform.services.jcr.datamodel.PropertyData;
 import org.exoplatform.services.jcr.datamodel.QPath;
 import org.exoplatform.services.jcr.impl.Constants;
@@ -1221,6 +1222,28 @@
    protected Document createDocument(NodeData node, NamespaceMappings nsMappings, IndexFormatVersion indexFormatVersion)
       throws RepositoryException
    {
+      return createDocument(new NodeDataIndexing(node), nsMappings, indexFormatVersion);
+   }
+
+   /**
+    * Creates a lucene <code>Document</code> for a node state using the
+    * namespace mappings <code>nsMappings</code>.
+    * 
+    * @param node
+    *            the node state to index.
+    * @param nsMappings
+    *            the namespace mappings of the search index.
+    * @param indexFormatVersion
+    *            the index format version that should be used to index the
+    *            passed node state.
+    * @return a lucene <code>Document</code> that contains all properties of
+    *         <code>node</code>.
+    * @throws RepositoryException
+    *             if an error occurs while indexing the <code>node</code>.
+    */
+   protected Document createDocument(NodeDataIndexing node, NamespaceMappings nsMappings,
+      IndexFormatVersion indexFormatVersion) throws RepositoryException
+   {
       NodeIndexer indexer = new NodeIndexer(node, getContext().getItemStateManager(), nsMappings, extractor);
       indexer.setSupportHighlighting(supportHighlighting);
       indexer.setIndexingConfiguration(indexingConfig);

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainer.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainer.java	2011-02-02 13:49:51 UTC (rev 3913)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainer.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -37,6 +37,8 @@
 import org.exoplatform.services.jcr.impl.backup.rdbms.DirectoryRestor;
 import org.exoplatform.services.jcr.impl.backup.rdbms.RestoreTableRule;
 import org.exoplatform.services.jcr.impl.clean.rdbms.DBCleanService;
+import org.exoplatform.services.jcr.impl.core.query.Indexable;
+import org.exoplatform.services.jcr.impl.core.query.NodeDataIndexingIterator;
 import org.exoplatform.services.jcr.impl.dataflow.serialization.ObjectReaderImpl;
 import org.exoplatform.services.jcr.impl.dataflow.serialization.ObjectWriterImpl;
 import org.exoplatform.services.jcr.impl.storage.WorkspaceDataContainerBase;
@@ -45,6 +47,7 @@
 import org.exoplatform.services.jcr.impl.storage.jdbc.db.MySQLConnectionFactory;
 import org.exoplatform.services.jcr.impl.storage.jdbc.db.OracleConnectionFactory;
 import org.exoplatform.services.jcr.impl.storage.jdbc.db.WorkspaceStorageConnectionFactory;
+import org.exoplatform.services.jcr.impl.storage.jdbc.indexing.JdbcNodeDataIndexingIterator;
 import org.exoplatform.services.jcr.impl.storage.jdbc.init.IngresSQLDBInitializer;
 import org.exoplatform.services.jcr.impl.storage.jdbc.init.OracleDBInitializer;
 import org.exoplatform.services.jcr.impl.storage.jdbc.init.PgSQLDBInitializer;
@@ -92,7 +95,8 @@
  * @author <a href="mailto:peter.nedonosko at exoplatform.com.ua">Peter Nedonosko</a>
  * @version $Id:GenericWorkspaceDataContainer.java 13433 2007-03-15 16:07:23Z peterit $
  */
-public class JDBCWorkspaceDataContainer extends WorkspaceDataContainerBase implements Startable, JdbcBackupable
+public class JDBCWorkspaceDataContainer extends WorkspaceDataContainerBase implements Startable, JdbcBackupable,
+   Indexable
 {
 
    protected static final Log LOG = ExoLogger.getLogger("exo.jcr.component.core.JDBCWorkspaceDataContainer");
@@ -1417,4 +1421,37 @@
          throw new BackupException(e);
       }
    }
+
+   /**
+    * {@inheritDoc}
+    */
+   public NodeDataIndexingIterator getNodeDataIndexingIterator() throws IOException
+   {
+      try
+      {
+         final DataSource ds = (DataSource)new InitialContext().lookup(dbSourceName);
+
+         if (ds != null)
+         {
+            Connection jdbcConn =
+               SecurityHelper.doPrivilegedSQLExceptionAction(new PrivilegedExceptionAction<Connection>()
+               {
+                  public Connection run() throws Exception
+                  {
+                     return ds.getConnection();
+                  }
+               });
+            return new JdbcNodeDataIndexingIterator(jdbcConn, multiDb, containerName, swapCleaner, maxBufferSize,
+               swapDirectory, valueStorageProvider);
+         }
+         else
+         {
+            throw new NameNotFoundException("Data source " + dbSourceName + " not found");
+         }
+      }
+      catch (Exception e)
+      {
+         throw new IOException(e);
+      }
+   }
 }

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/JdbcNodeDataIndexingIterator.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/JdbcNodeDataIndexingIterator.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/indexing/JdbcNodeDataIndexingIterator.java	2011-02-02 16:15:14 UTC (rev 3914)
@@ -0,0 +1,770 @@
+/*
+ * 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.storage.jdbc.indexing;
+
+import org.exoplatform.commons.utils.PrivilegedFileHelper;
+import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
+import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData;
+import org.exoplatform.services.jcr.datamodel.IllegalNameException;
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.NodeDataIndexing;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
+import org.exoplatform.services.jcr.datamodel.QPath;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.datamodel.ValueData;
+import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.core.query.NodeDataIndexingIterator;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.ByteArrayPersistedValueData;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.CleanableFilePersistedValueData;
+import org.exoplatform.services.jcr.impl.storage.jdbc.DBConstants;
+import org.exoplatform.services.jcr.impl.storage.jdbc.PrimaryTypeNotFoundException;
+import org.exoplatform.services.jcr.impl.storage.value.ValueStorageNotFoundException;
+import org.exoplatform.services.jcr.impl.storage.value.fs.operations.ValueFileIOHelper;
+import org.exoplatform.services.jcr.impl.util.io.FileCleaner;
+import org.exoplatform.services.jcr.impl.util.io.SwapFile;
+import org.exoplatform.services.jcr.storage.value.ValueIOChannel;
+import org.exoplatform.services.jcr.storage.value.ValueStoragePluginProvider;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.jcr.InvalidItemStateException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * Date: 1 02 2011
+ * 
+ * Iterator for fetching NodeData from database with all properties and its values.
+ * 
+ * @author <a href="mailto:anatoliy.bazko at exoplatform.com.ua">Anatoliy Bazko</a>
+ * @version $Id: JdbcIndexingDataIterator.java 34360 2010-11-11 11:11:11Z tolusha $
+ */
+public class JdbcNodeDataIndexingIterator extends DBConstants implements NodeDataIndexingIterator
+{
+
+   /**
+    * Logger.
+    */
+   protected static final Log LOG = ExoLogger.getLogger("exo.jcr.component.core.JdbcIndexingDataIterator");
+
+   /**
+    * Connection to the database. Should be released on close.
+    */
+   private final Connection jdbcConn;
+
+   /**
+    * Temporary used prepared statement for query execution. Should be released on close.
+    */
+   private PreparedStatement st = null;
+
+   /**
+    * Temporary used prepared statement. Should be released on close.
+    */
+   private PreparedStatement findItemQPathByIdentifierCQ;
+
+   /**
+    * Temporary used result set during fetching data. Should be released on close.
+    */
+   private ResultSet resultSet = null;
+
+   /**
+    * Connection to the database. Should be released on close.
+    */
+   private TempNodeData data = null;
+
+   /**
+    * Indicates if mulit db is used or not.
+    */
+   private final boolean multiDb;
+
+   /**
+    * Container name.
+    */
+   private final String containerName;
+
+   /**
+    * The File Cleaner.
+    */
+   private final FileCleaner swapCleaner;
+
+   /**
+    * Maximum buffer size.
+    */
+   private final int maxBufferSize;
+
+   /**
+    * Swap directory.
+    */
+   private final File swapDirectory;
+
+   /**
+    * Value storage provider.
+    */
+   private final ValueStoragePluginProvider valueStorageProvider;
+
+   /**
+    * The next node data to return in next() method.
+    */
+   private NodeDataIndexing nextNode = null;
+
+   /**
+    * Search query for single db.
+    */
+   private static final String FIND_NODES_SINGLE_DB =
+      "select I.ID AS N_ID, I.PARENT_ID AS N_PARENT_ID, I.NAME AS N_NAME, I.VERSION AS N_VERSION, I.I_INDEX AS N_I_INDEX, I.N_ORDER_NUM, "
+         + "P.ID AS P_ID, P.NAME AS P_NAME, P.VERSION AS P_VERSION, P.P_TYPE, P.P_MULTIVALUED, "
+         + "V.DATA, V.ORDER_NUM,  V.STORAGE_DESC"
+         + " from JCR_SITEM I, JCR_SITEM P, JCR_SVALUE V where I.I_CLASS=1 and I.CONTAINER_NAME=? and"
+         + " P.I_CLASS=2 and P.CONTAINER_NAME=? and P.PARENT_ID=I.ID" + " and V.PROPERTY_ID=P.ID order by N_ID";
+
+   /**
+    * Search query for multi db.
+    */
+   private static final String FIND_NODES_MULTI_DB =
+      "select I.ID AS N_ID, I.PARENT_ID AS N_PARENT_ID, I.NAME AS N_NAME, I.VERSION AS N_VERSION, I.I_INDEX AS N_I_INDEX, I.N_ORDER_NUM, "
+         + "P.ID AS P_ID, P.NAME AS P_NAME, P.VERSION AS P_VERSION, P.P_TYPE, P.P_MULTIVALUED, "
+         + "V.DATA, V.ORDER_NUM, V.STORAGE_DESC"
+         + " from JCR_MITEM I, JCR_MITEM P, JCR_MVALUE V where I.I_CLASS=1 and"
+         + " P.I_CLASS=2 and V.PROPERTY_ID=P.ID order by N_ID";
+
+   /**
+    * Constructor JdbcIndexingDataIterator.
+    * 
+    */
+   public JdbcNodeDataIndexingIterator(Connection jdbcConn, boolean multiDb, String containerName, FileCleaner swapCleaner,
+      int maxBufferSize, File swapDirectory, ValueStoragePluginProvider valueStorageProvider) throws SQLException,
+      PrimaryTypeNotFoundException, InvalidItemStateException, ValueStorageNotFoundException, IllegalNameException,
+      IOException
+   {
+      this.jdbcConn = jdbcConn;
+      this.multiDb = multiDb;
+      this.containerName = containerName;
+      this.swapCleaner = swapCleaner;
+      this.maxBufferSize = maxBufferSize;
+      this.swapDirectory = swapDirectory;
+      this.valueStorageProvider = valueStorageProvider;
+
+      String sql = multiDb ? FIND_NODES_MULTI_DB : FIND_NODES_SINGLE_DB;
+      st = jdbcConn.prepareStatement(sql);
+
+      if (!multiDb)
+      {
+         st.setString(1, containerName);
+         st.setString(2, containerName);
+      }
+      resultSet = st.executeQuery();
+
+      this.nextNode = readNext();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public boolean hasNext()
+   {
+      return this.nextNode != null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public NodeDataIndexing next() throws IOException
+   {
+      NodeDataIndexing current = this.nextNode;
+
+      try
+      {
+         this.nextNode = readNext();
+      }
+      catch (PrimaryTypeNotFoundException e)
+      {
+         throw new IOException(e);
+      }
+      catch (InvalidItemStateException e)
+      {
+         throw new IOException(e);
+      }
+      catch (ValueStorageNotFoundException e)
+      {
+         throw new IOException(e);
+      }
+      catch (SQLException e)
+      {
+         throw new IOException(e);
+      }
+      catch (IllegalNameException e)
+      {
+         throw new IOException(e);
+      }
+
+      return current;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void close() throws IOException
+   {
+      try
+      {
+         if (resultSet != null)
+         {
+            resultSet.close();
+         }
+
+         if (st != null)
+         {
+            st.close();
+         }
+         
+         if (findItemQPathByIdentifierCQ != null)
+         {
+            findItemQPathByIdentifierCQ.close();
+         }
+
+         jdbcConn.close();
+      }
+      catch (SQLException e)
+      {
+         throw new IOException(e);
+      }
+   }
+
+   /**
+    * Read next node from database. 
+    * 
+    * @return NodeDataIndexing 
+    */
+   private NodeDataIndexing readNext() throws PrimaryTypeNotFoundException, InvalidItemStateException,
+      ValueStorageNotFoundException, SQLException, IllegalNameException, IOException
+   {
+      while (resultSet.next())
+      {
+         if (data == null)
+         {
+            data = new TempNodeData(resultSet);
+            readTempPropertyData();
+         }
+         else if (!resultSet.getString("N_ID").equals(data.cid))
+         {
+            NodeDataIndexing node = createNodeData(data);
+
+            data = new TempNodeData(resultSet);
+            readTempPropertyData();
+
+            return node;
+         }
+         else
+         {
+            readTempPropertyData();
+         }
+      }
+
+      if (data != null)
+      {
+         NodeDataIndexing node = createNodeData(data);
+         data = null;
+
+         return node;
+      }
+
+      return null;
+   }
+
+   /**
+    * Read temporary property data.
+    * 
+    * @throws SQLException 
+    */
+   private void readTempPropertyData() throws SQLException
+   {
+      String key = resultSet.getString("P_NAME");
+
+      SortedSet<TempPropertyData> values = data.properties.get(key);
+      if (values == null)
+      {
+         values = new TreeSet<TempPropertyData>();
+         data.properties.put(key, values);
+      }
+
+      values.add(new TempPropertyData(resultSet));
+   }
+
+   /**
+    * Build node data and its properties data from temporary stored info.
+    * 
+    * @return NodeDataIndexing
+    */
+   private NodeDataIndexing createNodeData(TempNodeData tempNode) throws IllegalNameException,
+      InvalidItemStateException, SQLException, PrimaryTypeNotFoundException, IOException, ValueStorageNotFoundException
+   {
+      QPath parentPath;
+      String parentCid;
+
+      if (tempNode.cpid.equals(Constants.ROOT_PARENT_UUID))
+      {
+         // root node
+         parentPath = Constants.ROOT_PATH;
+         parentCid = null;
+      }
+      else
+      {
+         parentPath =
+            QPath.makeChildPath(traverseQPath(tempNode.cpid), InternalQName.parse(tempNode.cname), tempNode.cindex);
+         parentCid = tempNode.cpid;
+      }
+
+      // primary type
+      SortedSet<TempPropertyData> primaryTypeTempProp = tempNode.properties.get(Constants.JCR_PRIMARYTYPE.getAsString());
+      if (primaryTypeTempProp == null)
+      {
+         throw new PrimaryTypeNotFoundException("FATAL ERROR primary type record not found. Node "
+            + parentPath.getAsString() + ", id " + tempNode.cid + ", container " + this.containerName, null);
+      }
+
+      ByteArrayInputStream ba = ((ByteArrayInputStream)primaryTypeTempProp.first().cdata);
+      byte[] data = new byte[ba.available()];
+      ba.read(data);
+
+      primaryTypeTempProp.first().cdata = new ByteArrayInputStream(data);
+
+      InternalQName ptName =
+         InternalQName.parse(new String((data != null ? data : new byte[]{}), Constants.DEFAULT_ENCODING));
+
+      // mixins
+      List<InternalQName> mixins = new ArrayList<InternalQName>();
+      Set<TempPropertyData> mixinsTempProps = tempNode.properties.get(Constants.JCR_MIXINTYPES.getAsString());
+      if (mixinsTempProps != null)
+      {
+
+         for (TempPropertyData mxnb : mixinsTempProps)
+         {
+            ba = ((ByteArrayInputStream)mxnb.cdata);
+            data = new byte[ba.available()];
+            ba.read(data);
+
+            mxnb.cdata = new ByteArrayInputStream(data);
+
+            mixins.add(InternalQName.parse(new String(data, Constants.DEFAULT_ENCODING)));
+         }
+      }
+
+      // build node data
+      NodeData nodeData =
+         new PersistedNodeData(getIdentifier(tempNode.cid), parentPath, getIdentifier(parentCid), tempNode.cversion,
+            tempNode.cnordernumb, ptName, mixins.toArray(new InternalQName[mixins.size()]), null);
+
+      List<PropertyData> childProps = new ArrayList<PropertyData>();
+
+      for (String propName : tempNode.properties.keySet())
+      {
+         TempPropertyData prop = tempNode.properties.get(propName).first();
+         String identifier = getIdentifier(prop.cid);
+
+         // read values
+         List<ValueData> valueData = new ArrayList<ValueData>();
+         for (TempPropertyData tempProp : tempNode.properties.get(propName))
+         {
+            ValueData vdata =
+               tempProp.cstorage_desc == null ? readValueData(tempProp.cid, tempProp.corderNum, tempProp.cversion,
+                  tempProp.cdata) : readValueData(identifier, tempProp.corderNum, tempProp.cstorage_desc);
+
+            valueData.add(vdata);
+         }
+         Collections.sort(valueData, COMPARATOR_VALUE_DATA);
+
+         QPath qpath = QPath.makeChildPath(parentPath, InternalQName.parse(prop.cname));
+
+         // build property data
+         PropertyData pdata =
+            new PersistedPropertyData(identifier, qpath, tempNode.cid, prop.cversion, prop.ctype, prop.cmulti,
+               valueData);
+
+         childProps.add(pdata);
+      }
+
+      return new NodeDataIndexing(nodeData, childProps);
+   }
+
+   /**
+    * Build Item path by id.
+    * 
+    * @param cpid
+    *          - Item id (container id)
+    * @return Item QPath
+    * @throws SQLException
+    *           - if database error occurs
+    * @throws InvalidItemStateException
+    *           - if parent not found
+    * @throws IllegalNameException
+    *           - if name on the path is wrong
+    */
+   private QPath traverseQPath(String cpid) throws SQLException, InvalidItemStateException, IllegalNameException
+   {
+      String id = getIdentifier(cpid);
+      if (id.equals(Constants.ROOT_UUID))
+      {
+         return Constants.ROOT_PATH;
+      }
+
+      // get item by Identifier usecase
+      List<QPathEntry> qrpath = new ArrayList<QPathEntry>(); // reverted path
+      String caid = cpid; // container ancestor id
+      boolean isRoot = false;
+      do
+      {
+         ResultSet result = null;
+         try
+         {
+            result = findItemQPathByIdentifier(caid);
+            if (!result.next())
+               throw new InvalidItemStateException("Parent not found, uuid: " + getIdentifier(caid));
+
+            QPathEntry qpe1 =
+               new QPathEntry(InternalQName.parse(result.getString(COLUMN_NAME)), result.getInt(COLUMN_INDEX));
+            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));
+               if (isChild)
+               {
+                  // The child is the first result then we have the parent
+                  qrpath.add(qpe1);
+                  qrpath.add(qpe2);
+                  // We need to take the value of the parent node
+                  caid = result.getString(COLUMN_PARENTID);
+               }
+               else
+               {
+                  // The parent is the first result then we have the child
+                  qrpath.add(qpe2);
+                  qrpath.add(qpe1);
+               }
+            }
+            else
+            {
+               qrpath.add(qpe1);
+            }
+         }
+         finally
+         {
+            if (result != null)
+            {
+               try
+               {
+                  result.close();
+               }
+               catch (SQLException e)
+               {
+                  LOG.error("Can't close the ResultSet: " + e);
+               }
+            }
+         }
+
+         if (caid.equals(Constants.ROOT_PARENT_UUID) || (id = getIdentifier(caid)).equals(Constants.ROOT_UUID))
+         {
+            if (id.equals(Constants.ROOT_UUID))
+            {
+               qrpath.add(Constants.ROOT_PATH.getEntries()[0]);
+            }
+            isRoot = true;
+         }
+      }
+      while (!isRoot);
+
+      QPathEntry[] qentries = new QPathEntry[qrpath.size()];
+      int qi = 0;
+      for (int i = qrpath.size() - 1; i >= 0; i--)
+      {
+         qentries[qi++] = qrpath.get(i);
+      }
+      return new QPath(qentries);
+   }
+
+   /**
+    * Invoke item identifier from internalId. In case of single db need to
+    * remove prefix from internalId.
+    * 
+    * @param internalId
+    *          the internal identifier
+    */
+   private String getIdentifier(final String internalId)
+   {
+      if (internalId == null)
+         return null;
+
+      return multiDb ? internalId : internalId.substring(containerName.length());
+   }
+
+   /**
+    * 
+    * @param identifier
+    * @return
+    * @throws SQLException
+    */
+   private ResultSet findItemQPathByIdentifier(String identifier) throws SQLException
+   {
+      String findItemQPathByIdentifier;
+      if (multiDb)
+      {
+         findItemQPathByIdentifier =
+            "select I.ID, I.PARENT_ID, I.NAME, I.I_INDEX"
+               + " from JCR_MITEM I, (SELECT ID, PARENT_ID from JCR_MITEM where ID=?) J"
+               + " where I.ID = J.ID or I.ID = J.PARENT_ID";
+      }
+      else
+      {
+         findItemQPathByIdentifier =
+            "select I.ID, I.PARENT_ID, I.NAME, I.I_INDEX"
+               + " from JCR_SITEM I, (SELECT ID, PARENT_ID from JCR_SITEM where ID=?) J"
+               + " where I.ID = J.ID or I.ID = J.PARENT_ID";
+      }
+
+      if (findItemQPathByIdentifierCQ == null)
+      {
+         findItemQPathByIdentifierCQ = jdbcConn.prepareStatement(findItemQPathByIdentifier);
+      }
+      else
+      {
+         findItemQPathByIdentifierCQ.clearParameters();
+      }
+
+      findItemQPathByIdentifierCQ.setString(1, identifier);
+      return findItemQPathByIdentifierCQ.executeQuery();
+   }
+
+   /**
+    * Read ValueData from database.
+    * 
+    * @param cid
+    *          property id
+    * @param orderNumber
+    *          value order number
+    * @param version
+    *          persistent version (used for BLOB swapping)
+    * @param content
+    *          input stream
+    * @return ValueData
+    * @throws SQLException
+    *           database error
+    * @throws IOException
+    *           I/O error (swap)
+    */
+   private ValueData readValueData(String cid, int orderNumber, int version, final InputStream content)
+      throws SQLException, IOException
+   {
+
+      byte[] buffer = new byte[0];
+      byte[] spoolBuffer = new byte[ValueFileIOHelper.IOBUFFER_SIZE];
+      int read;
+      int len = 0;
+      OutputStream out = null;
+
+      SwapFile swapFile = null;
+      try
+      {
+         // stream from database
+         if (content != null)
+            while ((read = content.read(spoolBuffer)) >= 0)
+            {
+               if (out != null)
+               {
+                  // spool to temp file
+                  out.write(spoolBuffer, 0, read);
+                  len += read;
+               }
+               else if (len + read > maxBufferSize)
+               {
+                  // threshold for keeping data in memory exceeded;
+                  // create temp file and spool buffer contents
+                  swapFile = SwapFile.get(swapDirectory, cid + orderNumber + "." + version);
+                  if (swapFile.isSpooled())
+                  {
+                     // break, value already spooled
+                     buffer = null;
+                     break;
+                  }
+                  out = PrivilegedFileHelper.fileOutputStream(swapFile);
+                  out.write(buffer, 0, len);
+                  out.write(spoolBuffer, 0, read);
+                  buffer = null;
+                  len += read;
+               }
+               else
+               {
+                  // reallocate new buffer and spool old buffer contents
+                  byte[] newBuffer = new byte[len + read];
+                  System.arraycopy(buffer, 0, newBuffer, 0, len);
+                  System.arraycopy(spoolBuffer, 0, newBuffer, len, read);
+                  buffer = newBuffer;
+                  len += read;
+               }
+            }
+      }
+      finally
+      {
+         if (out != null)
+         {
+            out.close();
+            swapFile.spoolDone();
+         }
+      }
+
+      if (buffer == null)
+      {
+         return new CleanableFilePersistedValueData(orderNumber, swapFile, swapCleaner);
+      }
+
+      return new ByteArrayPersistedValueData(orderNumber, buffer);
+   }
+
+   /**
+    * Read ValueData from external storage.
+    * 
+    * @param identifier
+    *          property identifier
+    * @param orderNumber
+    *          value order number
+    * @param storageId
+    *          external Value storage id
+    * @return ValueData
+    * @throws SQLException
+    *           database error
+    * @throws IOException
+    *           I/O error
+    * @throws ValueStorageNotFoundException
+    *           if no such storage found with Value storageId
+    */
+   private ValueData readValueData(String identifier, int orderNumber, String storageId) throws SQLException,
+      IOException, ValueStorageNotFoundException
+   {
+      ValueIOChannel channel = valueStorageProvider.getChannel(storageId);
+      try
+      {
+         return channel.read(identifier, orderNumber, maxBufferSize);
+      }
+      finally
+      {
+         channel.close();
+      }
+   }
+
+   /**
+    * The comparator used to sort the value data
+    */
+   private static Comparator<ValueData> COMPARATOR_VALUE_DATA = new Comparator<ValueData>()
+   {
+      public int compare(ValueData vd1, ValueData vd2)
+      {
+         return vd1.getOrderNumber() - vd2.getOrderNumber();
+      }
+   };
+
+   /**
+    * Class needed to store temporary node data. 
+    */
+   private class TempNodeData
+   {
+      String cid;
+
+      String cname;
+
+      int cversion;
+
+      String cpid;
+
+      int cindex;
+
+      int cnordernumb;
+
+      Map<String, SortedSet<TempPropertyData>> properties = new HashMap<String, SortedSet<TempPropertyData>>();
+
+      public TempNodeData(ResultSet item) throws SQLException
+      {
+         cid = item.getString("N_ID");
+         cname = item.getString("N_NAME");
+         cversion = item.getInt("N_VERSION");
+         cpid = item.getString("N_PARENT_ID");
+         cindex = item.getInt("N_I_INDEX");
+         cnordernumb = item.getInt("N_ORDER_NUM");
+      }
+   }
+
+   /**
+    * Class needs to store temporary property data.
+    */
+   private class TempPropertyData implements Comparable<TempPropertyData>
+   {
+      String cid;
+
+      String cname;
+
+      int cversion;
+
+      int ctype;
+
+      boolean cmulti;
+
+      int corderNum;
+
+      InputStream cdata;
+
+      String cstorage_desc;
+
+      public TempPropertyData(ResultSet item) throws SQLException
+      {
+         cid = item.getString("P_ID");
+         cname = item.getString("P_NAME");
+         cversion = item.getInt("P_VERSION");
+         ctype = item.getInt("P_TYPE");
+         cmulti = item.getBoolean("P_MULTIVALUED");
+         cdata = item.getBinaryStream(COLUMN_VDATA);
+         cstorage_desc = item.getString(COLUMN_VSTORAGE_DESC);
+         corderNum = item.getInt(COLUMN_VORDERNUM);
+      }
+
+      public int compareTo(TempPropertyData o)
+      {
+         return corderNum - o.corderNum;
+      }
+   }
+}
+



More information about the exo-jcr-commits mailing list