/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.core.cluster;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.UUID;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.query.Query;
import javax.jcr.query.RowIterator;
import junit.framework.Assert;
import org.apache.commons.io.FileUtils;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.jackrabbit.core.RepositoryImpl;
import org.apache.jackrabbit.core.config.RepositoryConfig;
import org.apache.jackrabbit.test.JUnitTest;
/**
* Test for JCR3162
*/
public class DbClusterTestJCR3162 extends JUnitTest {
private static final SimpleCredentials ADMIN = new SimpleCredentials(
"admin", "admin".toCharArray());
private RepositoryImpl rep1;
private RepositoryImpl rep2;
private String clusterId1 = UUID.randomUUID().toString();
private String clusterId2 = UUID.randomUUID().toString();
private String prevClusterId;
public void setUp() throws Exception {
deleteAll();
FileUtils
.copyFile(
new File(
"./src/test/resources/org/apache/jackrabbit/core/cluster/repository-h2.xml"),
new File("./target/dbClusterTest/node1/repository.xml"));
FileUtils
.copyFile(
new File(
"./src/test/resources/org/apache/jackrabbit/core/cluster/repository-h2.xml"),
new File("./target/dbClusterTest/node2/repository.xml"));
prevClusterId = System.setProperty(ClusterNode.SYSTEM_PROPERTY_NODE_ID, clusterId1);
rep1 = RepositoryImpl.create(RepositoryConfig.create(new File(
"./target/dbClusterTest/node1")));
System.setProperty(ClusterNode.SYSTEM_PROPERTY_NODE_ID, clusterId2);
}
public void tearDown() throws Exception {
// revert change to system property
if (prevClusterId == null) {
System.clearProperty(ClusterNode.SYSTEM_PROPERTY_NODE_ID);
}
else {
System.setProperty(ClusterNode.SYSTEM_PROPERTY_NODE_ID, prevClusterId);
}
try {
rep1.shutdown();
if (rep2 != null) {
rep2.shutdown();
}
} finally {
deleteAll();
}
}
private static void deleteAll() throws IOException {
FileUtils.deleteDirectory(new File("./target/dbClusterTest"));
}
public void test() throws RepositoryException {
int count = 5;
// 1. create
Session s1 = rep1.login(ADMIN);
Node n = s1.getRootNode().addNode(
"test-cluster-" + System.currentTimeMillis(),
JcrConstants.NT_UNSTRUCTURED);
n.addMixin(JcrConstants.MIX_VERSIONABLE);
for (int i = 0; i < count; i++) {
Node c = n.addNode("child_" + i);
c.addMixin(JcrConstants.MIX_VERSIONABLE);
}
s1.save();
// 2. rollback journal revision
resetJournalRev();
// 3. sync & verify
// rep1.shutdown();
// start #2 with an empty search index
rep2 = RepositoryImpl.create(RepositoryConfig.create(new File(
"./target/dbClusterTest/node2")));
// verify
Session s2 = rep2.login(ADMIN);
checkConsistency(s2, "/", s2.getRootNode().getNodes().getSize());
}
private void resetJournalRev() {
Connection con = null;
try {
con = DriverManager.getConnection(
"jdbc:h2:./target/dbClusterTest/db", "sa", "sa");
PreparedStatement prep = con
.prepareStatement("update JOURNAL_LOCAL_REVISIONS set REVISION_ID=0 where JOURNAL_ID=?");
prep.setString(1, clusterId2);
prep.executeUpdate();
prep.close();
} catch (Exception e) {
e.printStackTrace();
Assert.fail("Unable to reset revision to 0. " + e.getMessage());
} finally {
if (con != null) {
try {
con.close();
} catch (Exception e) {
// e.printStackTrace();
}
}
}
}
private void checkConsistency(Session s, String path, long nodes)
throws RepositoryException {
s.refresh(true);
Node n = s.getNode(path);
RowIterator result = s
.getWorkspace()
.getQueryManager()
.createQuery(
"SELECT * FROM [" + JcrConstants.NT_BASE
+ "] as NODE WHERE ischildnode(NODE, ['"
+ n.getPath() + "'])", Query.JCR_SQL2)
.execute().getRows();
int foundViaQuery = 0;
while (result.hasNext()) {
result.next();
foundViaQuery++;
}
StringBuilder err = new StringBuilder("Path " + n.getPath() + ": ");
for (Node c : JcrUtils.getChildNodes(n)) {
err.append("(");
err.append(c.getPath());
err.append("|");
err.append(c.getPrimaryNodeType().getName());
err.append("),");
}
Assert.assertEquals(err.toString(), nodes, foundViaQuery);
for (Node c : JcrUtils.getChildNodes(n)) {
checkConsistency(s, c.getPath(), c.getNodes().getSize());
}
}
}