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

do-not-reply at jboss.org do-not-reply at jboss.org
Wed Oct 19 03:55:26 EDT 2011


Author: nzamosenchuk
Date: 2011-10-19 03:55:25 -0400 (Wed, 19 Oct 2011)
New Revision: 5067

Added:
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/AbstractRepositorySuspender.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLog.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLogWriter.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryCheckController.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainerChecker.java
   jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestInspectionLogFile.java
   jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestRepositoryCheckController.java
Modified:
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryContainer.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositorySuspendController.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.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/lucene/SearchIndex.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/DBConstants.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/value/fs/FileIOChannel.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/value/ValueIOChannel.java
   jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java
Log:
EXOJCR-1471 : commit patch with comments added to the code.

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/AbstractRepositorySuspender.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/AbstractRepositorySuspender.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/AbstractRepositorySuspender.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl;
+
+import org.exoplatform.services.jcr.core.ManageableRepository;
+import org.exoplatform.services.jcr.core.security.JCRRuntimePermissions;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 4.10.2011 skarpenko $
+ *
+ */
+public abstract class AbstractRepositorySuspender
+{
+   /**
+    * The current repository.
+    */
+   private final ManageableRepository repository;
+
+   /**
+    * AbstractRepositorySuspender constructor.
+    */
+   public AbstractRepositorySuspender(ManageableRepository repository)
+   {
+      this.repository = repository;
+   }
+
+   /**
+    * Suspend repository which means that allow only read operations. 
+    * All writing threads will wait until resume operations invoked.
+    */
+   protected void suspendRepository() throws RepositoryException
+   {
+      // Need privileges to manage repository.
+      SecurityManager security = System.getSecurityManager();
+      if (security != null)
+      {
+         security.checkPermission(JCRRuntimePermissions.MANAGE_REPOSITORY_PERMISSION);
+      }
+      repository.setState(ManageableRepository.SUSPENDED);
+   }
+
+   /**
+    * Resume repository. All previously suspended threads continue working.
+    */
+   protected void resumeRepository() throws RepositoryException
+   {
+      // Need privileges to manage repository.
+      SecurityManager security = System.getSecurityManager();
+      if (security != null)
+      {
+         security.checkPermission(JCRRuntimePermissions.MANAGE_REPOSITORY_PERMISSION);
+      }
+      repository.setState(ManageableRepository.ONLINE);
+   }
+
+   /**
+    * Returns repository state title.
+    */
+   protected String getRepositoryStateTitle()
+   {
+      return repository.getStateTitle();
+   }
+
+   /**
+    * Returns repository state.
+    */
+   protected int getRepositoryState()
+   {
+      return repository.getState();
+   }
+
+}


Property changes on: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/AbstractRepositorySuspender.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLog.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLog.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLog.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl;
+
+import java.io.IOException;
+
+/**
+ * Interface of inspection log. It provides general methods for logging consistency issues.  
+ * 
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 4.10.2011 skarpenko $
+ *
+ */
+public interface InspectionLog
+{
+   // represents broken object state
+   public enum InspectionStatus {
+      ERR("Error"), WARN("Warning"), REINDEX("Reindex");
+      final String text;
+
+      InspectionStatus(String text)
+      {
+         this.text = text;
+      }
+
+      public String toString()
+      {
+         return text;
+      }
+   }
+
+   /**
+    * @return true, if inconsistency was found
+    */
+   boolean hasInconsistency();
+
+   /**
+    * @return true, if inconsistency or warning was found
+    */
+   boolean hasWarnings();
+
+   /**
+    * Adds comment to log
+    */
+   void logComment(String message) throws IOException;
+
+   /**
+    * Adds description to log
+    */
+   void logInspectionDescription(String description) throws IOException;
+
+   /**
+    * Adds detailed event to log, with issue found
+    */
+   void logBrokenObjectInfo(String brokenObjectDesc, String comment, InspectionStatus status) throws IOException;
+
+   /**
+    * Adds exception with full trace to the log
+    */
+   void logException(String message, Exception ex) throws IOException;
+}


Property changes on: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLog.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLogWriter.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLogWriter.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLogWriter.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Text-based inspection log implementation. It uses any compatible Writer instance for output.
+ * 
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 6.10.2011 skarpenko $
+ *
+ */
+public class InspectionLogWriter implements InspectionLog
+{
+   private static final String LINE_COMMENT = "//";
+
+   private static final String LINE_DELIMITER = "\n";
+
+   private static final String WSP = " ";
+
+   private final Writer out;
+
+   private final Set<InspectionStatus> statusSet = new HashSet<InspectionStatus>();
+
+   public InspectionLogWriter(Writer out)
+   {
+      this.out = out;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public boolean hasInconsistency()
+   {
+      return statusSet.contains(InspectionStatus.ERR) || statusSet.contains(InspectionStatus.REINDEX);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public boolean hasWarnings()
+   {
+      return statusSet.contains(InspectionStatus.WARN);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void logComment(String message) throws IOException
+   {
+      writeLine(message);
+      out.flush();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void logInspectionDescription(String description) throws IOException
+   {
+      writeLine(description);
+      out.flush();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void logBrokenObjectInfo(String brokenObjectDesc, String comment, InspectionStatus status) throws IOException
+   {
+      statusSet.add(status);
+
+      out.write(status.toString());
+      out.write(WSP);
+      out.write(brokenObjectDesc);
+      out.write(WSP);
+      out.write(comment);
+      out.write(LINE_DELIMITER);
+      out.flush();
+   }
+
+   public void logException(String message, Exception ex) throws IOException
+   {
+      statusSet.add(InspectionStatus.ERR);
+
+      writeLine(message);
+      writeStackTrace(ex);
+      out.flush();
+   }
+
+   private void writeLine(String message) throws IOException
+   {
+      out.write(LINE_COMMENT);
+      out.write(message);
+      out.write(LINE_DELIMITER);
+   }
+
+   private void writeStackTrace(Throwable e) throws IOException
+   {
+      writeLine(e.getMessage());
+      writeLine(e.toString());
+      StackTraceElement[] trace = e.getStackTrace();
+      for (int i = 0; i < trace.length; i++)
+      {
+         writeLine("\tat " + trace[i]);
+      }
+
+      Throwable ourCause = e.getCause();
+      if (ourCause != null)
+      {
+         writeLine("Cause:");
+         writeStackTrace(ourCause);
+      }
+   }
+}


Property changes on: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/InspectionLogWriter.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryCheckController.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryCheckController.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryCheckController.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl;
+
+import org.exoplatform.commons.utils.PrivilegedFileHelper;
+import org.exoplatform.management.annotations.Managed;
+import org.exoplatform.management.annotations.ManagedDescription;
+import org.exoplatform.management.jmx.annotations.NameTemplate;
+import org.exoplatform.management.jmx.annotations.Property;
+import org.exoplatform.services.jcr.core.ManageableRepository;
+import org.exoplatform.services.jcr.impl.core.query.SearchManager;
+import org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer;
+import org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainerChecker;
+import org.exoplatform.services.jcr.storage.value.ValueStoragePluginProvider;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.picocontainer.Startable;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Repository check controller allows check jcr repository consistency:
+ * <ul>
+ *  <li>Check DB consistency</li>
+ *  <li>Check value storage</li>
+ *  <li>Check index</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 3.10.2011 skarpenko $
+ */
+ at Managed
+ at NameTemplate(@Property(key = "service", value = "RepositoryCheckController"))
+public class RepositoryCheckController extends AbstractRepositorySuspender implements Startable
+{
+   /**
+    * Logger.
+    */
+   protected static Log LOG = ExoLogger.getLogger("exo.jcr.component.core.RepositorySuspendController");
+
+   protected static final String FILE_NAME = "report";
+
+   protected class InspectorThread extends Thread
+   {
+      private final DataStorage[] checkData;
+
+      InspectorThread(DataStorage[] checkData)
+      {
+         super();
+         this.checkData = checkData;
+         this.setDaemon(true);
+      }
+
+      /**
+       * @see java.lang.Runnable#run()
+       */
+      @Override
+      public void run()
+      {
+         String result = checkRepositoryDataConsistency(checkData);
+         inspectionFinished(result);
+      }
+   }
+
+   protected enum DataStorage {
+      DB, VALUE_STORAGE, LUCENE_INDEX
+   };
+
+   private InspectorThread inspectorThread = null;
+
+   private File inspectionLogFile = null;
+
+   private String lastResult = null;
+
+   /**
+    * The current repository.
+    */
+   private final ManageableRepository repository;
+
+   /**
+    * RepositoryCheckController constructor.
+    */
+   public RepositoryCheckController(ManageableRepository repository)
+   {
+      super(repository);
+      this.repository = repository;
+   }
+
+   /**
+    * This method will make next steps:
+    * <ul>
+    *  <li>Suspend repository</li>
+    *  <li>Check DB consistency</li>
+    *  <li>Check value storage</li>
+    *  <li>Check index</li>
+    *  <li>Resume repository</li>
+    * </ul>
+    * 
+    * @return String check consistency report
+    */
+   @Managed
+   @ManagedDescription("Check repository data consistency. DB data, value storage and lucene index will be checked."
+      + "All writing threads will wait until check become finished.")
+   public String checkRepositoryDataConsistency()
+   {
+      return startInspectionInThread(new DataStorage[]{DataStorage.DB, DataStorage.VALUE_STORAGE,
+         DataStorage.LUCENE_INDEX});
+   }
+
+   @Managed
+   @ManagedDescription("Check repository database consistency."
+      + "All writing threads will wait until check become finished.")
+   public String checkRepositoryDataBaseConsistency()
+   {
+      return startInspectionInThread(new DataStorage[]{DataStorage.DB});
+   }
+
+   @Managed
+   @ManagedDescription("Check repository value storage consistency."
+      + "All writing threads will wait until check become finished.")
+   public String checkRepositoryValueStorageConsistency()
+   {
+      return startInspectionInThread(new DataStorage[]{DataStorage.VALUE_STORAGE});
+   }
+
+   @Managed
+   @ManagedDescription("Check repository search index consistency."
+      + "All writing threads will wait until check become finished.")
+   public String checkRepositorySearchIndexConsistency()
+   {
+      return startInspectionInThread(new DataStorage[]{DataStorage.LUCENE_INDEX});
+   }
+
+   @Managed
+   @ManagedDescription("Get inspection status.")
+   public String getStatus()
+   {
+      if (inspectorThread != null)
+      {
+         return "Data consistency inspection in progress..";
+      }
+      else
+      {
+         return lastResult;
+      }
+   }
+
+   protected void inspectionFinished(String resultMessage)
+   {
+      this.lastResult = resultMessage;
+      inspectorThread = null;
+   }
+
+   protected synchronized String startInspectionInThread(DataStorage[] checkData)
+   {
+      if (inspectorThread == null)
+      {
+         inspectorThread = new InspectorThread(checkData);
+         inspectorThread.start();
+
+         return "Data consistency inspection started.";
+      }
+      else
+      {
+         return "Current inspection process is not finished.";
+      }
+   }
+
+   protected String checkRepositoryDataConsistency(DataStorage[] checkData)
+   {
+      inspectionLogFile = null;
+      try
+      {
+         if (getRepositoryState() == ManageableRepository.SUSPENDED)
+         {
+            return "Can not check data consistency. Repository is already suspended.";
+         }
+
+         Writer reportWriter = null;
+         try
+         {
+            try
+            {
+               suspendRepository();
+            }
+            catch (RepositoryException e)
+            {
+               return "Can not check data consistency. Repository was not suspended. Error: " + e.getMessage();
+            }
+
+            // DO CHECK 
+            inspectionLogFile =
+               new File(FILE_NAME + "-" + repository.getConfiguration().getName() + "-"
+                  + new SimpleDateFormat("dd-MMM-yy-HH-mm").format(new Date()) + ".txt");
+            if (!PrivilegedFileHelper.exists(inspectionLogFile)
+               && !PrivilegedFileHelper.createNewFile(inspectionLogFile))
+            {
+               LOG.error("Inspection log file was not created. "
+                  + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile));
+               return "Can not check data consistency. Inspection log file was not created. "
+                  + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+            }
+
+            reportWriter =
+               new BufferedWriter(new OutputStreamWriter(PrivilegedFileHelper.fileOutputStream(inspectionLogFile)));
+            InspectionLog report = new InspectionLogWriter(reportWriter);
+            for (DataStorage cd : checkData)
+            {
+               switch (cd)
+               {
+                  case DB :
+                     try
+                     {
+                        checkDB(report);
+                     }
+                     catch (RepositoryException e)
+                     {
+                        report.logException("RepositoryException occures during DB consistency check.", e);
+                        return "RepositoryException occures during DB consistency check. Error: " + e.getMessage()
+                           + ". See log here: " + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+                     }
+                     catch (IOException e)
+                     {
+                        report.logException("IOException occures during DB consistency check.", e);
+                        return "IOException occures during DB consistency check. Error: " + e.getMessage()
+                           + ". See log here: " + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+                     }
+                     break;
+                  case VALUE_STORAGE :
+                     try
+                     {
+                        checkVS(report);
+                     }
+                     catch (RepositoryException e)
+                     {
+                        report.logException("RepositoryException occures during ValueStorage consistency check.", e);
+                        return "RepositoryException occures during ValueStorage consistency check. Error: "
+                           + e.getMessage() + ". See log here: "
+                           + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+                     }
+                     catch (IOException e)
+                     {
+                        report.logException("IOException occures during ValueStorage consistency check.", e);
+                        return "IOException occures during ValueStorage consistency check. Error: " + e.getMessage()
+                           + ". See log here: " + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+                     }
+                     break;
+                  case LUCENE_INDEX :
+                     try
+                     {
+                        checkLuceneIndex(report);
+                     }
+                     catch (RepositoryException e)
+                     {
+                        report.logException("RepositoryException occures during SearchIndex consistency check.", e);
+                        return "RepositoryException occures during SearchIndex consistency check. Error: "
+                           + e.getMessage() + ". See log here: "
+                           + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+                     }
+                     catch (IOException e)
+                     {
+                        report.logException("IOException occures during SearchIndex consistency check.", e);
+                        return "IOException occures during SearchIndex consistency check. Error: " + e.getMessage()
+                           + ". See log here: " + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+                     }
+                     break;
+               }
+            }
+
+            if (report.hasInconsistency())
+            {
+               report.logComment("Repository data is NOT consistent.");
+               return "Repository data is inconsistent. See full report by path "
+                  + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+            }
+            else if (report.hasWarnings())
+            {
+               report.logComment("Repository data is consistent, except some warnings.");
+               return "Repository data is consistent, except some warnings. See full report by path "
+                  + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+            }
+            else
+            {
+               report.logComment("Repository data is consistent");
+               return "Repository data is consistent. See full report by path "
+                  + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile);
+            }
+         }
+         finally
+         {
+            if (reportWriter != null)
+            {
+               try
+               {
+                  reportWriter.flush();
+                  reportWriter.close();
+               }
+               catch (IOException e)
+               {
+                  LOG.error("Can not close file " + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile), e);
+               }
+            }
+
+            //resume repository
+            try
+            {
+               resumeRepository();
+            }
+            catch (RepositoryException e)
+            {
+               LOG.error("Can not resume repository. Error: " + e.getMessage(), e);
+            }
+            if (getRepositoryState() != ManageableRepository.ONLINE)
+            {
+               LOG.error("Repository was not resumed and now it is OFFLINE");
+            }
+         }
+      }
+      catch (Throwable e)
+      {
+         LOG.error(e.getMessage(), e);
+         return "Exception thrown during repository data validation: "
+            + e
+            + (inspectionLogFile != null ? " See log by path "
+               + PrivilegedFileHelper.getAbsolutePath(inspectionLogFile) : "");
+      }
+   }
+
+   private void checkDB(InspectionLog inspectionLog) throws RepositoryException, IOException
+   {
+      String[] wsNames = repository.getWorkspaceNames();
+      for (String wsName : wsNames)
+      {
+         inspectionLog.logComment("Check DB consistency. Workspace " + wsName);
+         JDBCWorkspaceDataContainer dataContainer =
+            (JDBCWorkspaceDataContainer)repository.getWorkspaceContainer(wsName).getComponent(
+               JDBCWorkspaceDataContainer.class);
+         JDBCWorkspaceDataContainerChecker.checkDB(dataContainer, inspectionLog);
+      }
+   }
+
+   private void checkVS(InspectionLog inspectionLog) throws RepositoryException, IOException
+   {
+      String[] wsNames = repository.getWorkspaceNames();
+      for (String wsName : wsNames)
+      {
+         inspectionLog.logComment("Check ValueStorage consistency. Workspace " + wsName);
+
+         JDBCWorkspaceDataContainer dataContainer =
+            (JDBCWorkspaceDataContainer)repository.getWorkspaceContainer(wsName).getComponent(
+               JDBCWorkspaceDataContainer.class);
+
+         ValueStoragePluginProvider vsPlugin =
+            (ValueStoragePluginProvider)repository.getWorkspaceContainer(wsName).getComponent(
+               ValueStoragePluginProvider.class);
+
+         JDBCWorkspaceDataContainerChecker.checkValueStorage(dataContainer, vsPlugin, inspectionLog);
+      }
+   }
+
+   private void checkLuceneIndex(InspectionLog inspectionLog) throws RepositoryException, IOException
+   {
+      final String[] wsNames = repository.getWorkspaceNames();
+      final String systemWS = repository.getConfiguration().getSystemWorkspaceName();
+      for (String wsName : wsNames)
+      {
+         inspectionLog.logComment("Check SearchIndex consistency. Workspace " + wsName);
+         SearchManager searchManager =
+            (SearchManager)repository.getWorkspaceContainer(wsName).getComponent(SearchManager.class);
+         searchManager.checkIndex(inspectionLog, systemWS.equals(wsName));
+      }
+   }
+
+   /**
+    * For test purposes.
+    * @return
+    */
+   protected File getLastLogFile()
+   {
+      return inspectionLogFile;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void start()
+   {
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void stop()
+   {
+      if (inspectorThread != null)
+      {
+         inspectorThread.interrupt();
+      }
+   }
+}


Property changes on: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryCheckController.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryContainer.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryContainer.java	2011-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryContainer.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -610,6 +610,7 @@
             {
 
                registerComponentImplementation(RepositorySuspendController.class);
+               registerComponentImplementation(RepositoryCheckController.class);
                registerComponentImplementation(IdGenerator.class);
 
                registerComponentImplementation(RepositoryIndexSearcherHolder.class);

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositorySuspendController.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositorySuspendController.java	2011-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/RepositorySuspendController.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -23,7 +23,6 @@
 import org.exoplatform.management.jmx.annotations.NameTemplate;
 import org.exoplatform.management.jmx.annotations.Property;
 import org.exoplatform.services.jcr.core.ManageableRepository;
-import org.exoplatform.services.jcr.core.security.JCRRuntimePermissions;
 import org.exoplatform.services.log.ExoLogger;
 import org.exoplatform.services.log.Log;
 import org.picocontainer.Startable;
@@ -38,14 +37,9 @@
  */
 @Managed
 @NameTemplate(@Property(key = "service", value = "RepositorySuspendController"))
-public class RepositorySuspendController implements Startable
+public class RepositorySuspendController extends AbstractRepositorySuspender implements Startable
 {
    /**
-    * The current repository.
-    */
-   private final ManageableRepository repository;
-
-   /**
     * Logger.
     */
    protected static Log log = ExoLogger.getLogger("exo.jcr.component.core.RepositorySuspendController");
@@ -55,7 +49,7 @@
     */
    public RepositorySuspendController(ManageableRepository repository)
    {
-      this.repository = repository;
+      super(repository);
    }
 
    /**
@@ -69,23 +63,15 @@
             "All writing threads will wait until resume operations invoked.")
    public String suspend()
    {
-      // Need privileges to manage repository.
-      SecurityManager security = System.getSecurityManager();
-      if (security != null)
-      {
-         security.checkPermission(JCRRuntimePermissions.MANAGE_REPOSITORY_PERMISSION);
-      }
-
       try
       {
-         repository.setState(ManageableRepository.SUSPENDED);
+         suspendRepository();
       }
       catch (RepositoryException e)
       {
          log.error(e);
       }
-
-      return getState();
+      return getRepositoryStateTitle();
    }
 
    /**
@@ -97,23 +83,15 @@
    @ManagedDescription("Resume repository. All previously suspended threads continue working.")
    public String resume()
    {
-      // Need privileges to manage repository.
-      SecurityManager security = System.getSecurityManager();
-      if (security != null)
-      {
-         security.checkPermission(JCRRuntimePermissions.MANAGE_REPOSITORY_PERMISSION);
-      }
-
       try
       {
-         repository.setState(ManageableRepository.ONLINE);
+         resumeRepository();
       }
       catch (RepositoryException e)
       {
          log.error(e);
       }
-
-      return getState();
+      return getRepositoryStateTitle();
    }
 
    /**
@@ -123,7 +101,7 @@
    @ManagedDescription("Returns repository state.")
    public String getState()
    {
-      return repository.getStateTitle();
+      return getRepositoryStateTitle();
    }
 
    /**

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java	2011-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -18,7 +18,9 @@
 
 import org.apache.lucene.search.Query;
 import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.impl.InspectionLog;
 import org.exoplatform.services.jcr.impl.core.SessionDataManager;
 import org.exoplatform.services.jcr.impl.core.SessionImpl;
 import org.exoplatform.services.jcr.impl.core.query.lucene.ChangesHolder;
@@ -222,4 +224,17 @@
     */
    boolean isOnline();
 
+   /**
+    * Check index consistency. Iterator goes through index documents and check, does each document have
+    * according jcr-node. If <b>autoRepair</b> is true - all broken index-documents will be reindexed,
+    * and documents that do not have corresponding jcr-node will be removed.
+    * 
+    * @param itemStateManager
+    * @param isSystem
+    * @param inspectionLog
+    * @throws RepositoryException
+    * @throws IOException
+    */
+   void checkIndex(ItemDataConsumer itemStateManager, boolean isSystem, InspectionLog inspectionLog)
+      throws RepositoryException, IOException;
 }

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-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -22,6 +22,7 @@
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.WildcardQuery;
 import org.exoplatform.commons.utils.PrivilegedFileHelper;
+import org.exoplatform.commons.utils.SecurityHelper;
 import org.exoplatform.container.ExoContainerContext;
 import org.exoplatform.container.configuration.ConfigurationManager;
 import org.exoplatform.management.annotations.Managed;
@@ -48,6 +49,7 @@
 import org.exoplatform.services.jcr.datamodel.QPath;
 import org.exoplatform.services.jcr.datamodel.ValueData;
 import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.InspectionLog;
 import org.exoplatform.services.jcr.impl.backup.BackupException;
 import org.exoplatform.services.jcr.impl.backup.Backupable;
 import org.exoplatform.services.jcr.impl.backup.DataRestore;
@@ -88,6 +90,8 @@
 import java.io.Serializable;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -391,6 +395,78 @@
    }
 
    /**
+    * Check index consistency. Iterator goes through index documents and check, does each document have
+    * according jcr-node. If index is suspended then it will be temporary resumed, while check is running and suspended afterwards.
+	 */
+   public void checkIndex(final InspectionLog inspectionLog, final boolean isSystem) throws RepositoryException, IOException
+   { 
+	  
+      if (isSuspended)
+      {
+         try
+         {
+            SecurityHelper.doPrivilegedExceptionAction(new PrivilegedExceptionAction<Object>()
+            {
+               public Object run() throws RepositoryException, IOException
+               {
+                  // try resuming the workspace
+                  try
+                  {
+                     if (isSystem && parentSearchManager != null && parentSearchManager.isSuspended)
+                     {
+                        parentSearchManager.resume();
+                     }
+                     resume();
+                     
+                     handler.checkIndex(itemMgr, isSystem, inspectionLog);
+                     return null;
+                  }
+                  catch (ResumeException e)
+                  {
+                     throw new RepositoryException("Can not resume SearchManager for inspection purposes.", e);
+                  }
+                  finally
+                  {
+                     // safely return the state of the workspace
+                     try
+                     {
+                        suspend();
+                        if (isSystem && parentSearchManager != null && !parentSearchManager.isSuspended)
+                        {
+                           parentSearchManager.suspend();
+                        }
+                     }
+                     catch (SuspendException e)
+                     {
+                        log.error(e.getMessage(), e);
+                     }
+                  }
+               }
+            });
+         }
+         catch (PrivilegedActionException e)
+         {
+            Throwable ex = e.getCause();
+            if (ex instanceof RepositoryException)
+            {
+               throw (RepositoryException)ex;
+            }
+            else if (ex instanceof IOException)
+            {
+               throw (IOException)ex;
+            }
+            else
+            {
+               throw new RepositoryException(ex.getMessage(), ex);
+            }
+         }
+      }else{
+         // simply run checkIndex, if not suspended
+         handler.checkIndex(itemMgr, isSystem, inspectionLog);
+      }
+   }
+
+   /**
     * {@inheritDoc}
     */
    public Set<String> getFieldNames() throws IndexException

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-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -44,12 +44,15 @@
 import org.exoplatform.services.jcr.config.QueryHandlerParams;
 import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
 import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
+import org.exoplatform.services.jcr.dataflow.ItemDataTraversingVisitor;
 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;
+import org.exoplatform.services.jcr.impl.InspectionLog;
+import org.exoplatform.services.jcr.impl.InspectionLog.InspectionStatus;
 import org.exoplatform.services.jcr.impl.backup.ResumeException;
 import org.exoplatform.services.jcr.impl.backup.SuspendException;
 import org.exoplatform.services.jcr.impl.backup.Suspendable;
@@ -864,6 +867,127 @@
    }
 
    /**
+    * {@inheritDoc}
+    */
+   public void checkIndex(ItemDataConsumer itemStateManager, boolean isSystem, final InspectionLog inspectionLog)
+      throws RepositoryException, IOException
+   {
+
+      // The visitor, that performs item enumeration and checks if all nodes present in 
+      // persistent layer are indexed. Also collects the list of all indexed nodes
+      // to optimize the process of backward check, when index is traversed to find
+      // references to already deleted nodes
+      class ItemDataIndexConsistencyVisitor extends ItemDataTraversingVisitor
+      {
+         private final IndexReader indexReader;
+
+         private final Set<String> indexedNodes = new HashSet<String>();
+
+         /**
+          * @param dataManager
+          */
+         public ItemDataIndexConsistencyVisitor(ItemDataConsumer dataManager, IndexReader indexReader)
+         {
+            super(dataManager);
+            this.indexReader = indexReader;
+         }
+
+         /**
+          * {@inheritDoc}
+          */
+         @Override
+         protected void entering(PropertyData property, int level) throws RepositoryException
+         {
+            // ignore properties;
+         }
+
+         /**
+          * {@inheritDoc}
+          */
+         @Override
+         protected void entering(NodeData node, int level) throws RepositoryException
+         {
+            // process node uuids one-by-one
+            try
+            {
+               String uuid = node.getIdentifier();
+               TermDocs docs = indexReader.termDocs(new Term(FieldNames.UUID, uuid));
+
+               if (docs.next())
+               {
+                  indexedNodes.add(uuid);
+                  docs.doc();
+                  if (docs.next())
+                  {
+                     //multiple entries
+                     inspectionLog.logBrokenObjectInfo("ID=" + uuid, "Multiple entires.", InspectionStatus.REINDEX);
+                  }
+               }
+               else
+               {
+                  inspectionLog.logBrokenObjectInfo("ID=" + uuid, "Not indexed.", InspectionStatus.REINDEX);
+               }
+            }
+            catch (IOException e)
+            {
+               throw new RepositoryException(e.getMessage(), e);
+            }
+         }
+
+         @Override
+         protected void leaving(PropertyData property, int level) throws RepositoryException
+         {
+            // ignore properties
+         }
+
+         @Override
+         protected void leaving(NodeData node, int level) throws RepositoryException
+         {
+            // do nothing
+         }
+
+         @Override
+         protected void visitChildProperties(NodeData node) throws RepositoryException
+         {
+            //do nothing
+         }
+
+         public Set<String> getIndexedNodes()
+         {
+            return indexedNodes;
+         }
+      }
+
+      // check relation Persistent Layer -> Index
+      // If current workspace is system, then need to invoke reader correspondent to system index
+      IndexReader indexReader = getIndexReader(isSystem);
+      ItemData root = itemStateManager.getItemData(Constants.ROOT_UUID);
+      ItemDataIndexConsistencyVisitor visitor = new ItemDataIndexConsistencyVisitor(itemStateManager, indexReader);
+      root.accept(visitor);
+
+      Set<String> documentUUIDs = visitor.getIndexedNodes();
+
+      // check relation Index -> Persistent Layer
+      // find document that do not corresponds to real node
+      // iterate on documents one-by-one
+      for (int i = 0; i < indexReader.maxDoc(); i++)
+      {
+         if (indexReader.isDeleted(i))
+         {
+            continue;
+         }
+         final int currentIndex = i;
+         Document d = indexReader.document(currentIndex, FieldSelectors.UUID);
+         String uuid = d.get(FieldNames.UUID);
+         if (!documentUUIDs.contains(uuid))
+         {
+            inspectionLog.logBrokenObjectInfo("ID=" + uuid, "Document corresponds to removed node.",
+               InspectionStatus.REINDEX);
+         }
+      }
+   }
+
+   /**
     * @return the errorLogfileSize
     */
    public int getErrorLogfileSize()

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/DBConstants.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/DBConstants.java	2011-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/DBConstants.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -247,6 +247,11 @@
 
    // VALUE table
    /**
+    * PROPERTY_ID
+    */
+   protected static final String COLUMN_VPROPERTY_ID = "PROPERTY_ID";
+
+   /**
     * COLUMN_VDATA.
     */
    protected static final String COLUMN_VDATA = "DATA";
@@ -340,9 +345,8 @@
    /**
     * DB_DIALECTS.
     */
-   public final static String[] DB_DIALECTS =
-      {DB_DIALECT_GENERIC, DB_DIALECT_ORACLE, DB_DIALECT_ORACLEOCI, DB_DIALECT_PGSQL, DB_DIALECT_MYSQL,
-         DB_DIALECT_HSQLDB, DB_DIALECT_DB2, DB_DIALECT_DB2V8, DB_DIALECT_MSSQL, DB_DIALECT_SYBASE, DB_DIALECT_DERBY,
-         DB_DIALECT_MYSQL_UTF8, DB_DIALECT_INGRES, DB_DIALECT_H2};
+   public final static String[] DB_DIALECTS = {DB_DIALECT_GENERIC, DB_DIALECT_ORACLE, DB_DIALECT_ORACLEOCI,
+      DB_DIALECT_PGSQL, DB_DIALECT_MYSQL, DB_DIALECT_HSQLDB, DB_DIALECT_DB2, DB_DIALECT_DB2V8, DB_DIALECT_MSSQL,
+      DB_DIALECT_SYBASE, DB_DIALECT_DERBY, DB_DIALECT_MYSQL_UTF8, DB_DIALECT_INGRES, DB_DIALECT_H2};
 
 }

Added: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainerChecker.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainerChecker.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainerChecker.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.storage.jdbc;
+
+import org.exoplatform.commons.utils.SecurityHelper;
+import org.exoplatform.services.jcr.impl.InspectionLog;
+import org.exoplatform.services.jcr.impl.InspectionLog.InspectionStatus;
+import org.exoplatform.services.jcr.impl.storage.value.ValueDataNotFoundException;
+import org.exoplatform.services.jcr.impl.storage.value.ValueStorageNotFoundException;
+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.IOException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 14 жовт. 2011 skarpenko $
+ *
+ */
+public class JDBCWorkspaceDataContainerChecker
+{
+   protected static final Log LOG = ExoLogger.getLogger("exo.jcr.component.core.JDBCWorkspaceDataContainerChecker");
+
+   /**
+    * Check database.
+    * <p>
+    * Check that database is not broken, and all base relation between jcr-items are not corrupted.
+    * </p>
+    * 
+    * @param inspectionLog - log where inspection results will be placed
+    * @return InspectionLog
+    * @throws RepositoryException
+    * @throws IOException
+    */
+   public static void checkDB(JDBCWorkspaceDataContainer jdbcDataContainer, InspectionLog inspectionLog)
+      throws RepositoryException, IOException
+   {
+
+      /**
+       * Data class, contains a combination of SQL states, description, field names and status  
+       */
+      class InspectionQuery
+      {
+         /**
+          * SQL query that must be executed.
+          */
+         private final String statement;
+
+         /**
+          * Inspection query description.
+          */
+         private final String description;
+
+         /**
+          * Field names that must be showed in inspection log if something wrong.
+          */
+         private final String[] fieldNames;
+
+         /**
+          * Corruption status. Is it critical - <b>ERR</b>, or not - <b>WARN</b>.
+          */
+         private final InspectionStatus status;
+
+         public InspectionQuery(String statement, String[] fieldNames, String headerMessage, InspectionStatus status)
+         {
+            this.statement = statement;
+            this.description = headerMessage;
+            this.fieldNames = fieldNames;
+            this.status = status;
+         }
+
+         public String getStatement()
+         {
+            return statement;
+         }
+
+         public String getDescription()
+         {
+            return description;
+         }
+
+         public String[] getFieldNames()
+         {
+            return fieldNames;
+         }
+
+         public InspectionStatus getStatus()
+         {
+            return status;
+         }
+      }
+
+      Set<InspectionQuery> queries = new HashSet<InspectionQuery>();
+
+      // preload queries
+      queries.add(new InspectionQuery(jdbcDataContainer.multiDb
+         ? "select * from JCR_MITEM as I where NOT EXISTS(select * from JCR_MITEM AS P where P.ID = I.PARENT_ID)"
+         : "select * from JCR_SITEM as I where I.CONTAINER_NAME='" + jdbcDataContainer.containerName
+            + "' and NOT EXISTS(select * from JCR_SITEM AS P where P.ID = I.PARENT_ID)", new String[]{
+         DBConstants.COLUMN_ID, DBConstants.COLUMN_PARENTID, DBConstants.COLUMN_NAME, DBConstants.COLUMN_CLASS},
+         "Items that do not have parent nodes", InspectionStatus.ERR));
+      queries
+         .add(new InspectionQuery(
+            jdbcDataContainer.multiDb
+               ? "select * from JCR_MITEM as N where N.I_CLASS=1 and NOT EXISTS (select * from JCR_MITEM AS P where P.I_CLASS=2 and P.PARENT_ID=N.ID)"
+               : "select * from JCR_SITEM as N where N.CONTAINER_NAME='"
+                  + jdbcDataContainer.containerName
+                  + "' and N.I_CLASS=1 and NOT EXISTS (select * from JCR_SITEM AS P where P.I_CLASS=2 and P.PARENT_ID=N.ID)",
+            new String[]{DBConstants.COLUMN_ID, DBConstants.COLUMN_PARENTID, DBConstants.COLUMN_NAME},
+            "Nodes that do not have at least one property", InspectionStatus.ERR));
+      queries
+         .add(new InspectionQuery(
+            jdbcDataContainer.multiDb
+               ? "select * from JCR_MVALUE as V where NOT EXISTS(select * from JCR_MITEM as P where V.PROPERTY_ID = P.ID and P.I_CLASS=2)"
+               : "select * from JCR_SVALUE as V where NOT EXISTS(select * from JCR_SITEM as P where P.CONTAINER_NAME='"
+                  + jdbcDataContainer.containerName + "' and V.PROPERTY_ID = P.ID and P.I_CLASS=2)", new String[]{
+               DBConstants.COLUMN_ID, DBConstants.COLUMN_VPROPERTY_ID},
+            "All value records that has not owner-property record", InspectionStatus.ERR));
+      queries
+         .add(new InspectionQuery(
+            jdbcDataContainer.multiDb
+               ? "select * from JCR_MITEM as P where P.I_CLASS=2 and NOT EXISTS( select * from JCR_MVALUE as V where V.PROPERTY_ID=P.ID)"
+               : "select * from JCR_SITEM as P where P.CONTAINER_NAME='" + jdbcDataContainer.containerName
+                  + "' and P.I_CLASS=2 and NOT EXISTS( select * from JCR_SVALUE as V where V.PROPERTY_ID=P.ID)",
+            new String[]{DBConstants.COLUMN_ID, DBConstants.COLUMN_PARENTID, DBConstants.COLUMN_NAME},
+            "All properties that have not value record.", InspectionStatus.WARN));
+      queries
+         .add(new InspectionQuery(
+            jdbcDataContainer.multiDb
+               ? "select * from JCR_MVALUE where (STORAGE_DESC is null and DATA is null) or (STORAGE_DESC is not null and DATA is not null)"
+               : "select * from JCR_SVALUE where (STORAGE_DESC is null and DATA is null) or (STORAGE_DESC is not null and DATA is not null)",
+            new String[]{DBConstants.COLUMN_ID}, "Incorrect JCR_VALUE records", InspectionStatus.ERR));
+      queries
+         .add(new InspectionQuery(
+            jdbcDataContainer.multiDb
+               ? "select * from JCR_MITEM AS P where P.P_TYPE=9 and NOT EXISTS( select * from JCR_MREF AS R where P.ID=R.PROPERTY_ID)"
+               : "select * from JCR_SITEM AS P where P.CONTAINER_NAME='" + jdbcDataContainer.containerName
+                  + "' and P.P_TYPE=9 and NOT EXISTS( select * from JCR_SREF AS R where P.ID=R.PROPERTY_ID)",
+            new String[]{DBConstants.COLUMN_ID, DBConstants.COLUMN_PARENTID, DBConstants.COLUMN_NAME},
+            "Reference properties without reference records", InspectionStatus.ERR));
+
+      // properties can refer to missing node. It is possible to perform this usecase via JCR API with no exceptions 
+      queries.add(new InspectionQuery(jdbcDataContainer.multiDb
+         ? "select * from JCR_MREF AS R where NOT EXISTS(select * from JCR_MITEM AS N where R.NODE_ID=N.ID)"
+         : "select * from JCR_SREF AS R where NOT EXISTS(select * from JCR_SITEM AS N where N.CONTAINER_NAME='"
+            + jdbcDataContainer.containerName + "' and R.NODE_ID=N.ID)", new String[]{"NODE_ID", "PROPERTY_ID",
+         DBConstants.COLUMN_VORDERNUM},
+         "Reference records that linked to unexisted nodes. Can be normal for some usecases.", InspectionStatus.WARN));
+
+      // using existing DataSource to get a JDBC Connection.
+      Connection jdbcConn = jdbcDataContainer.getConnectionFactory().getJdbcConnection();
+
+      try
+      {
+         // perform all queries on-by-one
+         for (InspectionQuery query : queries)
+         {
+            PreparedStatement st = null;
+            ResultSet resultSet = null;
+            try
+            {
+               st = jdbcConn.prepareStatement(query.getStatement());
+               // the result of query is expected to be empty
+               resultSet = st.executeQuery();
+               if (resultSet.next())
+               {
+                  // but if result not empty, then inconsistency takes place
+                  inspectionLog.logInspectionDescription(query.getDescription());
+                  do
+                  {
+                     StringBuilder record = new StringBuilder();
+                     for (String fieldName : query.getFieldNames())
+                     {
+                        record.append(fieldName);
+                        record.append('=');
+                        if (fieldName.equals(DBConstants.COLUMN_NORDERNUM)
+                           || fieldName.equals(DBConstants.COLUMN_VORDERNUM))
+                        {
+                           record.append(resultSet.getInt(fieldName));
+                        }
+                        else
+                        {
+                           record.append(resultSet.getString(fieldName));
+                        }
+                        record.append(' ');
+                     }
+                     // log inconsistency issue.
+                     inspectionLog.logBrokenObjectInfo(record.toString(), "", query.getStatus());
+                  }
+                  while (resultSet.next());
+               }
+            }
+            // safely free resources
+            finally
+            {
+               if (resultSet != null)
+               {
+                  try
+                  {
+                     resultSet.close();
+                  }
+                  catch (SQLException e)
+                  {
+                     LOG.error(e.getMessage(), e);
+                  }
+               }
+               if (st != null)
+               {
+                  try
+                  {
+                     st.close();
+                  }
+                  catch (SQLException e)
+                  {
+                     LOG.error(e.getMessage(), e);
+                  }
+               }
+            }
+         }
+      }
+      catch (SQLException e)
+      {
+         // log unexpected exceptions to log
+         inspectionLog.logException("Exception during DB inspection.", e);
+      }
+      finally
+      {
+         // safely close connection
+         if (jdbcConn != null)
+         {
+            try
+            {
+               jdbcConn.close();
+            }
+            catch (SQLException e)
+            {
+               LOG.error(e.getMessage(), e);
+            }
+         }
+      }
+   }
+
+   /**
+    * Inspect ValueStorage. 
+    * <p>
+    * All ValueDatas that have storage description (that means, value data stored in value storage) will be inspected:
+    * <ul>
+    * <li> does value exists in value storage;</li>
+    * <li> is this value readable;</li>
+    * <ul>
+    *
+    * 
+    * @param vsPlugin - value storages
+    * @param inspectionLog - log where inspection results will be placed
+    * @return resulting InspectionLog
+    * @throws RepositoryException
+    * @throws IOException
+    */
+   public static void checkValueStorage(JDBCWorkspaceDataContainer jdbcDataContainer,
+      ValueStoragePluginProvider vsPlugin, InspectionLog inspectionLog) throws RepositoryException, IOException
+   {
+      final String valueRecordFormat = "ValueData[PROPERTY_ID=%s ORDER_NUM=%d STORAGE_DESC=%s]";
+
+      Connection connection = jdbcDataContainer.getConnectionFactory().getJdbcConnection();
+      PreparedStatement st = null;
+      ResultSet resultSet = null;
+      try
+      {
+         st =
+            connection.prepareStatement(jdbcDataContainer.multiDb
+               ? "SELECT PROPERTY_ID, ORDER_NUM, STORAGE_DESC from JCR_MVALUE where STORAGE_DESC is not null"
+               : "SELECT PROPERTY_ID, ORDER_NUM, STORAGE_DESC from JCR_SVALUE where STORAGE_DESC is not null");
+
+         resultSet = st.executeQuery();
+         // traverse all values, written to value storage
+         if (resultSet.next())
+         {
+            ValueIOChannel channel = null;
+            do
+            {
+               final String propertyId = resultSet.getString(DBConstants.COLUMN_VPROPERTY_ID);
+               final int orderNumber = resultSet.getInt(DBConstants.COLUMN_VORDERNUM);
+               final String storageDesc = resultSet.getString(DBConstants.COLUMN_VSTORAGE_DESC);
+
+               // don't acquire channel if it is already open 
+               if (channel == null || !channel.getStorageId().equals(storageDesc))
+               {
+                  try
+                  {
+                     if (channel != null)
+                     {
+                        channel.close();
+                     }
+                     channel = vsPlugin.getChannel(storageDesc);
+                  }
+                  catch (ValueStorageNotFoundException e)
+                  {
+                     inspectionLog.logBrokenObjectInfo("ValueStorage " + storageDesc + " not found. "
+                        + String.format(valueRecordFormat, propertyId, orderNumber, storageDesc), e.getMessage(),
+                        InspectionStatus.ERR);
+                     continue;
+                  }
+               }
+
+               try
+               {
+                  // check value data
+                  final ValueIOChannel vdChannel = channel;
+                  SecurityHelper.doPrivilegedExceptionAction(new PrivilegedExceptionAction<Object>()
+                  {
+                     public Object run() throws ValueDataNotFoundException, IOException
+                     {
+                        vdChannel.checkValueData(propertyId, orderNumber);
+                        return null;
+                     }
+                  });
+               }
+               // process exception thrown by checkValueData
+               catch (PrivilegedActionException e)
+               {
+                  Throwable ex = e.getCause();
+                  if (ex instanceof ValueDataNotFoundException)
+                  {
+                     inspectionLog.logBrokenObjectInfo(String.format(valueRecordFormat, propertyId, orderNumber,
+                        storageDesc)
+                        + " not found.", ex.getMessage(), InspectionStatus.ERR);
+                  }
+                  else if (ex instanceof IOException)
+                  {
+                     inspectionLog.logException(ex.getMessage(), (IOException)ex);
+                  }
+                  else
+                  {
+                     throw new RepositoryException(ex.getMessage(), ex);
+                  }
+               }
+            }
+            while (resultSet.next());
+         }
+      }
+      catch (SQLException e)
+      {
+         // log unexpceted exception
+         inspectionLog.logException("Exception during ValueStorage inspection.", e);
+      }
+      finally
+      {
+         // safely free resources
+         if (resultSet != null)
+         {
+            try
+            {
+               resultSet.close();
+            }
+            catch (SQLException e)
+            {
+               LOG.error(e.getMessage(), e);
+            }
+         }
+
+         if (st != null)
+         {
+            try
+            {
+               st.close();
+            }
+            catch (SQLException e)
+            {
+               LOG.error(e.getMessage(), e);
+            }
+         }
+
+         if (connection != null)
+         {
+            try
+            {
+               connection.close();
+            }
+            catch (SQLException e)
+            {
+               LOG.error(e.getMessage(), e);
+            }
+         }
+      }
+   }
+
+}


Property changes on: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCWorkspaceDataContainerChecker.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/value/fs/FileIOChannel.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/value/fs/FileIOChannel.java	2011-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/value/fs/FileIOChannel.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -19,6 +19,7 @@
 package org.exoplatform.services.jcr.impl.storage.value.fs;
 
 import org.exoplatform.services.jcr.datamodel.ValueData;
+import org.exoplatform.services.jcr.impl.storage.value.ValueDataNotFoundException;
 import org.exoplatform.services.jcr.impl.storage.value.ValueDataResourceHolder;
 import org.exoplatform.services.jcr.impl.storage.value.ValueOperation;
 import org.exoplatform.services.jcr.impl.storage.value.fs.operations.DeleteValues;
@@ -30,7 +31,9 @@
 import org.exoplatform.services.log.Log;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -166,6 +169,48 @@
    }
 
    /**
+    * {@inheritDoc}
+    */
+   public void checkValueData(String propertyId, int orderNumber) throws ValueDataNotFoundException, IOException
+   {
+      try
+      {
+         //check that file exists
+         File f = getFile(propertyId, orderNumber);
+         if (!f.exists())
+         {
+            throw new ValueDataNotFoundException("Value data of property with [id=" + propertyId + ", ordernum="
+               + orderNumber + "] do not exists.");
+         }
+         else
+         {
+            //check readability
+            InputStream is = new FileInputStream(f);
+            try
+            {
+               is.read();
+            }
+            finally
+            {
+               try
+               {
+                  is.close();
+               }
+               catch (IOException e)
+               {
+               }
+            }
+         }
+      }
+      catch (IOException e)
+      {
+         throw new ValueDataNotFoundException("Value data of property [id=" + propertyId + ", ordernum=" + orderNumber
+            + "] can not be read.");
+
+      }
+   }
+
+   /**
     * Makes storage file path by propertyId and order number.<br/>
     * 
     * @param propertyId

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/value/ValueIOChannel.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/value/ValueIOChannel.java	2011-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/storage/value/ValueIOChannel.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -19,6 +19,7 @@
 package org.exoplatform.services.jcr.storage.value;
 
 import org.exoplatform.services.jcr.datamodel.ValueData;
+import org.exoplatform.services.jcr.impl.storage.value.ValueDataNotFoundException;
 
 import java.io.IOException;
 
@@ -46,6 +47,16 @@
    ValueData read(String propertyId, int orderNumber, int maxBufferSize) throws IOException;
 
    /**
+    * Check ValueData. Check that value storage contain this value and value is readable.
+    * 
+    * @param propertyId - Property ID
+    * @param orderNumber - Property order number
+    * @throws ValueDataNotFoundException thrown if value data not exist or can not be read
+    * @throws IOException
+    */
+   void checkValueData(String propertyId, int orderNumber) throws ValueDataNotFoundException, IOException;
+
+   /**
     * Add or update Property value.
     * 
     * @param propertyId

Modified: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java	2011-10-18 13:35:56 UTC (rev 5066)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -17,7 +17,9 @@
 package org.exoplatform.services.jcr.api.core.query.lucene;
 
 import org.apache.lucene.search.Query;
+import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.impl.InspectionLog;
 import org.exoplatform.services.jcr.impl.core.SessionDataManager;
 import org.exoplatform.services.jcr.impl.core.SessionImpl;
 import org.exoplatform.services.jcr.impl.core.query.AbstractQueryHandler;
@@ -123,4 +125,14 @@
       // TODO Auto-generated method stub
       
    }
+
+   /**
+    * @see org.exoplatform.services.jcr.impl.core.query.QueryHandler#checkIndex(org.exoplatform.services.jcr.dataflow.ItemDataConsumer, boolean, InspectionLog)
+    */
+   @Override
+   public void checkIndex(ItemDataConsumer itemStateManager, boolean isSystem, InspectionLog inspectionLog) throws RepositoryException,
+      IOException
+   {
+      // do nothing
+   }
 }

Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestInspectionLogFile.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestInspectionLogFile.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestInspectionLogFile.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.commons.utils.PrivilegedFileHelper;
+import org.exoplatform.services.jcr.impl.InspectionLog.InspectionStatus;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 11 ����. 2011 skarpenko $
+ *
+ */
+public class TestInspectionLogFile extends TestCase
+{
+
+   private File f;
+
+   private Writer writer;
+
+   public void setUp() throws Exception
+   {
+      super.setUp();
+      f = File.createTempFile("testlog", "suf");
+      writer = new OutputStreamWriter(PrivilegedFileHelper.fileOutputStream(f));
+   }
+
+   public void tearDown() throws Exception
+   {
+      writer.close();
+      f.delete();
+      super.tearDown();
+   }
+
+   public void testLogComment() throws Exception
+   {
+      InspectionLog report = new InspectionLogWriter(writer);
+      report.logComment("test message");
+
+      // read file;
+      Reader reader = new FileReader(f);
+      BufferedReader br = new BufferedReader(reader);
+      String s = br.readLine();
+      br.close();
+      assertEquals("//test message", s);
+      assertFalse(report.hasInconsistency());
+   }
+
+   public void testLogInspectionDescription() throws Exception
+   {
+      InspectionLog report = new InspectionLogWriter(writer);
+      report.logInspectionDescription("description");
+
+      // read file;
+      Reader reader = new FileReader(f);
+      BufferedReader br = new BufferedReader(reader);
+      String s = br.readLine();
+      br.close();
+      assertEquals("//description", s);
+      assertFalse(report.hasInconsistency());
+   }
+
+   public void testLogBrokenObjectInfo() throws Exception
+   {
+      InspectionLog report = new InspectionLogWriter(writer);
+      report.logBrokenObjectInfo("broken object descr", "message", InspectionStatus.REINDEX);
+
+      // read file;
+      Reader reader = new FileReader(f);
+      BufferedReader br = new BufferedReader(reader);
+      String s = br.readLine();
+      br.close();
+
+      assertEquals("Reindex broken object descr message", s);
+      assertTrue(report.hasInconsistency());
+   }
+
+   public void testLogException() throws Exception
+   {
+      Exception e = new Exception("Exception message.");
+
+      InspectionLog report = new InspectionLogWriter(writer);
+      report.logException("message", e);
+
+      // read file;
+      Reader reader = new FileReader(f);
+      BufferedReader br = new BufferedReader(reader);
+      String s = br.readLine();
+      assertEquals("//message", s);
+      s = br.readLine();
+      assertEquals("//" + e.getMessage(), s);
+      s = br.readLine();
+      assertEquals("//" + e.toString(), s);
+      br.close();
+      assertTrue(report.hasInconsistency());
+   }
+
+}


Property changes on: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestInspectionLogFile.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestRepositoryCheckController.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestRepositoryCheckController.java	                        (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestRepositoryCheckController.java	2011-10-19 07:55:25 UTC (rev 5067)
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl;
+
+import org.exoplatform.services.jcr.BaseStandaloneTest;
+import org.exoplatform.services.jcr.impl.RepositoryCheckController.DataStorage;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+import javax.jcr.Node;
+
+/**
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 10.10.2011 skarpenko $
+ *
+ */
+public class TestRepositoryCheckController extends BaseStandaloneTest
+{
+
+   private RepositoryCheckController checkController;
+
+   /**
+    * @see org.exoplatform.services.jcr.BaseStandaloneTest#getRepositoryName()
+    */
+   @Override
+   protected String getRepositoryName()
+   {
+      String repName = System.getProperty("test.repository");
+      if (repName == null)
+      {
+         throw new RuntimeException(
+            "Test repository is undefined. Set test.repository system property "
+               + "(For maven: in project.properties: maven.junit.sysproperties=test.repository\ntest.repository=<rep-name>)");
+      }
+      return repName;
+
+   }
+
+   public void setUp() throws Exception
+   {
+      super.setUp();
+      checkController = new RepositoryCheckController(repositoryService.getRepository("db1"));
+   }
+
+   public void tearDown() throws Exception
+   {
+      File f = checkController.getLastLogFile();
+      if (f != null)
+      {
+         f.delete();
+      }
+      super.tearDown();
+   }
+
+   public void testDB()
+   {
+      String result = checkController.checkRepositoryDataConsistency(new DataStorage[]{DataStorage.DB});
+      System.out.println("\n\n\n\n\n\n"+result+"\n\n\n\n\n\n");
+      assertEquals("Repository data is consistent. See full report by path "
+         + checkController.getLastLogFile().getAbsolutePath(), result);
+   }
+
+   public void testValueStorage() throws Exception
+   {
+      File f = this.createBLOBTempFile(20);
+      InputStream is = new FileInputStream(f);
+      try
+      {
+         Node n = root.addNode("node");
+         n.setProperty("prop", is);
+
+         root.save();
+
+         String result = checkController.checkRepositoryDataConsistency(new DataStorage[]{DataStorage.VALUE_STORAGE});
+         assertEquals("Repository data is consistent. See full report by path "
+            + checkController.getLastLogFile().getAbsolutePath(), result);
+      }
+      finally
+      {
+         is.close();
+         f.delete();
+      }
+   }
+
+   public void testSearchIndex()
+   {
+      String result = checkController.checkRepositoryDataConsistency(new DataStorage[]{DataStorage.LUCENE_INDEX});
+      assertEquals("Repository data is consistent. See full report by path "
+         + checkController.getLastLogFile().getAbsolutePath(), result);
+   }
+
+   public void testAll()
+   {
+      String result =
+         checkController.checkRepositoryDataConsistency(new DataStorage[]{DataStorage.DB, DataStorage.VALUE_STORAGE,
+            DataStorage.LUCENE_INDEX});
+      System.out.println("\n\n\n\n\n\n"+result+"\n\n\n\n\n\n");
+      assertEquals("Repository data is consistent. See full report by path "
+         + checkController.getLastLogFile().getAbsolutePath(), result);
+   }
+}


Property changes on: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/TestRepositoryCheckController.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain



More information about the exo-jcr-commits mailing list