/*
* 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.services.jcr.BaseStandaloneTest;
import org.exoplatform.services.jcr.access.AccessControlList;
import org.exoplatform.services.jcr.config.LockManagerEntry;
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.core.WorkspaceContainerFacade;
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
import org.exoplatform.services.jcr.datamodel.InternalQName;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.impl.Constants;
import org.exoplatform.services.jcr.impl.TesterRepositoryCheckController;
import org.exoplatform.services.jcr.impl.checker.InconsistencyRepair;
import org.exoplatform.services.jcr.impl.checker.NodeRemover;
import org.exoplatform.services.jcr.impl.checker.RepositoryCheckController;
import org.exoplatform.services.jcr.impl.core.ItemImpl;
import org.exoplatform.services.jcr.impl.core.NodeImpl;
import org.exoplatform.services.jcr.impl.core.PropertyImpl;
import org.exoplatform.services.jcr.impl.core.SessionImpl;
import org.exoplatform.services.jcr.impl.core.nodetype.NodeTypeDataManagerImpl;
import org.exoplatform.services.jcr.impl.core.query.SearchManager;
import org.exoplatform.services.jcr.impl.core.query.SystemSearchManager;
import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData;
import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData;
import org.exoplatform.services.jcr.impl.dataflow.TransientValueData;
import org.exoplatform.services.jcr.impl.storage.jdbc.JDBCDataContainerConfig.DatabaseStructureType;
import org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.db.SybaseJDBCConnectionHelper;
import org.exoplatform.services.jcr.impl.storage.value.fs.FileValueStorage;
import org.exoplatform.services.jcr.util.IdGenerator;
import org.exoplatform.services.jcr.util.TesterConfigurationHelper;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jcr.LoginException;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
/**
* @author <a href="mailto:skarpenko@exoplatform.com">Sergiy Karpenko</a>
* @version $Id: exo-jboss-codetemplates.xml 34360 10.10.2011 skarpenko $
*
*/
public class TestRepositoryCheckController extends BaseStandaloneTest
{
private static boolean SHARED_CACHE = true;
private static boolean NOT_SHARED_CACHE = false;
private static boolean CACHE_DISABLED = false;
private final TesterConfigurationHelper helper = TesterConfigurationHelper.getInstance();
protected String getRepositoryName()
{
return null;
}
public void tearDown() throws Exception
{
// remove generated reports
for (File file : new File(".").listFiles())
{
if (file.getName().startsWith("report"))
{
file.delete();
}
}
super.tearDown();
}
public void testCheckDataBase() throws Exception
{
ManageableRepository db1 = repositoryService.getRepository("db1");
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(db1);
checkDatabase(checkController, 1);
}
public void testCheckDataBaseMultiThreading() throws Exception
{
ManageableRepository db1 = repositoryService.getRepository("db1");
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(db1);
checkDatabase(checkController, 5);
}
private void checkDatabase(TesterRepositoryCheckController checkController, int nThreads) throws Exception
{
SessionImpl session = (SessionImpl)repository.login(credentials, "ws1");
Node testRoot = session.getRootNode().addNode("testRoot");
Node exoTrash = testRoot.addNode("exo:trash");
Node exoTrash2 = testRoot.addNode("exo:trash2");
exoTrash.addNode("node1");
exoTrash.addNode("node2");
Node node1 = exoTrash2.addNode("node1");
Node node2 = exoTrash2.addNode("node2");
session.save();
assertResult(checkController.checkIndex(nThreads), checkController.getLastReportPath(), true);
QueryManager qman = session.getWorkspace().getQueryManager();
Query q = qman.createQuery("SELECT * FROM nt:base WHERE jcr:path LIKE '/testRoot/%'", Query.SQL);
assertEquals(5, q.execute().getNodes().getSize());
node1.addMixin("exo:hiddenable");
node2.addMixin("exo:nothiddenable");
session.save();
assertResult(checkController.checkIndex(nThreads), checkController.getLastReportPath(), true);
q = qman.createQuery("SELECT * FROM nt:base WHERE jcr:path LIKE '/testRoot/%'", Query.SQL);
assertEquals(4, q.execute().getNodes().getSize());
testRoot.remove();
session.save();
}
public void testLockUsecases() throws Exception
{
checkConsistentLocksInDataBase(helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED,
NOT_SHARED_CACHE));
checkConsistentLocksInDataBase(helper.createRepository(container, DatabaseStructureType.MULTI, CACHE_DISABLED,
NOT_SHARED_CACHE));
checkConsistentLocksInDataBase(helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED,
SHARED_CACHE));
checkConsistentLocksInDataBase(helper.createRepository(container, DatabaseStructureType.MULTI, CACHE_DISABLED,
SHARED_CACHE));
checkInconsistentLocksInLockTable(helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED,
NOT_SHARED_CACHE));
checkInconsistentLocksInLockTable(helper.createRepository(container, DatabaseStructureType.MULTI, CACHE_DISABLED,
NOT_SHARED_CACHE));
checkInconsistentLocksInLockTable(helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED,
SHARED_CACHE));
checkInconsistentLocksInLockTable(helper.createRepository(container, DatabaseStructureType.MULTI, CACHE_DISABLED,
SHARED_CACHE));
}
private void checkConsistentLocksInDataBase(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
lockNode(node);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
removePropertyInDB(repository, (PropertyImpl)node.getProperty("jcr:lockIsDeep"));
removePropertyInDB(repository, (PropertyImpl)node.getProperty("jcr:lockOwner"));
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
private void checkInconsistentLocksInLockTable(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
lockNode(node);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
clearLockTable(repository);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
public void testCheckValueStorage() throws Exception
{
TesterRepositoryCheckController checkController =
new TesterRepositoryCheckController(repositoryService.getRepository("db1"));
assertResult(checkController.checkValueStorage(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkValueStorage().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
public void testCheckValueStorageMultiThreading() throws Exception
{
TesterRepositoryCheckController checkController =
new TesterRepositoryCheckController(repositoryService.getRepository("db1"));
assertResult(checkController.checkValueStorage(5), checkController.getLastReportPath(), true);
}
public void testCheckIndex() throws Exception
{
TesterRepositoryCheckController checkController =
new TesterRepositoryCheckController(repositoryService.getRepository("db1"));
assertResult(checkController.checkIndex(), checkController.getLastReportPath(), true);
}
public void testCheckIndexMultiThreading() throws Exception
{
TesterRepositoryCheckController checkController =
new TesterRepositoryCheckController(repositoryService.getRepository("db1"));
assertResult(checkController.checkIndex(5), checkController.getLastReportPath(), true);
}
public void testCheckAll() throws Exception
{
TesterRepositoryCheckController checkController =
new TesterRepositoryCheckController(repositoryService.getRepository("db1"));
assertResult(checkController.checkAll(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkAll().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
public void testCheckAllMultiThreading() throws Exception
{
TesterRepositoryCheckController checkController =
new TesterRepositoryCheckController(repositoryService.getRepository("db1"));
assertResult(checkController.checkAll(5), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkAll().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
/**
* Index contains documents that was already removed from DB.
*/
public void testIndexUsecaseWrongDocumentId() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED);
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
assertResult(checkController.checkIndex(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkIndex().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
removeNodeInDB(repository, node);
assertResult(checkController.checkIndex(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkIndex().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Index contains multiple documents.
*/
public void testIndexUsecaseMultipleDocuments() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED);
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
assertResult(checkController.checkIndex(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkIndex().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
indexNode(repository, node, ItemState.ADDED);
assertResult(checkController.checkIndex(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkIndex().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Index doesn't contain document which stored in DB.
*/
public void testIndexUsecaseDocumentNotExists() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED);
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
assertResult(checkController.checkIndex(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkIndex().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
indexNode(repository, node, ItemState.DELETED);
assertResult(checkController.checkIndex(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkIndex().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Ensure index has pending deletions, then call optimize to get rid of it.
*/
public void testOptimizeIndexUsecase() throws Exception
{
ManageableRepository repository =
helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED);
makeIndexContaingDeletions(repository);
boolean hasDeletions = hasDeletions(repository);
if (hasDeletions)
{
optimize(repository);
assertFalse(hasDeletions(repository));
}
helper.removeRepository(container, repository.getConfiguration().getName());
}
/**
* Ensures index contains deletions.
*/
private void makeIndexContaingDeletions(ManageableRepository repository) throws Exception
{
SessionImpl session =
(SessionImpl)repository.login(credentials, repository.getConfiguration().getSystemWorkspaceName());
Node testRoot = session.getRootNode().addNode("test");
for (int i = 0; i < 200; i++)
{
Node node = testRoot.addNode("test" + i);
node.addMixin("mix:versionable");
session.save();
node.checkin();
node.checkout();
}
testRoot.remove();
session.save();
}
/**
* Checks if index has deletions.
*/
private boolean hasDeletions(ManageableRepository repository)
{
boolean hasDeletions = false;
for (String wsName : repository.getWorkspaceNames())
{
List<SearchManager> searches =
repository.getWorkspaceContainer(wsName).getComponentInstancesOfType(SearchManager.class);
for (SearchManager search : searches)
{
hasDeletions |= search.hasDeletions();
}
}
return hasDeletions;
}
/**
* Checks if index has deletions.
*/
private void optimize(ManageableRepository repository)
{
for (String wsName : repository.getWorkspaceNames())
{
List<SearchManager> searches =
repository.getWorkspaceContainer(wsName).getComponentInstancesOfType(SearchManager.class);
for (SearchManager search : searches)
{
search.optimize();
}
}
}
/**
* Usecase: property doens't have have parent node.
*/
public void testDBUsecasesTheParentIdIsIdOfThisNode() throws Exception
{
checkDBUsecasesTheParentIdIsIdOfThisNode(helper.createRepository(container, DatabaseStructureType.SINGLE,
CACHE_DISABLED));
checkDBUsecasesTheParentIdIsIdOfThisNode2(helper.createRepository(container, DatabaseStructureType.SINGLE,
CACHE_DISABLED));
checkDBUsecasesTheParentIdIsIdOfThisNode(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
checkDBUsecasesTheParentIdIsIdOfThisNode2(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
}
private void checkDBUsecasesTheParentIdIsIdOfThisNode(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
assingItsOwnParent(repository, (ItemImpl)node);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
private void checkDBUsecasesTheParentIdIsIdOfThisNode2(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
Property prop = addTestProperty(repository, node);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
assingItsOwnParent(repository, (ItemImpl)prop);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Usecase: property doens't have have parent node.
*/
public void testDBUsecasesSeveralVersionsOfSameItem() throws Exception
{
checkSeveralVersionsOfSameItem(helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED));
checkSeveralVersionsOfSameItem(helper.createRepository(container, DatabaseStructureType.MULTI, CACHE_DISABLED));
}
private void checkSeveralVersionsOfSameItem(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
NodeImpl node1 = (NodeImpl)addTestNode(repository);
NodeImpl node2 = (NodeImpl)addTestNode(repository);
PropertyImpl prop = (PropertyImpl)addTestProperty(repository, node1);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
updateNodeRecord(repository, node2.getInternalIdentifier(), 1, 1);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
insertPropertyRecord(repository, prop.getInternalIdentifier(), prop.getParentIdentifier(), prop.getName());
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Usecase: property doens't have have parent node.
*/
public void testDBUsecasesPropertyWithoutParent() throws Exception
{
checkDBUsecasesPropertyWithoutParent(helper.createRepository(container, DatabaseStructureType.SINGLE,
CACHE_DISABLED));
checkDBUsecasesPropertyWithoutParent(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
}
private void checkDBUsecasesPropertyWithoutParent(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
insertPropertyRecord(repository, IdGenerator.generate(), IdGenerator.generate(), "testName");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Usecase: Incorrect JCR_VALUE records.
*/
public void testDBUsecasesIncorrectValueRecords() throws Exception
{
checkDBUsecasesIncorrectValueRecords(helper.createRepository(container, DatabaseStructureType.SINGLE,
CACHE_DISABLED));
checkDBUsecasesIncorrectValueRecords(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
}
private void checkDBUsecasesIncorrectValueRecords(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
PropertyImpl prop = (PropertyImpl)addTestProperty(repository, node);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
updateValueRecord(repository, prop.getInternalIdentifier());
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Usecase: value records has no item record.
*/
public void testDBUsecasesValueRecordHasNoItemRecord() throws Exception
{
checkDBUsecasesValueRecordHasNoItemRecord(helper.createRepository(container, DatabaseStructureType.SINGLE,
CACHE_DISABLED));
checkDBUsecasesValueRecordHasNoItemRecord(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
}
private void checkDBUsecasesValueRecordHasNoItemRecord(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
PropertyImpl prop = (PropertyImpl)addTestProperty(repository, node);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
removeItemRecord(repository, prop.getInternalIdentifier());
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Usecase: properties that have not value record.
*/
public void testDBUsecasesPrimaryTypePropertyHasNoValueRecord() throws Exception
{
checkDBUsecasesPrimaryTypePropertyHasNoValueRecor(helper.createRepository(container,
DatabaseStructureType.SINGLE, CACHE_DISABLED));
checkDBUsecasesPrimaryTypePropertyHasNoValueRecor(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
}
private void checkDBUsecasesPrimaryTypePropertyHasNoValueRecor(ManageableRepository repository) throws Exception
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
PropertyImpl prop = (PropertyImpl)node.getProperty("jcr:primaryType");
assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
removeValueRecord(repository, prop.getInternalIdentifier());
assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
helper.removeRepository(container, repository.getConfiguration().getName());
}
/**
* Usecase: properties that have not value record.
*/
public void testDBUsecasesPropertiesHasNoValueRecord() throws Exception
{
checkDBUsecasesPropertiesHasNoSingleValueRecord(helper.createRepository(container, DatabaseStructureType.SINGLE,
CACHE_DISABLED));
checkDBUsecasesPropertiesHasEmptyMultiValueRecord(helper.createRepository(container,
DatabaseStructureType.SINGLE, CACHE_DISABLED));
checkDBUsecasesPropertiesHasNoSingleValueRecord(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
checkDBUsecasesPropertiesHasEmptyMultiValueRecord(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
}
private void checkDBUsecasesPropertiesHasNoSingleValueRecord(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
PropertyImpl prop = (PropertyImpl)addTestProperty(repository, node);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
removeValueRecord(repository, prop.getInternalIdentifier());
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
private void checkDBUsecasesPropertiesHasEmptyMultiValueRecord(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
node.setProperty("prop", new String[]{});
node.save();
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Usecase: reference properties without reference records.
*/
public void testDBUsecasesReferencePropertyWithoutReferenceRecord() throws Exception
{
checkDBUsecasesReferencePropertyWithoutReferenceRecord(helper.createRepository(container,
DatabaseStructureType.SINGLE, CACHE_DISABLED));
checkDBUsecasesReferencePropertyWithoutReferenceRecord(helper.createRepository(container,
DatabaseStructureType.MULTI, CACHE_DISABLED));
}
private void checkDBUsecasesReferencePropertyWithoutReferenceRecord(ManageableRepository repository)
throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
Node node2 = addTestNode(repository);
PropertyImpl prop = (PropertyImpl)node2.setProperty("prop", node);
node2.save();
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
removeReferenceRecord(repository, prop.getInternalIdentifier());
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkDataBase().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Usecase when node doesn't have at primary type property.
*/
public void testDBUsecasesNodeHasNoProperties() throws Exception
{
checkDBUsecasesNodeHasNotPrimaryTypeProperties(helper.createRepository(container, DatabaseStructureType.SINGLE,
CACHE_DISABLED));
checkDBUsecasesNodeHasNotPrimaryTypeProperties(helper.createRepository(container, DatabaseStructureType.MULTI,
CACHE_DISABLED));
}
private void checkDBUsecasesNodeHasNotPrimaryTypeProperties(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
removePropertyInDB(repository, (PropertyImpl)node.getProperty("jcr:primaryType"));
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
checkController.repairDataBase("yes");
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Usecase when tree of nodes do't have primary type property.
*/
public void testDBUsecasesTreeOfNodeHasNoProperties() throws Exception
{
checkDBUsecasesTreeOfNodeHasNotPrimaryTypeProperties1(helper.createRepository(container,
DatabaseStructureType.SINGLE, CACHE_DISABLED));
checkDBUsecasesTreeOfNodeHasNotPrimaryTypeProperties1(helper.createRepository(container,
DatabaseStructureType.MULTI, CACHE_DISABLED));
}
private void checkDBUsecasesTreeOfNodeHasNotPrimaryTypeProperties1(ManageableRepository repository) throws Exception
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
NodeImpl node1 = (NodeImpl)addTestNode(repository);
NodeImpl node2 = (NodeImpl)addTestNode(repository, node1.getUUID());
NodeImpl node3 = (NodeImpl)addTestNode(repository, node2.getUUID());
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
removePropertyInDB(repository, (PropertyImpl)node3.getProperty("jcr:primaryType"));
removePropertyInDB(repository, (PropertyImpl)node2.getProperty("jcr:primaryType"));
removePropertyInDB(repository, (PropertyImpl)node1.getProperty("jcr:primaryType"));
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), false);
InconsistencyRepair repair = getNodeRemover(repository);
// check correctness repairing child with parent without primaryType property
Connection conn = getConnection(repository);
ResultSet resultSet = getResultSetWithNode(repository, conn, node3);
resultSet.next();
repair.doRepair(resultSet);
resultSet.close();
conn.close();
// check correctness repairing parent with child without primaryType property
conn = getConnection(repository);
resultSet = getResultSetWithNode(repository, conn, node1);
resultSet.next();
repair.doRepair(resultSet);
resultSet.close();
conn.close();
// check correctness repairing node already removed in previous check
Map<String, String> strFields = new HashMap<String, String>();
strFields.put(DBConstants.COLUMN_PARENTID, "already-removed-parentId");
strFields.put(DBConstants.COLUMN_NAME, "[]" + node2.getName());
strFields.put(DBConstants.COLUMN_ID, node2.getIdentifier());
Map<String, Integer> intFields = new HashMap<String, Integer>();
intFields.put(DBConstants.COLUMN_NORDERNUM, 1);
intFields.put(DBConstants.COLUMN_VERSION, 0);
intFields.put(DBConstants.COLUMN_INDEX, 0);
resultSet = new FakeResultSet(strFields, intFields);
repair.doRepair(resultSet);
assertResult(checkController.checkDataBase(), checkController.getLastReportPath(), true);
helper.removeRepository(container, repository.getConfiguration().getName());
}
/**
* Usescase when STORAGE_DESC field in VALUE table is not empty but there is no file in the value storage.
*/
public void testValueStorageUsecases() throws Exception
{
checkValueStorageUsecases(helper.createRepository(container, DatabaseStructureType.SINGLE, CACHE_DISABLED));
checkValueStorageUsecases(helper.createRepository(container, DatabaseStructureType.MULTI, CACHE_DISABLED));
}
private void checkValueStorageUsecases(ManageableRepository repository) throws Exception
{
try
{
TesterRepositoryCheckController checkController = new TesterRepositoryCheckController(repository);
Node node = addTestNode(repository);
PropertyImpl prop = (PropertyImpl)node.setProperty("prop", new FileInputStream(createBLOBTempFile(300)));
node.save();
assertResult(checkController.checkValueStorage(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkValueStorage().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
removeFileFromVS(repository, prop.getInternalIdentifier());
assertResult(checkController.checkValueStorage(), checkController.getLastReportPath(), false);
//assertTrue(checkController.checkValueStorage().startsWith(RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE));
checkController.repairValueStorage("yes");
assertResult(checkController.checkValueStorage(), checkController.getLastReportPath(), true);
//assertTrue(checkController.checkValueStorage().startsWith(RepositoryCheckController.REPORT_CONSISTENT_MESSAGE));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
private Node addTestNode(ManageableRepository repository) throws LoginException, NoSuchWorkspaceException,
RepositoryException
{
return addTestNode(repository, Constants.ROOT_UUID);
}
private Node addTestNode(ManageableRepository repository, String parentId) throws LoginException,
NoSuchWorkspaceException, RepositoryException
{
SessionImpl session =
(SessionImpl)repository.login(credentials, repository.getConfiguration().getSystemWorkspaceName());
Node parent = session.getNodeByIdentifier(parentId);
NodeImpl node = (NodeImpl)parent.addNode("testNode");
node.addMixin("mix:referenceable");
node.addMixin("mix:versionable");
session.save();
return node;
}
private Property addTestProperty(ManageableRepository repository, Node node) throws LoginException,
NoSuchWorkspaceException, RepositoryException
{
Property prop = node.setProperty("testProp", "value");
node.save();
return prop;
}
private void lockNode(Node node) throws LoginException, NoSuchWorkspaceException, RepositoryException
{
node.addMixin("mix:lockable");
node.save();
node.lock(false, false);
}
private void removeNodeInDB(ManageableRepository repository, Node node) throws SQLException,
RepositoryConfigurationException, NamingException, UnsupportedRepositoryOperationException, RepositoryException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
String vTable = "JCR_" + (isMultiDb ? "M" : "S") + "VALUE";
String iTable = "JCR_" + (isMultiDb ? "M" : "S") + "ITEM";
String nodeId = (isMultiDb ? "" : wsEntry.getName()) + node.getUUID();
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
ResultSet resultSet =
conn.prepareStatement("SELECT * FROM " + iTable + " WHERE PARENT_ID='" + nodeId + "'").executeQuery();
while (resultSet.next())
{
String propertyId = resultSet.getString(DBConstants.COLUMN_ID);
conn.prepareStatement("DELETE FROM " + vTable + " WHERE PROPERTY_ID = '" + propertyId + "'").execute();
conn.prepareStatement("DELETE FROM " + iTable + " WHERE ID = '" + propertyId + "'").execute();
}
conn.prepareStatement("DELETE FROM " + iTable + " WHERE ID='" + nodeId + "'").execute();
conn.commit();
conn.close();
}
private void removePropertyInDB(ManageableRepository repository, PropertyImpl property) throws SQLException,
RepositoryConfigurationException, NamingException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
String vTable = "JCR_" + (isMultiDb ? "M" : "S") + "VALUE";
String iTable = "JCR_" + (isMultiDb ? "M" : "S") + "ITEM";
String propertyId = (isMultiDb ? "" : wsEntry.getName()) + property.getInternalIdentifier();
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
conn.prepareStatement("DELETE FROM " + vTable + " WHERE PROPERTY_ID = '" + propertyId + "'").execute();
conn.prepareStatement("DELETE FROM " + iTable + " WHERE ID = '" + propertyId + "'").execute();
conn.commit();
conn.close();
}
private ResultSet getResultSetWithNode(ManageableRepository repository, Connection conn, NodeImpl node)
throws Exception
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String iTable = "JCR_" + (isMultiDb ? "M" : "S") + "ITEM";
String nodeId = (isMultiDb ? "" : wsEntry.getName()) + node.getInternalIdentifier();
return conn.prepareStatement("SELECT * FROM " + iTable + " WHERE ID = '" + nodeId + "'").executeQuery();
}
private Connection getConnection(ManageableRepository repository) throws Exception
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
return ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
}
private void removeValueRecord(ManageableRepository repository, String propId) throws SQLException,
RepositoryConfigurationException, NamingException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
String vTable = "JCR_" + (isMultiDb ? "M" : "S") + "VALUE";
propId = (isMultiDb ? "" : wsEntry.getName()) + propId;
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
conn.prepareStatement("DELETE FROM " + vTable + " WHERE PROPERTY_ID = '" + propId + "'").execute();
conn.prepareStatement(
"ALTER TABLE " + vTable + " DROP CONSTRAINT JCR_FK_" + (isMultiDb ? "M" : "S") + "VALUE_PROPERTY").execute();
conn.commit();
conn.close();
}
private void removeReferenceRecord(ManageableRepository repository, String propId) throws SQLException,
RepositoryConfigurationException, NamingException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
String rTable = "JCR_" + (isMultiDb ? "M" : "S") + "REF";
propId = (isMultiDb ? "" : wsEntry.getName()) + propId;
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
conn.prepareStatement("DELETE FROM " + rTable + " WHERE PROPERTY_ID = '" + propId + "'").execute();
conn.commit();
conn.close();
}
private void removeItemRecord(ManageableRepository repository, String propId) throws SQLException,
RepositoryConfigurationException, NamingException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
String vTable = "JCR_" + (isMultiDb ? "M" : "S") + "VALUE";
String iTable = "JCR_" + (isMultiDb ? "M" : "S") + "ITEM";
propId = (isMultiDb ? "" : wsEntry.getName()) + propId;
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
conn.prepareStatement(
"ALTER TABLE " + vTable + " DROP CONSTRAINT JCR_FK_" + (isMultiDb ? "M" : "S") + "VALUE_PROPERTY").execute();
conn.prepareStatement(
"ALTER TABLE " + iTable + " DROP CONSTRAINT JCR_FK_" + (isMultiDb ? "M" : "S") + "ITEM_PARENT").execute();
conn.prepareStatement("DELETE FROM " + iTable + " WHERE ID = '" + propId + "'").execute();
conn.commit();
conn.close();
}
private void assingItsOwnParent(ManageableRepository repository, ItemImpl item) throws SQLException,
RepositoryConfigurationException, NamingException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String iTable = "JCR_" + (isMultiDb ? "M" : "S") + "ITEM";
String itemId = (isMultiDb ? "" : wsEntry.getName()) + item.getInternalIdentifier();
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
conn.prepareStatement("DROP INDEX JCR_IDX_" + (isMultiDb ? "M" : "S") + "ITEM_PARENT").execute();
conn.prepareStatement("DROP INDEX JCR_IDX_" + (isMultiDb ? "M" : "S") + "ITEM_PARENT_NAME").execute();
conn.prepareStatement("UPDATE " + iTable + " SET PARENT_ID='" + itemId + "' WHERE ID='" + itemId + "'").execute();
conn.commit();
conn.close();
}
private void clearLockTable(ManageableRepository repository) throws RepositoryConfigurationException, SQLException,
NamingException
{
WorkspaceEntry workspaceEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
LockManagerEntry lockManagerEntry = workspaceEntry.getLockManager();
String sourceName = null;
String queryStatement = null;
if (helper.ispnCacheEnabled())
{
sourceName = lockManagerEntry.getParameterValue("infinispan-cl-cache.jdbc.datasource");
queryStatement =
"DELETE FROM \"" + lockManagerEntry.getParameterValue("infinispan-cl-cache.jdbc.table.name") + "_" + "L"
+ workspaceEntry.getUniqueName().replace("_", "").replace("-", "_") + "\"";
}
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
conn.prepareStatement(queryStatement).execute();
conn.commit();
conn.close();
}
private void indexNode(ManageableRepository repository, Node node, int state)
throws UnsupportedRepositoryOperationException, RepositoryException
{
// Indexing one more document with same UUID
List<SearchManager> searchManagers =
repository.getWorkspaceContainer(repository.getConfiguration().getSystemWorkspaceName())
.getComponentInstancesOfType(SearchManager.class);
PlainChangesLog log = new PlainChangesLogImpl();
NodeData data =
new TransientNodeData(QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName("", "testNode")),
node.getUUID(), -1, Constants.NT_UNSTRUCTURED, null, 0, null, new AccessControlList());
TransientPropertyData primaryType =
new TransientPropertyData(QPath.makeChildPath(data.getQPath(), Constants.JCR_PRIMARYTYPE),
IdGenerator.generate(), -1, PropertyType.NAME, data.getIdentifier(), false, new TransientValueData(
Constants.NT_UNSTRUCTURED));
log.add(new ItemState(data, ItemState.ADDED, false, null));
log.add(new ItemState(primaryType, ItemState.ADDED, false, null));
for (SearchManager searchManager : searchManagers)
{
if (!(searchManager instanceof SystemSearchManager))
{
searchManager.onSaveItems(log);
break;
}
}
}
private void insertPropertyRecord(ManageableRepository repository, String id, String parentId, String name)
throws RepositoryConfigurationException, SQLException, NamingException,
RepositoryException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String iTable = "JCR_" + (isMultiDb ? "M" : "S") + "ITEM";
String vTable = "JCR_" + (isMultiDb ? "M" : "S") + "VALUE";
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
// add another item with new persisted version
String propId = (isMultiDb ? "" : wsEntry.getName()) + IdGenerator.generate();
parentId = (isMultiDb ? "" : wsEntry.getName()) + parentId;
conn.prepareStatement(
"ALTER TABLE " + iTable + " DROP CONSTRAINT JCR_FK_" + (isMultiDb ? "M" : "S") + "ITEM_PARENT").execute();
if (isMultiDb)
{
conn.prepareStatement(
"INSERT INTO " + iTable + " VALUES ('" + propId + "','" + parentId + "','[]" + name
+ "',1,2,1,NULL,1,FALSE)").execute();
}
else
{
conn.prepareStatement(
"INSERT INTO " + iTable + " VALUES ('" + propId + "','" + parentId + "','[]" + name + "',1,'"
+ wsEntry.getName() + "',2,1,NULL,1,FALSE)").execute();
}
conn.prepareStatement("INSERT INTO " + vTable + " VALUES ('10000','data','1','" + propId + "',NULL)").execute();
conn.commit();
conn.close();
}
private void updateValueRecord(ManageableRepository repository, String propId)
throws RepositoryConfigurationException, SQLException, NamingException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
String vTable = "JCR_" + (isMultiDb ? "M" : "S") + "VALUE";
propId = (isMultiDb ? "" : wsEntry.getName()) + propId;
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
conn.prepareStatement(
"UPDATE " + vTable + " SET STORAGE_DESC = 'unexisted-desc' WHERE PROPERTY_ID = '" + propId + "'").execute();
conn.commit();
conn.close();
}
private void updateNodeRecord(ManageableRepository repository, String nodeId, int newPersistedVersion, int newIndex)
throws RepositoryConfigurationException, SQLException, NamingException
{
WorkspaceEntry wsEntry = repository.getConfiguration().getWorkspaceEntries().get(0);
boolean isMultiDb =
DatabaseStructureType.valueOf(
wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.DB_STRUCTURE_TYPE)).isMultiDatabase();
String sourceName = wsEntry.getContainer().getParameterValue(JDBCWorkspaceDataContainer.SOURCE_NAME);
String iTable = "JCR_" + (isMultiDb ? "M" : "S") + "ITEM";
nodeId = (isMultiDb ? "" : wsEntry.getName()) + nodeId;
Connection conn = ((DataSource)new InitialContext().lookup(sourceName)).getConnection();
conn.prepareStatement(
"UPDATE " + iTable + " SET VERSION=" + newPersistedVersion + ", I_INDEX=" + newIndex + " WHERE ID = '"
+ nodeId + "'").execute();
conn.commit();
conn.close();
}
private void removeFileFromVS(ManageableRepository repository, String propId)
throws RepositoryConfigurationException
{
String vsPath =
repository.getConfiguration().getWorkspaceEntries().get(0).getContainer().getValueStorages().get(0)
.getParameterValue(FileValueStorage.PATH);
File vsFile = new File(vsPath, propId + "0");
assertTrue(vsFile.exists());
assertTrue(vsFile.delete());
}
private void assertResult(String reportMessage, String reportPath, boolean consistent)
{
String expected =
consistent ? RepositoryCheckController.REPORT_CONSISTENT_MESSAGE
: RepositoryCheckController.REPORT_NOT_CONSISTENT_MESSAGE;
if (!reportMessage.startsWith(expected))
{
log.error("Expected result is:" + expected + "but report is:" + reportMessage);
log.error("Full report content is ... " + getFileContent(reportPath) + "======================");
fail("Expected result is \"" + expected + "\", but report is \"" + reportMessage + "\"");
}
// else - ok
}
private InconsistencyRepair getNodeRemover(ManageableRepository repository)
{
String wsName = repository.getConfiguration().getSystemWorkspaceName();
WorkspaceContainerFacade wsContainer = repository.getWorkspaceContainer(wsName);
NodeTypeDataManagerImpl nodeTypeManager =
(NodeTypeDataManagerImpl)wsContainer.getComponent(NodeTypeDataManagerImpl.class);
JDBCWorkspaceDataContainer jdbcDataContainer =
(JDBCWorkspaceDataContainer)wsContainer.getComponent(JDBCWorkspaceDataContainer.class);
InconsistencyRepair repair =
new NodeRemover(jdbcDataContainer.getConnectionFactory(), jdbcDataContainer.containerConfig, nodeTypeManager);
return repair;
}
private String getFileContent(String reportPath)
{
StringBuffer contents = new StringBuffer();
BufferedReader reader = null;
try
{
reader = new BufferedReader(new FileReader(reportPath));
String text = null;
// repeat until all lines is read
while ((text = reader.readLine()) != null)
{
contents.append(text).append(System.getProperty("line.separator"));
}
}
catch (FileNotFoundException e)
{
return "Report file (" + reportPath + ") not found.";
}
catch (IOException e)
{
return "IOException reading report file (" + reportPath + ").";
}
finally
{
try
{
if (reader != null)
{
reader.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
// show file contents here
return contents.toString();
}
private class FakeResultSet extends SybaseJDBCConnectionHelper.EmptyResultSet
{
private final Map<String, String> strFields;
private final Map<String, Integer> intFields;
FakeResultSet(Map<String, String> strFields, Map<String, Integer> intFields)
{
this.strFields = strFields;
this.intFields = intFields;
}
public String getString(String columnName) throws SQLException
{
String value = strFields.get(columnName);
if (value == null)
{
throw new SQLException("Field not found");
}
return value;
}
public int getInt(String columnName) throws SQLException
{
Integer value = intFields.get(columnName);
if (value == null)
{
throw new SQLException("Field not found");
}
return value;
}
}
}