[exo-jcr-commits] exo-jcr SVN: r5709 - jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker.

do-not-reply at jboss.org do-not-reply at jboss.org
Wed Feb 29 03:24:58 EST 2012


Author: tolusha
Date: 2012-02-29 03:24:57 -0500 (Wed, 29 Feb 2012)
New Revision: 5709

Added:
   jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionQuery.java
   jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionQueryFilteredMultivaluedProperties.java
   jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionReport.java
   jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/RepositoryCheckController.java
Log:
EXOJCR-1762: auto-repair for VS and Lock inconsistency

Added: jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionQuery.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionQuery.java	                        (rev 0)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionQuery.java	2012-02-29 08:24:57 UTC (rev 5709)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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.checker;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * @author <a href="mailto:aplotnikov at exoplatform.com">Andrey Plotnikov</a>
+ * @version $Id: InspectionQuery.java 34360 16.02.2012 andrew.plotnikov $
+ */
+public class InspectionQuery
+{
+   /**
+    * SQL query that must be executed.
+    */
+   public String statement;
+
+   /**
+    * Inspection query description.
+    */
+   public String description;
+
+   /**
+    * Field names that must be showed in inspection log if something wrong.
+    */
+   public String[] fieldNames;
+
+   /**
+    * Data class, contains a combination of SQL states, description, field names and status  
+    */
+   public InspectionQuery(String statement, String[] fieldNames, String headerMessage)
+   {
+      this.statement = statement;
+      this.description = headerMessage;
+      this.fieldNames = fieldNames;
+   }
+
+   public String getStatement()
+   {
+      return statement;
+   }
+
+   public String getDescription()
+   {
+      return description;
+   }
+
+   public String[] getFieldNames()
+   {
+      return fieldNames;
+   }
+
+   /**
+    * Creates a PreparedStatement object for sending parameterized SQL statements to the database. 
+    * 
+    * @param connection
+    *          connection to workspace storage
+    * @return
+    *          a new default PreparedStatement object containing the pre-compiled SQL statement 
+    * @throws SQLException
+    *           if a database access error occurs or this method is called on a closed connection
+    */
+   public PreparedStatement prepareStatement(Connection connection) throws SQLException
+   {
+      return connection.prepareStatement(statement);
+   }
+
+}

Added: jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionQueryFilteredMultivaluedProperties.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionQueryFilteredMultivaluedProperties.java	                        (rev 0)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionQueryFilteredMultivaluedProperties.java	2012-02-29 08:24:57 UTC (rev 5709)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 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.checker;
+
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * @author <a href="mailto:aplotnikov at exoplatform.com">Andrey Plotnikov</a>
+ * @version $Id: InspectionQueryFilteredMultivaluedProperties.java 34360 16.02.2012 andrew.plotnikov $
+ */
+public class InspectionQueryFilteredMultivaluedProperties extends InspectionQuery
+{
+
+   /**
+    * {@inheritDoc}
+    */
+   public InspectionQueryFilteredMultivaluedProperties(String statement, String[] fieldNames, String headerMessage)
+   {
+      super(statement, fieldNames, headerMessage);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public PreparedStatement prepareStatement(Connection connection) throws SQLException
+   {
+      PreparedStatement preparedStatement = super.prepareStatement(connection);
+      preparedStatement.setBoolean(1, false);
+
+      return preparedStatement;
+   }
+
+}

Added: jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionReport.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionReport.java	                        (rev 0)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/InspectionReport.java	2012-02-29 08:24:57 UTC (rev 5709)
@@ -0,0 +1,170 @@
+/*
+ * 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.checker;
+
+import org.exoplatform.commons.utils.SecurityHelper;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.security.PrivilegedExceptionAction;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Text-based inspection log implementation.
+ * 
+ * @author <a href="mailto:skarpenko at exoplatform.com">Sergiy Karpenko</a>
+ * @version $Id: InspectionReport.java 34360 6.10.2011 skarpenko $
+ */
+public class InspectionReport
+{
+   private static final String COMMENT = "//";
+
+   private static final String DELIMITER = "\n";
+
+   private static final String WHITE_SPACE = " ";
+
+   private Writer writer;
+
+   private boolean reportHasInconsistency;
+
+   private String reportPath;
+
+   /**
+    * InspectionReport constructor.
+    */
+   public InspectionReport(String forRepository) throws IOException
+   {
+      final File reportFile =
+         new File("report-" + forRepository + "-" + new SimpleDateFormat("dd-MMM-yy-HH-mm").format(new Date()) + ".txt");
+
+      SecurityHelper.doPrivilegedIOExceptionAction(new PrivilegedExceptionAction<Void>()
+      {
+         public Void run() throws IOException
+         {
+            reportPath = reportFile.getAbsolutePath();
+            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(reportFile)));
+
+            return null;
+         }
+      });
+
+   }
+
+   /**
+    * Indicates if report has inconsistency info or not.
+    */
+   public boolean hasInconsistency()
+   {
+      return reportHasInconsistency;
+   }
+
+   /**
+    * Adds comment to log.
+    */
+   public void logComment(String message) throws IOException
+   {
+      writeLine(message);
+      writer.flush();
+   }
+
+   /**
+    * Adds description to log.
+    */
+   public void logDescription(String description) throws IOException
+   {
+      writeLine(description);
+      writer.flush();
+   }
+
+   /**
+    * Adds detailed event to log.
+    */
+   public void logBrokenObjectAndSetInconsistency(String brokenObject) throws IOException
+   {
+      setInconsistency();
+
+      writer.write(brokenObject);
+      writer.write(DELIMITER);
+      writer.flush();
+   }
+
+   /**
+    * Adds exception with full stack trace.
+    */
+   public void logExceptionAndSetInconsistency(String message, Throwable e) throws IOException
+   {
+      setInconsistency();
+
+      writeLine(message);
+      writeStackTrace(e);
+      writer.flush();
+   }
+
+   /**
+    * Closes report and frees all allocated resources. 
+    */
+   public void close() throws IOException
+   {
+      writer.close();
+   }
+
+   /**
+    * Returns the absolute path to report file. 
+    */
+   public String getReportPath()
+   {
+      return reportPath;
+   }
+
+   private void setInconsistency()
+   {
+      reportHasInconsistency = true;
+   }
+
+   private void writeLine(String message) throws IOException
+   {
+      writer.write(COMMENT);
+      writer.write(message);
+      writer.write(DELIMITER);
+      writer.flush();
+   }
+
+   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);
+      }
+   }
+}

Added: jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/RepositoryCheckController.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/RepositoryCheckController.java	                        (rev 0)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/checker/RepositoryCheckController.java	2012-02-29 08:24:57 UTC (rev 5709)
@@ -0,0 +1,385 @@
+/*
+ * 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.checker;
+
+import org.exoplatform.commons.utils.SecurityHelper;
+import org.exoplatform.management.annotations.Managed;
+import org.exoplatform.management.annotations.ManagedDescription;
+import org.exoplatform.management.annotations.ManagedName;
+import org.exoplatform.management.jmx.annotations.NameTemplate;
+import org.exoplatform.management.jmx.annotations.Property;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.core.ManageableRepository;
+import org.exoplatform.services.jcr.impl.AbstractRepositorySuspender;
+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.IOException;
+import java.security.PrivilegedAction;
+
+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: RepositoryCheckController.java 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.RepositoryCheckController");
+
+   public static final String REPORT_CONSISTENT_MESSAGE = "Repository data is consistent";
+
+   public static final String REPORT_NOT_CONSISTENT_MESSAGE = "Repository data is NOT consistent";
+
+   public static final String EXCEPTION_DURING_CHECKING_MESSAGE = "Exception occured during consistency checking";
+
+   public static final String CONFIRMATION_FAILED_MESSAGE =
+      "For starting auto-repair function please enter \"YES\" as method parameter";
+
+   /**
+    * The list of available storages for checking.
+    */
+   public enum DataStorage {
+      DB, VALUE_STORAGE, LUCENE_INDEX
+   };
+
+   /**
+    * Store the results of last checking.
+    */
+   protected InspectionReport lastReport;
+
+   /**
+    * RepositoryCheckController constructor.
+    */
+   public RepositoryCheckController(ManageableRepository repository)
+   {
+      super(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.")
+   public String checkAll()
+   {
+      return checkAndRepair(new DataStorage[]{DataStorage.DB, DataStorage.VALUE_STORAGE,
+         DataStorage.LUCENE_INDEX}, false);
+   }
+
+   @Managed
+   @ManagedDescription("Check repository database consistency.")
+   public String checkDataBase()
+   {
+      return checkAndRepair(new DataStorage[]{DataStorage.DB}, false);
+   }
+
+   @Managed
+   @ManagedDescription("Check repository value storage consistency.")
+   public String checkValueStorage()
+   {
+      return checkAndRepair(new DataStorage[]{DataStorage.VALUE_STORAGE}, false);
+   }
+
+   @Managed
+   @ManagedDescription("Check repository search index consistency.")
+   public String checkIndex()
+   {
+      return checkAndRepair(new DataStorage[]{DataStorage.LUCENE_INDEX}, false);
+   }
+
+   @Managed
+   @ManagedDescription("Auto-repair inconsistencies for value storage. "
+      + "Don't forget to backup your data first. Set parameter to \"YES\" for enabling auto-repair feature")
+   public String repairValueStorage(String confirmation)
+   {
+      if (confirmation.equalsIgnoreCase("YES"))
+      {
+         return checkAndRepair(new DataStorage[]{DataStorage.VALUE_STORAGE}, true);
+      }
+      else
+      {
+         return CONFIRMATION_FAILED_MESSAGE;
+      }
+   }
+
+   @Managed
+   @ManagedDescription("Auto-repair inconsistencies for database. "
+      + "Don't forget to backup your data first. Set parameter to \"YES\" for enabling auto-repair feature")
+   public String repairDataBase(String confirmation)
+   {
+      if (confirmation.equalsIgnoreCase("YES"))
+      {
+         return checkAndRepair(new DataStorage[]{DataStorage.DB}, true);
+      }
+      else
+      {
+         return CONFIRMATION_FAILED_MESSAGE;
+      }
+   }
+
+   public String checkAndRepair(final DataStorage[] storages, final boolean autoRepair)
+   {
+      return SecurityHelper.doPrivilegedAction(new PrivilegedAction<String>()
+      {
+         public String run()
+         {
+            return checkAndRepairAction(storages, autoRepair);
+         }
+      });
+   }
+
+   protected String checkAndRepairAction(DataStorage[] storages, boolean autoRepair)
+   {
+      try
+      {
+         createNewReport();
+      }
+      catch (IOException e)
+      {
+         return getExceptionDuringCheckingMessage(e);
+      }
+
+      try
+      {
+         suspendRepository();
+         
+         return doCheckAndRepair(storages, autoRepair);
+      }
+      catch (RepositoryException e)
+      {
+         return getExceptionDuringCheckingMessage(e);
+      }
+      finally
+      {
+         resumeRepository();
+         closeReport();
+      }
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   protected void resumeRepository()
+   {
+      try
+      {
+         super.resumeRepository();
+      }
+      catch (RepositoryException e)
+      {
+         LOG.error("Can not resume repository. Error: " + e.getMessage(), e);
+      }
+   }
+
+   private String doCheckAndRepair(DataStorage[] storages, boolean autoRepair)
+   {
+      try
+      {
+         for (DataStorage storage : storages)
+         {
+            switch (storage)
+            {
+               case DB :
+                  doCheckDataBase(autoRepair);
+                  break;
+
+               case VALUE_STORAGE :
+                  doCheckValueStorage(autoRepair);
+                  break;
+
+               case LUCENE_INDEX :
+                  doCheckIndex(autoRepair);
+                  break;
+            }
+         }
+
+         return logAndGetCheckingResultMessage();
+      }
+      catch (Throwable e)
+      {
+         return logAndGetExceptionDuringCheckingMessage(e);
+      }
+   }
+
+   private String logAndGetCheckingResultMessage()
+   {
+      if (lastReport.hasInconsistency())
+      {
+         logComment(REPORT_NOT_CONSISTENT_MESSAGE);
+         return REPORT_NOT_CONSISTENT_MESSAGE + getPathToReportMessage();
+      }
+      else
+      {
+         logComment(REPORT_CONSISTENT_MESSAGE);
+         return REPORT_CONSISTENT_MESSAGE + getPathToReportMessage();
+      }
+   }
+
+   private String logAndGetExceptionDuringCheckingMessage(Throwable e)
+   {
+      logExceptionAndSetInconsistency(EXCEPTION_DURING_CHECKING_MESSAGE, e);
+      return getExceptionDuringCheckingMessage(e) + getPathToReportMessage();
+   }
+
+   private String getExceptionDuringCheckingMessage(Throwable e)
+   {
+      return EXCEPTION_DURING_CHECKING_MESSAGE + ": " + e.getMessage();
+   }
+
+   private void logComment(String message)
+   {
+      try
+      {
+         lastReport.logComment(message);
+      }
+      catch (IOException e)
+      {
+         LOG.error(e.getMessage(), e);
+      }
+   }
+
+   private void logExceptionAndSetInconsistency(String message, Throwable e)
+   {
+      try
+      {
+         lastReport.logExceptionAndSetInconsistency(message, e);
+      }
+      catch (IOException e1)
+      {
+         LOG.error(e1.getMessage(), e1);
+      }
+   }
+
+   private void createNewReport() throws IOException
+   {
+      lastReport = new InspectionReport(repository.getConfiguration().getName());
+   }
+
+   private void closeReport()
+   {
+      try
+      {
+         lastReport.close();
+      }
+      catch (IOException e)
+      {
+         LOG.error(e.getMessage(), e);
+      }
+   }
+
+   private void doCheckDataBase(boolean autoRepair) throws RepositoryException, IOException,
+      RepositoryConfigurationException
+   {
+      for (String wsName : repository.getWorkspaceNames())
+      {
+         logComment("Check DB consistency. Workspace " + wsName);
+
+         JDBCWorkspaceDataContainerChecker jdbcChecker = getJDBCChecker(wsName);
+         jdbcChecker.checkDataBase();
+         jdbcChecker.checkLocksInDataBase(autoRepair);
+      }
+   }
+
+   private void doCheckValueStorage(boolean autoRepair)
+   {
+      for (String wsName : repository.getWorkspaceNames())
+      {
+         logComment("Check ValueStorage consistency. Workspace " + wsName);
+         getJDBCChecker(wsName).checkValueStorage(autoRepair);
+      }
+   }
+
+   private void doCheckIndex(boolean autoRepair) throws RepositoryException, IOException
+   {
+      final String systemWS = repository.getConfiguration().getSystemWorkspaceName();
+      for (String wsName : repository.getWorkspaceNames())
+      {
+         logComment("Check SearchIndex consistency. Workspace " + wsName);
+
+         SearchManager searchManager = (SearchManager)getComponent(SearchManager.class, wsName);
+
+         searchManager.checkIndex(lastReport, systemWS.equals(wsName));
+      }
+   }
+
+   private JDBCWorkspaceDataContainerChecker getJDBCChecker(String wsName)
+   {
+      JDBCWorkspaceDataContainer dataContainer =
+         (JDBCWorkspaceDataContainer)getComponent(JDBCWorkspaceDataContainer.class, wsName);
+
+      ValueStoragePluginProvider vsPlugin =
+         (ValueStoragePluginProvider)getComponent(ValueStoragePluginProvider.class, wsName);
+
+      WorkspaceEntry wsEntry = (WorkspaceEntry)getComponent(WorkspaceEntry.class, wsName);
+      
+      return new JDBCWorkspaceDataContainerChecker(dataContainer, vsPlugin, wsEntry, lastReport);
+   }
+
+   private Object getComponent(Class forClass, String wsName)
+   {
+      return repository.getWorkspaceContainer(wsName).getComponent(forClass);
+   }
+
+   private String getPathToReportMessage()
+   {
+      return ". See full report by path " + lastReport.getReportPath();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void start()
+   {
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void stop()
+   {
+   }
+}



More information about the exo-jcr-commits mailing list