DNA SVN: r104 - in trunk: dna-common/src/main/java/org/jboss/dna/common/monitor and 9 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-04-22 16:42:49 -0400 (Tue, 22 Apr 2008)
New Revision: 104
Added:
trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18n.java
trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18nTest.java
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/MockI18n.properties
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java
trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties
trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java
trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java
trunk/dna-common/src/test/java/org/jboss/dna/common/stats/HistogramTest.java
trunk/dna-common/src/test/java/org/jboss/dna/common/util/LogContextTest.java
trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitBasicFunctionTest.java
trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitDerbyStressTest.java
trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitInMemoryTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java
Log:
Removed the 'passthrough' I18n instance in CommonI18n, and moved it to MockI18n class that is useful for testing.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -47,7 +47,7 @@
public static I18n i18nReplaceArgumentMismatchedParameters;
public static I18n i18nReplaceArgumentsMismatchedParameters;
public static I18n i18nClassInterface;
- public static I18n i18nClassNotPublic;
+ public static I18n i18nClassNotPublic;
public static I18n i18nFieldFinal;
public static I18n i18nFieldInvalidType;
public static I18n i18nFieldNotPublic;
@@ -62,6 +62,7 @@
public static I18n componentNotConfigured;
public static I18n progressMonitorBeginTask;
public static I18n progressMonitorStatus;
+ public static I18n initialProgressMonitorTaskName;
public static I18n argumentMayNotBeNegative;
public static I18n argumentMayNotBePositive;
@@ -89,7 +90,4 @@
public static I18n pathIsNotAbsolute;
public static I18n pathIsNotRelative;
public static I18n pathCannotBeNormalized;
-
- public static I18n passthrough;
- public static I18n empty;
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -54,7 +54,7 @@
public SimpleProgressMonitor( String activityName ) {
this.activityName = activityName != null ? activityName.trim() : "";
- this.taskName = CommonI18n.empty;
+ this.taskName = CommonI18n.initialProgressMonitorTaskName;
}
/**
Modified: trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties
===================================================================
--- trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties 2008-04-22 20:42:49 UTC (rev 104)
@@ -23,6 +23,7 @@
componentNotConfigured = The component {0} was not configured and will not be used
progressMonitorBeginTask = Beginning {0} ({1})
progressMonitorStatus = {0}
+initialProgressMonitorTaskName =
argumentMayNotBeNegative = The {0} argument value, {1}, may not be negative
argumentMayNotBePositive = The {0} argument value, {1}, may not be positive
@@ -50,6 +51,3 @@
pathCannotBeNormalized = The path {0} is invalid and cannot be normalized
dateParsingFailure = Unable to parse the date "{0}" using the standard ISO 8601 format
-
-passthrough = {0}
-empty =
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -24,7 +24,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.monitor.ProgressMonitor;
/**
@@ -49,7 +49,7 @@
*/
public void doSomething( ProgressMonitor progressMonitor ) {
try {
- progressMonitor.beginTask(1, CommonI18n.passthrough, "Incrementing counter");
+ progressMonitor.beginTask(1, MockI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
progressMonitor.worked(1);
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -24,7 +24,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.monitor.ProgressMonitor;
/**
@@ -49,7 +49,7 @@
*/
public void doSomething( ProgressMonitor progressMonitor ) {
try {
- progressMonitor.beginTask(1, CommonI18n.passthrough, "Incrementing counter");
+ progressMonitor.beginTask(1, MockI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
progressMonitor.worked(1);
Added: trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18n.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18n.java (rev 0)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18n.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -0,0 +1,38 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.common.i18n;
+
+/**
+ * @author Randall Hauch
+ */
+public class MockI18n {
+
+ static {
+ try {
+ I18n.initialize(MockI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static I18n passthrough;
+}
Property changes on: trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18n.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18nTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18nTest.java (rev 0)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18nTest.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.common.i18n;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class MockI18nTest {
+
+ @Test
+ public void shouldPassthroughText() {
+ String str = "This is some string to be passed through";
+ assertThat(MockI18n.passthrough.text(str), is(str));
+ }
+
+ @Test
+ public void shouldPassthroughTextWithoutReplacingParameters() {
+ String str = "This is some string to be passed through with {1} parameters";
+ assertThat(MockI18n.passthrough.text(str), is(str));
+ }
+
+}
Property changes on: trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/MockI18nTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -22,13 +22,13 @@
package org.jboss.dna.common.monitor;
+import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsSame.sameInstance;
-import static org.hamcrest.core.Is.is;
import static org.hamcrest.number.IsCloseTo.closeTo;
import static org.junit.Assert.assertThat;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.junit.Before;
import org.junit.Test;
@@ -64,7 +64,7 @@
@Test
public void shouldHaveProgressOfZeroPercentUponBeginningTask() {
- this.monitor.beginTask(100, CommonI18n.passthrough, validTaskName);
+ this.monitor.beginTask(100, MockI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -74,7 +74,7 @@
@Test
public void shouldShowProperProgress() {
- this.monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
+ this.monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -102,7 +102,7 @@
@Test
public void shouldShowProperProgressUsingSubtasks() {
- monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
+ monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -117,7 +117,7 @@
assertThat(((SubProgressMonitor)subtask).getParent(), is(sameInstance(monitor)));
String subtaskName = "Subtask " + i;
- subtask.beginTask(10, CommonI18n.passthrough, subtaskName); // note the different total work for the subtask
+ subtask.beginTask(10, MockI18n.passthrough, subtaskName); // note the different total work for the subtask
for (int j = 1; j <= 10; ++j) {
// Work the subtask
subtask.worked(1);
@@ -155,7 +155,7 @@
@Test
public void shouldAllowDoneToBeCalledEvenAfterFinished() {
- monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
+ monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -184,7 +184,7 @@
@Test
public void shouldAllowCancelToBeRejected() {
- monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
+ monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -218,7 +218,7 @@
@Test
public void shouldContinueToRecordWorkEvenWhenCancelled() {
- monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
+ monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/stats/HistogramTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/stats/HistogramTest.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/stats/HistogramTest.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -21,15 +21,17 @@
*/
package org.jboss.dna.common.stats;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.math.FloatOperations;
import org.jboss.dna.common.math.MathOperations;
-import org.jboss.dna.common.stats.Histogram;
import org.jboss.dna.common.text.Inflector;
import org.jboss.dna.common.util.Logger;
import org.junit.Before;
@@ -55,7 +57,7 @@
}
public static <T extends Number> void writeHistogramToLog( Logger logger, Histogram<T> histogram, int barLength, String description ) {
- logger.info(CommonI18n.passthrough, description != null ? description : "Histogram:");
+ logger.info(MockI18n.passthrough, description != null ? description : "Histogram:");
List<String> barGraph = histogram.getTextGraph(barLength);
for (String line : barGraph) {
logger.debug(" " + line);
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/util/LogContextTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/util/LogContextTest.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/util/LogContextTest.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -22,9 +22,7 @@
package org.jboss.dna.common.util;
-import org.jboss.dna.common.CommonI18n;
-import org.jboss.dna.common.util.LogContext;
-import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.common.i18n.MockI18n;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -46,8 +44,8 @@
@Test
public void shouldAcceptValidKeys() {
LogContext.set("username", "jsmith");
- logger.info(CommonI18n.passthrough, "tracking activity for username");
- logger.info(CommonI18n.passthrough, "A second log message");
+ logger.info(MockI18n.passthrough, "tracking activity for username");
+ logger.info(MockI18n.passthrough, "A second log message");
}
}
Added: trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/MockI18n.properties
===================================================================
--- trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/MockI18n.properties (rev 0)
+++ trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/MockI18n.properties 2008-04-22 20:42:49 UTC (rev 104)
@@ -0,0 +1 @@
+passthrough = {0}
Property changes on: trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/MockI18n.properties
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitBasicFunctionTest.java
===================================================================
--- trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitBasicFunctionTest.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitBasicFunctionTest.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -31,7 +31,7 @@
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.core.TransientRepository;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.util.FileUtil;
import org.jboss.dna.common.util.Logger;
import org.junit.After;
@@ -76,7 +76,7 @@
assertNotNull(session);
String username = session.getUserID();
String name = repository.getDescriptor(Repository.REP_NAME_DESC);
- logger.info(CommonI18n.passthrough, "Logged in as " + username + " to a " + name + " repository");
+ logger.info(MockI18n.passthrough, "Logged in as " + username + " to a " + name + " repository");
} finally {
if (session != null) session.logout();
}
@@ -91,7 +91,7 @@
assertNotNull(session);
String username = session.getUserID();
String name = repository.getDescriptor(Repository.REP_NAME_DESC);
- logger.info(CommonI18n.passthrough, "Logged in as " + username + " to a " + name + " repository");
+ logger.info(MockI18n.passthrough, "Logged in as " + username + " to a " + name + " repository");
} finally {
if (session != null) session.logout();
}
@@ -106,7 +106,7 @@
Session session = this.repository.login(creds);
assertNotNull(session);
sessions.add(session);
- logger.info(CommonI18n.passthrough, "Logged in as " + session.getUserID());
+ logger.info(MockI18n.passthrough, "Logged in as " + session.getUserID());
}
} finally {
while (!sessions.isEmpty()) {
@@ -150,8 +150,8 @@
// Retrieve content ...
Node node = root.getNode("hello/world");
- this.logger.info(CommonI18n.passthrough, "Node 'hello/world' has path: " + node.getPath());
- this.logger.info(CommonI18n.passthrough, "Node 'hello/world' has 'message' property: " + node.getProperty("message").getString());
+ this.logger.info(MockI18n.passthrough, "Node 'hello/world' has path: " + node.getPath());
+ this.logger.info(MockI18n.passthrough, "Node 'hello/world' has 'message' property: " + node.getProperty("message").getString());
} finally {
if (session != null) session.logout();
}
@@ -163,11 +163,11 @@
// Retrieve content
Node node = root.getNode("hello/world");
- this.logger.info(CommonI18n.passthrough, "Node 'hello/world' has path: " + node.getPath());
- this.logger.info(CommonI18n.passthrough, "Node 'hello/world' has 'message' property: " + node.getProperty("message").getString());
+ this.logger.info(MockI18n.passthrough, "Node 'hello/world' has path: " + node.getPath());
+ this.logger.info(MockI18n.passthrough, "Node 'hello/world' has 'message' property: " + node.getProperty("message").getString());
// Remove content
- this.logger.info(CommonI18n.passthrough, "Node 'hello' is being removed");
+ this.logger.info(MockI18n.passthrough, "Node 'hello' is being removed");
root.getNode("hello").remove();
session.save();
} finally {
Modified: trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitDerbyStressTest.java
===================================================================
--- trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitDerbyStressTest.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitDerbyStressTest.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -27,7 +27,7 @@
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.core.TransientRepository;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.stats.HistogramTest;
import org.jboss.dna.common.stats.Stopwatch;
import org.jboss.dna.common.util.FileUtil;
@@ -65,7 +65,7 @@
logger = Logger.getLogger(JackrabbitDerbyStressTest.class);
// Set up the transient repository ...
- logger.info(CommonI18n.passthrough, "Creating test repository for stress test and logging in with user " + USERNAME);
+ logger.info(MockI18n.passthrough, "Creating test repository for stress test and logging in with user " + USERNAME);
this.repository = new TransientRepository(REPOSITORY_CONFIG_PATH, REPOSITORY_DIRECTORY_PATH);
SimpleCredentials creds = new SimpleCredentials(USERNAME, PASSWORD);
@@ -95,7 +95,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(3).setBucketCount(50), 80, "create 100 nodes with no children and no properties");
- this.logger.info(CommonI18n.passthrough, stopwatch.toString());
+ this.logger.info(MockI18n.passthrough, stopwatch.toString());
}
@Test
@@ -109,7 +109,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(1).setBucketCount(50), 80, "create 1000 nodes with no children and no properties");
- this.logger.info(CommonI18n.passthrough, stopwatch.toString());
+ this.logger.info(MockI18n.passthrough, stopwatch.toString());
}
@Test
@@ -123,7 +123,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(1).setBucketCount(50), 80, "create 5000 nodes with no children and no properties");
- this.logger.info(CommonI18n.passthrough, stopwatch.toString());
+ this.logger.info(MockI18n.passthrough, stopwatch.toString());
}
@Test
@@ -137,7 +137,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(1).setBucketCount(50), 80, "create 10000 nodes with no children and no properties");
- this.logger.info(CommonI18n.passthrough, stopwatch.toString());
+ this.logger.info(MockI18n.passthrough, stopwatch.toString());
}
@Test
@@ -153,7 +153,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(3).setBucketCount(50), 80, "create 100 nodes with no children and several properties");
- this.logger.info(CommonI18n.passthrough, stopwatch.toString());
+ this.logger.info(MockI18n.passthrough, stopwatch.toString());
}
//
// @Test
Modified: trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitInMemoryTest.java
===================================================================
--- trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitInMemoryTest.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitInMemoryTest.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -27,7 +27,7 @@
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.core.TransientRepository;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.stats.HistogramTest;
import org.jboss.dna.common.stats.Stopwatch;
import org.jboss.dna.common.util.FileUtil;
@@ -64,7 +64,7 @@
logger = Logger.getLogger(JackrabbitInMemoryTest.class);
// Set up the transient repository ...
- logger.info(CommonI18n.passthrough, "Creating test repository for stress test and logging in with user " + USERNAME);
+ logger.info(MockI18n.passthrough, "Creating test repository for stress test and logging in with user " + USERNAME);
this.repository = new TransientRepository(REPOSITORY_CONFIG_PATH, REPOSITORY_DIRECTORY_PATH);
SimpleCredentials creds = new SimpleCredentials(USERNAME, PASSWORD);
@@ -119,7 +119,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, nodeStopwatch.getHistogram(3).setBucketCount(50), 80, "create 100 nodes with no children and no properties");
- this.logger.info(CommonI18n.passthrough, nodeStopwatch.toString());
+ this.logger.info(MockI18n.passthrough, nodeStopwatch.toString());
}
@Test
@@ -133,8 +133,8 @@
HistogramTest.writeHistogramToLog(logger, nodeStopwatch.getHistogram(3).setBucketCount(50), 80, "create tree of " + numNodes + " nodes (2 deep, 10 children at every node)");
HistogramTest.writeHistogramToLog(logger, saveStopwatch.getHistogram(3).setBucketCount(50), 80, "1 save of 2x10 tree of " + numNodes + " nodes");
- this.logger.info(CommonI18n.passthrough, "Node operation times: " + nodeStopwatch.toString());
- this.logger.info(CommonI18n.passthrough, "Save times: " + saveStopwatch.toString());
+ this.logger.info(MockI18n.passthrough, "Node operation times: " + nodeStopwatch.toString());
+ this.logger.info(MockI18n.passthrough, "Save times: " + saveStopwatch.toString());
}
@Test
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -28,11 +28,9 @@
import java.util.concurrent.atomic.AtomicInteger;
import javax.jcr.Node;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.monitor.ProgressMonitor;
import org.jboss.dna.repository.observation.NodeChange;
-import org.jboss.dna.repository.sequencers.Sequencer;
-import org.jboss.dna.repository.sequencers.SequencerConfig;
import org.jboss.dna.repository.util.ExecutionContext;
import org.jboss.dna.repository.util.RepositoryNodePath;
@@ -67,7 +65,7 @@
*/
public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, ExecutionContext context, ProgressMonitor progress ) {
try {
- progress.beginTask(1, CommonI18n.passthrough, "Incrementing counter");
+ progress.beginTask(1, MockI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
this.latch.countDown();
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java 2008-04-22 17:35:34 UTC (rev 103)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java 2008-04-22 20:42:49 UTC (rev 104)
@@ -28,11 +28,9 @@
import java.util.concurrent.atomic.AtomicInteger;
import javax.jcr.Node;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.monitor.ProgressMonitor;
import org.jboss.dna.repository.observation.NodeChange;
-import org.jboss.dna.repository.sequencers.Sequencer;
-import org.jboss.dna.repository.sequencers.SequencerConfig;
import org.jboss.dna.repository.util.ExecutionContext;
import org.jboss.dna.repository.util.RepositoryNodePath;
@@ -67,7 +65,7 @@
*/
public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, ExecutionContext context, ProgressMonitor progress ) {
try {
- progress.beginTask(1, CommonI18n.passthrough, "Incrementing counter");
+ progress.beginTask(1, MockI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
this.latch.countDown();
16 years
DNA SVN: r103 - trunk/dna-integration-tests.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-04-22 13:35:34 -0400 (Tue, 22 Apr 2008)
New Revision: 103
Modified:
trunk/dna-integration-tests/pom.xml
Log:
DNA-54: Set up continuous integration with Hudson
http://jira.jboss.org/jira/browse/DNA-54
Changed the "dna-integration-tests" project to run the unit tests only during the "integration-test" phase of Maven.
Modified: trunk/dna-integration-tests/pom.xml
===================================================================
--- trunk/dna-integration-tests/pom.xml 2008-04-22 16:05:24 UTC (rev 102)
+++ trunk/dna-integration-tests/pom.xml 2008-04-22 17:35:34 UTC (rev 103)
@@ -99,4 +99,29 @@
<artifactId>derby</artifactId>
</dependency>
</dependencies>
+ <!--
+ Build configuration - run integration tests only in 'integration' phase
+ -->
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skip>false</skip>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</project>
16 years
DNA SVN: r102 - trunk/dna-common/src/main/java/org/jboss/dna/common/i18n.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-04-22 12:05:24 -0400 (Tue, 22 Apr 2008)
New Revision: 102
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java
Log:
DNA-27: Oops, forgot to remove an old assertion.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java 2008-04-22 15:59:38 UTC (rev 101)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java 2008-04-22 16:05:24 UTC (rev 102)
@@ -355,9 +355,7 @@
id2TextMap = initializeIdToTextMap(localization);
}
- String text = id2TextMap.get(id);
- assert text != null;
- return text;
+ return id2TextMap.get(id);
}
/**
16 years
DNA SVN: r101 - trunk/dna-maven-classloader.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-04-22 11:59:38 -0400 (Tue, 22 Apr 2008)
New Revision: 101
Modified:
trunk/dna-maven-classloader/.project
Log:
Renamed Eclipse project to match Maven project name
Modified: trunk/dna-maven-classloader/.project
===================================================================
--- trunk/dna-maven-classloader/.project 2008-04-22 15:46:10 UTC (rev 100)
+++ trunk/dna-maven-classloader/.project 2008-04-22 15:59:38 UTC (rev 101)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>dna-maven</name>
+ <name>dna-maven-classloader</name>
<comment></comment>
<projects>
</projects>
16 years
DNA SVN: r100 - in trunk: dna-repository and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-04-22 11:46:10 -0400 (Tue, 22 Apr 2008)
New Revision: 100
Modified:
trunk/dna-repository/pom.xml
trunk/pom.xml
Log:
Corrected parent pom.xml and removed dependency in dna-repository to dna-maven-classloader
Modified: trunk/dna-repository/pom.xml
===================================================================
--- trunk/dna-repository/pom.xml 2008-04-22 15:16:43 UTC (rev 99)
+++ trunk/dna-repository/pom.xml 2008-04-22 15:46:10 UTC (rev 100)
@@ -23,11 +23,6 @@
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
- <artifactId>dna-maven-classloader</artifactId>
- <version>0.1-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.jboss.dna</groupId>
<artifactId>dna-common</artifactId>
<version>0.1-SNAPSHOT</version>
<type>test-jar</type>
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2008-04-22 15:16:43 UTC (rev 99)
+++ trunk/pom.xml 2008-04-22 15:46:10 UTC (rev 100)
@@ -10,9 +10,10 @@
<description>JBoss DNA (aggregator)</description>
<modules>
<module>dna-common</module>
- <module>dna-maven-classloader</module>
+ <module>dna-spi</module>
<module>dna-repository</module>
<module>sequencers/dna-sequencer-images</module>
+ <module>dna-maven-classloader</module>
<module>dna-integration-tests</module>
</modules>
<build>
16 years
DNA SVN: r99 - in trunk: dna-common/src/main/java/org/jboss/dna/common/component and 12 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-04-22 11:16:43 -0400 (Tue, 22 Apr 2008)
New Revision: 99
Added:
trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java
trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties
Removed:
trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java
trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentConfig.java
trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentLibrary.java
trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java
trunk/dna-common/src/main/java/org/jboss/dna/common/jcr/Path.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingProgressMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/util/ArgCheck.java
trunk/dna-common/src/main/java/org/jboss/dna/common/util/ClassUtil.java
trunk/dna-common/src/main/java/org/jboss/dna/common/util/DateUtil.java
trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java
trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java
trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java
trunk/dna-common/src/test/java/org/jboss/dna/common/stats/HistogramTest.java
trunk/dna-common/src/test/java/org/jboss/dna/common/util/LogContextTest.java
trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitBasicFunctionTest.java
trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitDerbyStressTest.java
trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitInMemoryTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java
Log:
DNA-56: Rename CoreI18n to CommonI18n
http://jira.jboss.org/jira/browse/DNA-56
Renamed class and properties file.
Copied: trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java (from rev 98, trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java)
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -0,0 +1,95 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.common;
+
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author John Verhaeg
+ * @author Randall Hauch
+ */
+public final class CommonI18n {
+
+ static {
+ try {
+ I18n.initialize(CommonI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ // Make sure the following I18n.java-related fields are defined before all other fields to ensure a valid error message is
+ // produced in the event of a missing/duplicate/unused property
+
+ public static I18n i18nArgumentsMismatchedParameter;
+ public static I18n i18nArgumentMismatchedParameters;
+ public static I18n i18nArgumentsMismatchedParameters;
+ public static I18n i18nReplaceArgumentsMismatchedParameter;
+ public static I18n i18nReplaceArgumentMismatchedParameters;
+ public static I18n i18nReplaceArgumentsMismatchedParameters;
+ public static I18n i18nClassInterface;
+ public static I18n i18nClassNotPublic;
+ public static I18n i18nFieldFinal;
+ public static I18n i18nFieldInvalidType;
+ public static I18n i18nFieldNotPublic;
+ public static I18n i18nFieldNotStatic;
+ public static I18n i18nPropertiesFileNotFound;
+ public static I18n i18nPropertyDuplicate;
+ public static I18n i18nPropertyMissing;
+ public static I18n i18nPropertyUnused;
+
+ // Core-related fields
+ public static I18n componentClassnameNotValid;
+ public static I18n componentNotConfigured;
+ public static I18n progressMonitorBeginTask;
+ public static I18n progressMonitorStatus;
+
+ public static I18n argumentMayNotBeNegative;
+ public static I18n argumentMayNotBePositive;
+ public static I18n argumentMustBeNegative;
+ public static I18n argumentMustBePositive;
+ public static I18n argumentMustBeNumber;
+ public static I18n argumentMayNotBeNullOrZeroLength;
+ public static I18n argumentMayNotBeNullOrZeroLengthOrEmpty;
+ public static I18n argumentMayNotBeNull;
+ public static I18n argumentMustBeNull;
+ public static I18n argumentMustBeInstanceOf;
+ public static I18n argumentMustBeSameAs;
+ public static I18n argumentMustNotBeSameAs;
+ public static I18n argumentMustBeEquals;
+ public static I18n argumentMustNotBeEquals;
+ public static I18n argumentMayNotBeEmpty;
+ public static I18n argumentDidNotContainObject;
+ public static I18n argumentDidNotContainKey;
+ public static I18n argumentMayNotContainNullValue;
+
+ public static I18n dateParsingFailure;
+
+ public static I18n pathAncestorDegreeIsInvalid;
+ public static I18n pathIsAlreadyAbsolute;
+ public static I18n pathIsNotAbsolute;
+ public static I18n pathIsNotRelative;
+ public static I18n pathCannotBeNormalized;
+
+ public static I18n passthrough;
+ public static I18n empty;
+}
Deleted: trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -1,95 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.common;
-
-import org.jboss.dna.common.i18n.I18n;
-
-/**
- * @author John Verhaeg
- * @author Randall Hauch
- */
-public final class CoreI18n {
-
- static {
- try {
- I18n.initialize(CoreI18n.class);
- } catch (final Exception err) {
- System.err.println(err);
- }
- }
-
- // Make sure the following I18n.java-related fields are defined before all other fields to ensure a valid error message is
- // produced in the event of a missing/duplicate/unused property
-
- public static I18n i18nArgumentsMismatchedParameter;
- public static I18n i18nArgumentMismatchedParameters;
- public static I18n i18nArgumentsMismatchedParameters;
- public static I18n i18nReplaceArgumentsMismatchedParameter;
- public static I18n i18nReplaceArgumentMismatchedParameters;
- public static I18n i18nReplaceArgumentsMismatchedParameters;
- public static I18n i18nClassInterface;
- public static I18n i18nClassNotPublic;
- public static I18n i18nFieldFinal;
- public static I18n i18nFieldInvalidType;
- public static I18n i18nFieldNotPublic;
- public static I18n i18nFieldNotStatic;
- public static I18n i18nPropertiesFileNotFound;
- public static I18n i18nPropertyDuplicate;
- public static I18n i18nPropertyMissing;
- public static I18n i18nPropertyUnused;
-
- // Core-related fields
- public static I18n componentClassnameNotValid;
- public static I18n componentNotConfigured;
- public static I18n progressMonitorBeginTask;
- public static I18n progressMonitorStatus;
-
- public static I18n argumentMayNotBeNegative;
- public static I18n argumentMayNotBePositive;
- public static I18n argumentMustBeNegative;
- public static I18n argumentMustBePositive;
- public static I18n argumentMustBeNumber;
- public static I18n argumentMayNotBeNullOrZeroLength;
- public static I18n argumentMayNotBeNullOrZeroLengthOrEmpty;
- public static I18n argumentMayNotBeNull;
- public static I18n argumentMustBeNull;
- public static I18n argumentMustBeInstanceOf;
- public static I18n argumentMustBeSameAs;
- public static I18n argumentMustNotBeSameAs;
- public static I18n argumentMustBeEquals;
- public static I18n argumentMustNotBeEquals;
- public static I18n argumentMayNotBeEmpty;
- public static I18n argumentDidNotContainObject;
- public static I18n argumentDidNotContainKey;
- public static I18n argumentMayNotContainNullValue;
-
- public static I18n dateParsingFailure;
-
- public static I18n pathAncestorDegreeIsInvalid;
- public static I18n pathIsAlreadyAbsolute;
- public static I18n pathIsNotAbsolute;
- public static I18n pathIsNotRelative;
- public static I18n pathCannotBeNormalized;
-
- public static I18n passthrough;
- public static I18n empty;
-}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentConfig.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentConfig.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentConfig.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -25,7 +25,7 @@
import java.util.Collections;
import java.util.List;
import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.util.ArgCheck;
import org.jboss.dna.common.util.ClassUtil;
@@ -73,7 +73,7 @@
this.timestamp = timestamp;
// Check the classname is a valid classname ...
if (!ClassUtil.isFullyQualifiedClassname(classname)) {
- throw new IllegalArgumentException(CoreI18n.componentClassnameNotValid.text(classname, name));
+ throw new IllegalArgumentException(CommonI18n.componentClassnameNotValid.text(classname, name));
}
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentLibrary.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentLibrary.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentLibrary.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -30,7 +30,7 @@
import java.util.concurrent.locks.ReentrantLock;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.SystemFailureException;
import org.jboss.dna.common.util.ArgCheck;
@@ -210,7 +210,7 @@
throw new SystemFailureException(e);
}
if (newInstance instanceof Component && ((Component<ConfigType>)newInstance).getConfiguration() == null) {
- throw new SystemFailureException(CoreI18n.componentNotConfigured.text(config.getName()));
+ throw new SystemFailureException(CommonI18n.componentNotConfigured.text(config.getName()));
}
return newInstance;
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -37,7 +37,7 @@
import java.util.regex.Pattern;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.SystemFailureException;
import org.jboss.dna.common.util.ArgCheck;
import org.jboss.dna.common.util.ClassUtil;
@@ -119,7 +119,7 @@
public static void initialize( Class i18nClass ) {
ArgCheck.isNotNull(i18nClass, "i18nClass");
if (i18nClass.isInterface()) {
- throw new IllegalArgumentException(CoreI18n.i18nClassInterface.text(i18nClass.getName()));
+ throw new IllegalArgumentException(CommonI18n.i18nClassInterface.text(i18nClass.getName()));
}
// Find all public static non-final String fields in the specified class and instantiate an I18n object for each.
@@ -131,17 +131,17 @@
// Ensure field is not final
if ((fld.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
- throw new SystemFailureException(CoreI18n.i18nFieldFinal.text(fld.getName(), i18nClass));
+ throw new SystemFailureException(CommonI18n.i18nFieldFinal.text(fld.getName(), i18nClass));
}
// Ensure field is public
if ((fld.getModifiers() & Modifier.PUBLIC) != Modifier.PUBLIC) {
- throw new SystemFailureException(CoreI18n.i18nFieldNotPublic.text(fld.getName(), i18nClass));
+ throw new SystemFailureException(CommonI18n.i18nFieldNotPublic.text(fld.getName(), i18nClass));
}
// Ensure field is static
if ((fld.getModifiers() & Modifier.STATIC) != Modifier.STATIC) {
- throw new SystemFailureException(CoreI18n.i18nFieldNotStatic.text(fld.getName(), i18nClass));
+ throw new SystemFailureException(CommonI18n.i18nFieldNotStatic.text(fld.getName(), i18nClass));
}
// Ensure we can access field even if it's in a private class
@@ -152,7 +152,7 @@
}
}
} catch (IllegalAccessException err) {
- throw new IllegalArgumentException(CoreI18n.i18nClassNotPublic.text(i18nClass.getName()));
+ throw new IllegalArgumentException(CommonI18n.i18nClassNotPublic.text(i18nClass.getName()));
}
}
@@ -193,7 +193,7 @@
String bundleMsg = null;
if (url == null) {
// Record no variant of the i18n properties file for the specified class found
- bundleMsg = CoreI18n.i18nPropertiesFileNotFound.text(bundleName);
+ bundleMsg = CommonI18n.i18nPropertiesFileNotFound.text(bundleName);
} else {
// Initialize i18n map
final Map<String, String> finalMap = id2TextMap;
@@ -210,18 +210,18 @@
Field fld = localization.i18nClass.getDeclaredField(id);
if (fld.getType() != I18n.class) {
// Invalid field type
- mapErrorMessage(localization, id, CoreI18n.i18nFieldInvalidType.text(id,
+ mapErrorMessage(localization, id, CommonI18n.i18nFieldInvalidType.text(id,
finalUrl,
getClass().getName()));
}
} catch (NoSuchFieldException err) {
// No corresponding field exists
- mapErrorMessage(localization, id, CoreI18n.i18nPropertyUnused.text(id, finalUrl));
+ mapErrorMessage(localization, id, CommonI18n.i18nPropertyUnused.text(id, finalUrl));
}
if (finalMap.put(id, text) != null) {
// Duplicate id encountered
- mapErrorMessage(localization, id, CoreI18n.i18nPropertyDuplicate.text(id, finalUrl));
+ mapErrorMessage(localization, id, CommonI18n.i18nPropertyDuplicate.text(id, finalUrl));
}
return null;
@@ -245,7 +245,7 @@
if (fld.getType() == I18n.class && id2TextMap.get(fld.getName()) == null) {
mapErrorMessage(localization,
fld.getName(),
- bundleMsg == null ? CoreI18n.i18nPropertyMissing.text(fld.getName(), url) : bundleMsg);
+ bundleMsg == null ? CommonI18n.i18nPropertyMissing.text(fld.getName(), url) : bundleMsg);
}
}
@@ -302,20 +302,20 @@
I18n msg = null;
if (id != null) {
if (arguments.length == 1) {
- msg = CoreI18n.i18nArgumentMismatchedParameters;
+ msg = CommonI18n.i18nArgumentMismatchedParameters;
} else if (argCount == 1) {
- msg = CoreI18n.i18nArgumentsMismatchedParameter;
+ msg = CommonI18n.i18nArgumentsMismatchedParameter;
} else {
- msg = CoreI18n.i18nArgumentsMismatchedParameters;
+ msg = CommonI18n.i18nArgumentsMismatchedParameters;
}
throw new IllegalArgumentException(msg.text(arguments.length, id, argCount, text, newText.toString()));
}
if (arguments.length == 1) {
- msg = CoreI18n.i18nReplaceArgumentMismatchedParameters;
+ msg = CommonI18n.i18nReplaceArgumentMismatchedParameters;
} else if (argCount == 1) {
- msg = CoreI18n.i18nReplaceArgumentsMismatchedParameter;
+ msg = CommonI18n.i18nReplaceArgumentsMismatchedParameter;
} else {
- msg = CoreI18n.i18nReplaceArgumentsMismatchedParameters;
+ msg = CommonI18n.i18nReplaceArgumentsMismatchedParameters;
}
throw new IllegalArgumentException(msg.text(arguments.length, argCount, text, newText.toString()));
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/jcr/Path.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/jcr/Path.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/jcr/Path.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -30,7 +30,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.text.Inflector;
import org.jboss.dna.common.text.Jsr283Encoder;
import org.jboss.dna.common.text.NoOpEncoder;
@@ -449,7 +449,7 @@
if (segment.equals(PARENT_SEGMENT)) {
if (newSegments.size() <= 0) {
if (this.isAbsolute()) {
- throw new InvalidPathException(CoreI18n.pathCannotBeNormalized.text(this));
+ throw new InvalidPathException(CommonI18n.pathCannotBeNormalized.text(this));
}
}
if (newSegments.size() > 0 && !newSegments.getLast().equals(PARENT_SEGMENT)) {
@@ -474,7 +474,7 @@
*/
public Path getCanonicalPath() {
if (!this.isAbsolute()) {
- String msg = CoreI18n.pathIsNotAbsolute.text(this);
+ String msg = CommonI18n.pathIsNotAbsolute.text(this);
throw new InvalidPathException(msg);
}
if (this.isNormalized()) return this;
@@ -491,11 +491,11 @@
public Path relativeTo( Path startingPath ) {
ArgCheck.isNotNull(startingPath, "to");
if (!this.isAbsolute()) {
- String msg = CoreI18n.pathIsNotAbsolute.text(this);
+ String msg = CommonI18n.pathIsNotAbsolute.text(this);
throw new InvalidPathException(msg);
}
if (!startingPath.isAbsolute()) {
- String msg = CoreI18n.pathIsNotAbsolute.text(startingPath);
+ String msg = CommonI18n.pathIsNotAbsolute.text(startingPath);
throw new InvalidPathException(msg);
}
@@ -540,11 +540,11 @@
public Path resolve( Path relativePath ) {
ArgCheck.isNotNull(relativePath, "relative path");
if (!this.isAbsolute()) {
- String msg = CoreI18n.pathIsAlreadyAbsolute.text(this.path);
+ String msg = CommonI18n.pathIsAlreadyAbsolute.text(this.path);
throw new InvalidPathException(msg);
}
if (relativePath.isAbsolute()) {
- String msg = CoreI18n.pathIsNotRelative.text(relativePath);
+ String msg = CommonI18n.pathIsNotRelative.text(relativePath);
throw new InvalidPathException(msg);
}
// If the relative path is the self or parent reference ...
@@ -655,7 +655,7 @@
if (this.isRoot()) return this;
int endIndex = this.segments.size() - degree;
if (endIndex < 0) {
- String msg = CoreI18n.pathAncestorDegreeIsInvalid.text(this.path, Inflector.getInstance().ordinalize(degree));
+ String msg = CommonI18n.pathAncestorDegreeIsInvalid.text(this.path, Inflector.getInstance().ordinalize(degree));
throw new PathNotFoundException(msg);
}
return createPath(this.segments.subList(0, endIndex), this.isAbsolute());
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingProgressMonitor.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingProgressMonitor.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingProgressMonitor.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -22,7 +22,7 @@
package org.jboss.dna.common.monitor;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.Logger;
@@ -48,7 +48,7 @@
@Override
public void beginTask( double totalWork, I18n name, Object... params ) {
super.beginTask(totalWork, name, params);
- this.logger.log(level, CoreI18n.progressMonitorBeginTask, getActivityName(), name.text(params));
+ this.logger.log(level, CommonI18n.progressMonitorBeginTask, getActivityName(), name.text(params));
}
/**
@@ -57,7 +57,7 @@
@Override
public void done() {
super.done();
- this.logger.log(level, CoreI18n.progressMonitorStatus, super.getStatus());
+ this.logger.log(level, CommonI18n.progressMonitorStatus, super.getStatus());
}
/**
@@ -66,7 +66,7 @@
@Override
public void setCancelled( boolean value ) {
super.setCancelled(value);
- this.logger.log(level, CoreI18n.progressMonitorStatus, super.getStatus());
+ this.logger.log(level, CommonI18n.progressMonitorStatus, super.getStatus());
}
/**
@@ -75,7 +75,7 @@
@Override
public void worked( double work ) {
super.worked(work);
- this.logger.log(level, CoreI18n.progressMonitorStatus, super.getStatus());
+ this.logger.log(level, CommonI18n.progressMonitorStatus, super.getStatus());
}
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -25,7 +25,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.i18n.I18n;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
@@ -54,7 +54,7 @@
public SimpleProgressMonitor( String activityName ) {
this.activityName = activityName != null ? activityName.trim() : "";
- this.taskName = CoreI18n.empty;
+ this.taskName = CommonI18n.empty;
}
/**
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/ArgCheck.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/ArgCheck.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/ArgCheck.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -24,7 +24,7 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
/**
* Utility class that checks arguments to methods. This class is to be used only in API methods, where failure to supply correct
@@ -42,7 +42,7 @@
*/
public static void isNonNegative( int argument, String name ) {
if (argument < 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeNegative.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeNegative.text(name, argument));
}
}
@@ -54,7 +54,7 @@
*/
public static void isNonPositive( int argument, String name ) {
if (argument > 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBePositive.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBePositive.text(name, argument));
}
}
@@ -66,7 +66,7 @@
*/
public static void isNegative( int argument, String name ) {
if (argument >= 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBeNegative.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeNegative.text(name, argument));
}
}
@@ -78,7 +78,7 @@
*/
public static void isPositive( int argument, String name ) {
if (argument <= 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBePositive.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBePositive.text(name, argument));
}
}
@@ -92,7 +92,7 @@
*/
public static void isNonNegative( long argument, String name ) {
if (argument < 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeNegative.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeNegative.text(name, argument));
}
}
@@ -104,7 +104,7 @@
*/
public static void isNonPositive( long argument, String name ) {
if (argument > 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBePositive.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBePositive.text(name, argument));
}
}
@@ -116,7 +116,7 @@
*/
public static void isNegative( long argument, String name ) {
if (argument >= 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBeNegative.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeNegative.text(name, argument));
}
}
@@ -128,7 +128,7 @@
*/
public static void isPositive( long argument, String name ) {
if (argument <= 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBePositive.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBePositive.text(name, argument));
}
}
@@ -142,7 +142,7 @@
*/
public static void isNonNegative( double argument, String name ) {
if (argument < 0.0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeNegative.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeNegative.text(name, argument));
}
}
@@ -154,7 +154,7 @@
*/
public static void isNonPositive( double argument, String name ) {
if (argument > 0.0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBePositive.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBePositive.text(name, argument));
}
}
@@ -166,7 +166,7 @@
*/
public static void isNegative( double argument, String name ) {
if (argument >= 0.0) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBeNegative.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeNegative.text(name, argument));
}
}
@@ -178,7 +178,7 @@
*/
public static void isPositive( double argument, String name ) {
if (argument <= 0.0) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBePositive.text(name, argument));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBePositive.text(name, argument));
}
}
@@ -190,7 +190,7 @@
*/
public static void isNotNan( double argument, String name ) {
if (Double.isNaN(argument)) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBeNumber.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeNumber.text(name));
}
}
@@ -205,7 +205,7 @@
public static void isNotZeroLength( String argument, String name ) {
isNotNull(argument, name);
if (argument.length() <= 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeNullOrZeroLength.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeNullOrZeroLength.text(name));
}
}
@@ -218,7 +218,7 @@
public static void isNotEmpty( String argument, String name ) {
isNotZeroLength(argument, name);
if (argument != null && argument.trim().length() == 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeNullOrZeroLengthOrEmpty.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeNullOrZeroLengthOrEmpty.text(name));
}
}
@@ -232,7 +232,7 @@
*/
public static void isNotNull( Object argument, String name ) {
if (argument == null) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeNull.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeNull.text(name));
}
}
@@ -257,7 +257,7 @@
*/
public static void isNull( Object argument, String name ) {
if (argument != null) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBeNull.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeNull.text(name));
}
}
@@ -271,7 +271,7 @@
public static void isInstanceOf( Object argument, Class expectedClass, String name ) {
isNotNull(argument, name);
if (!expectedClass.isInstance(argument)) {
- throw new IllegalArgumentException(CoreI18n.argumentMustBeInstanceOf.text(name, argument.getClass(), expectedClass.getName()));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeInstanceOf.text(name, argument.getClass(), expectedClass.getName()));
}
}
@@ -305,7 +305,7 @@
public static <T> void isSame( final T argument, String argumentName, final T object, String objectName ) {
if (argument != object) {
if (objectName == null) objectName = getObjectName(object);
- throw new IllegalArgumentException(CoreI18n.argumentMustBeSameAs.text(argumentName, objectName));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeSameAs.text(argumentName, objectName));
}
}
@@ -323,7 +323,7 @@
public static <T> void isNotSame( final T argument, String argumentName, final T object, String objectName ) {
if (argument == object) {
if (objectName == null) objectName = getObjectName(object);
- throw new IllegalArgumentException(CoreI18n.argumentMustNotBeSameAs.text(argumentName, objectName));
+ throw new IllegalArgumentException(CommonI18n.argumentMustNotBeSameAs.text(argumentName, objectName));
}
}
@@ -341,7 +341,7 @@
public static <T> void isEquals( final T argument, String argumentName, final T object, String objectName ) {
if (!argument.equals(object)) {
if (objectName == null) objectName = getObjectName(object);
- throw new IllegalArgumentException(CoreI18n.argumentMustBeEquals.text(argumentName, objectName));
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeEquals.text(argumentName, objectName));
}
}
@@ -359,7 +359,7 @@
public static <T> void isNotEquals( final T argument, String argumentName, final T object, String objectName ) {
if (argument.equals(object)) {
if (objectName == null) objectName = getObjectName(object);
- throw new IllegalArgumentException(CoreI18n.argumentMustNotBeEquals.text(argumentName, objectName));
+ throw new IllegalArgumentException(CommonI18n.argumentMustNotBeEquals.text(argumentName, objectName));
}
}
@@ -374,7 +374,7 @@
public static void isNotEmpty( Iterator argument, String name ) {
isNotNull(argument, name);
if (!argument.hasNext()) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeEmpty.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeEmpty.text(name));
}
}
@@ -389,7 +389,7 @@
public static void isNotEmpty( Collection argument, String name ) {
isNotNull(argument, name);
if (argument.isEmpty()) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeEmpty.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeEmpty.text(name));
}
}
@@ -402,7 +402,7 @@
public static void isNotEmpty( Map argument, String name ) {
isNotNull(argument, name);
if (argument.isEmpty()) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeEmpty.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeEmpty.text(name));
}
}
@@ -415,7 +415,7 @@
public static void isNotEmpty( Object[] argument, String name ) {
isNotNull(argument, name);
if (argument.length == 0) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotBeEmpty.text(name));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotBeEmpty.text(name));
}
}
@@ -433,7 +433,7 @@
public static void contains( Collection argument, Object value, String name ) {
isNotNull(argument, name);
if (!argument.contains(value)) {
- throw new IllegalArgumentException(CoreI18n.argumentDidNotContainObject.text(name, getObjectName(value)));
+ throw new IllegalArgumentException(CommonI18n.argumentDidNotContainObject.text(name, getObjectName(value)));
}
}
@@ -447,7 +447,7 @@
public static void containsKey( Map argument, Object key, String name ) {
isNotNull(argument, name);
if (!argument.containsKey(key)) {
- throw new IllegalArgumentException(CoreI18n.argumentDidNotContainKey.text(name, getObjectName(key)));
+ throw new IllegalArgumentException(CommonI18n.argumentDidNotContainKey.text(name, getObjectName(key)));
}
}
@@ -462,7 +462,7 @@
int i = 0;
for (Object object : argument) {
if (object == null) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotContainNullValue.text(name, i));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotContainNullValue.text(name, i));
}
++i;
}
@@ -479,7 +479,7 @@
int i = 0;
for (Object object : argument) {
if (object == null) {
- throw new IllegalArgumentException(CoreI18n.argumentMayNotContainNullValue.text(name, i));
+ throw new IllegalArgumentException(CommonI18n.argumentMayNotContainNullValue.text(name, i));
}
++i;
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/ClassUtil.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/ClassUtil.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/ClassUtil.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -118,7 +118,7 @@
*/
public static String nonPackageQualifiedName( final Class clazz ) {
// if (clazz == null) {
- // throw new IllegalArgumentException(I18n.format(CoreI18n.mustNotBeNull, "Class")); //$NON-NLS-1$
+ // throw new IllegalArgumentException(I18n.format(CommonI18n.mustNotBeNull, "Class")); //$NON-NLS-1$
// }
String name = clazz.getName();
return name.substring(name.lastIndexOf('.') + 1);
@@ -131,7 +131,7 @@
*/
public static String nonPackageQualifiedName( final Object object ) {
// if (object == null) {
- // throw new IllegalArgumentException(I18n.format(CoreI18n.mustNotBeNull, "Object")); //$NON-NLS-1$
+ // throw new IllegalArgumentException(I18n.format(CommonI18n.mustNotBeNull, "Object")); //$NON-NLS-1$
// }
return nonPackageQualifiedName(object.getClass());
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/DateUtil.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/DateUtil.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/DateUtil.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -30,7 +30,7 @@
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import net.jcip.annotations.ThreadSafe;
/**
@@ -157,7 +157,7 @@
final Pattern pattern = Pattern.compile(regex);
final Matcher matcher = pattern.matcher(dateString);
if (!matcher.matches()) {
- throw new ParseException(CoreI18n.dateParsingFailure.text(dateString), 0);
+ throw new ParseException(CommonI18n.dateParsingFailure.text(dateString), 0);
}
String year = matcher.group(1);
String week = matcher.group(4);
Copied: trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties (from rev 98, trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties)
===================================================================
--- trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties (rev 0)
+++ trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties 2008-04-22 15:16:43 UTC (rev 99)
@@ -0,0 +1,55 @@
+# Make sure the following I18n.java-related properties are defined before all other properties to ensure a valid error message is
+# produced in the event of a missing/duplicate/unused property
+
+i18nArgumentsMismatchedParameter = {0} arguments were specified for internationalization object "{1}", but {2} parameter is required: "{3}" => "{4}"
+i18nArgumentMismatchedParameters = {0} argument was specified for internationalization object "{1}", but {2} parameters are required: "{3}" => "{4}"
+i18nArgumentsMismatchedParameters = {0} arguments were specified for internationalization object "{1}", but {2} parameters are required: "{3}" => "{4}"
+i18nReplaceArgumentsMismatchedParameter = {0} arguments were specified, but {1} parameter is required: "{2}" => "{3}"
+i18nReplaceArgumentMismatchedParameters = {0} argument was specified, but {1} parameters are required: "{2}" => "{3}"
+i18nReplaceArgumentsMismatchedParameters = {0} arguments were specified, but {1} parameters are required: "{2}" => "{3}"
+i18nClassInterface = Class {0} must not be an interface.
+i18nClassNotPublic = Class {0} must be public.
+i18nFieldFinal = Internationalization field "{0}" in {1} must not be final.
+i18nFieldInvalidType = Internationalization field "{0}" in {1} must be of type {2}.
+i18nFieldNotPublic = Internationalization field "{0}" in {1} must be public.
+i18nFieldNotStatic = Internationalization field "{0}" in {1} must be static.
+i18nPropertiesFileNotFound = No variant of the localization file for "{0}" could be found.
+i18nPropertyDuplicate = Duplicate property values were found for property "{0}" in localization file "{1}";
+i18nPropertyMissing = Missing property "{0}" in localization file {1}.
+i18nPropertyUnused = An unused property, "{0}", was found in localization file "{1}".
+
+# Core-related fields
+componentClassnameNotValid = The class name {0} specified for {1} is not a valid Java class name
+componentNotConfigured = The component {0} was not configured and will not be used
+progressMonitorBeginTask = Beginning {0} ({1})
+progressMonitorStatus = {0}
+
+argumentMayNotBeNegative = The {0} argument value, {1}, may not be negative
+argumentMayNotBePositive = The {0} argument value, {1}, may not be positive
+argumentMustBeNegative = The {0} argument value, {1}, must be negative
+argumentMustBePositive = The {0} argument value, {1}, must be positive
+argumentMustBeNumber = The {0} argument value must be a number
+argumentMayNotBeNullOrZeroLength = The {0} argument may not be null or zero-length
+argumentMayNotBeNullOrZeroLengthOrEmpty = The {0} argument may not be empty or contain only whitespace
+argumentMayNotBeNull = The {0} argument may not be null
+argumentMustBeNull = The {0} argument must be null
+argumentMustBeInstanceOf = The {0} argument was an instance of {1} but was expected to be an instance of {2}
+argumentMustBeSameAs = The {0} argument is not the same as "{1}"
+argumentMustNotBeSameAs = The {0} argument is the same as "{1}"
+argumentMustBeEquals = The {0} argument is not equal to {1}
+argumentMustNotBeEquals = The {0} argument is equal to {1}
+argumentMayNotBeEmpty = The {0} argument may not be empty
+argumentDidNotContainObject = "The {0} argument did not contain the expected object {1}
+argumentDidNotContainKey = "The {0} argument did not contain the expected key {1}
+argumentMayNotContainNullValue = The {0} argument may not contain a null value (first null found at position {1})
+
+pathAncestorDegreeIsInvalid = Unable to obtain the {1} ancestor for {0}
+pathIsAlreadyAbsolute = The path {0} is already an absolute path
+pathIsNotAbsolute = The path {0} is not an absolute path
+pathIsNotRelative = The path {0} is not a relative path
+pathCannotBeNormalized = The path {0} is invalid and cannot be normalized
+
+dateParsingFailure = Unable to parse the date "{0}" using the standard ISO 8601 format
+
+passthrough = {0}
+empty =
Deleted: trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties
===================================================================
--- trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties 2008-04-22 15:16:43 UTC (rev 99)
@@ -1,55 +0,0 @@
-# Make sure the following I18n.java-related properties are defined before all other properties to ensure a valid error message is
-# produced in the event of a missing/duplicate/unused property
-
-i18nArgumentsMismatchedParameter = {0} arguments were specified for internationalization object "{1}", but {2} parameter is required: "{3}" => "{4}"
-i18nArgumentMismatchedParameters = {0} argument was specified for internationalization object "{1}", but {2} parameters are required: "{3}" => "{4}"
-i18nArgumentsMismatchedParameters = {0} arguments were specified for internationalization object "{1}", but {2} parameters are required: "{3}" => "{4}"
-i18nReplaceArgumentsMismatchedParameter = {0} arguments were specified, but {1} parameter is required: "{2}" => "{3}"
-i18nReplaceArgumentMismatchedParameters = {0} argument was specified, but {1} parameters are required: "{2}" => "{3}"
-i18nReplaceArgumentsMismatchedParameters = {0} arguments were specified, but {1} parameters are required: "{2}" => "{3}"
-i18nClassInterface = Class {0} must not be an interface.
-i18nClassNotPublic = Class {0} must be public.
-i18nFieldFinal = Internationalization field "{0}" in {1} must not be final.
-i18nFieldInvalidType = Internationalization field "{0}" in {1} must be of type {2}.
-i18nFieldNotPublic = Internationalization field "{0}" in {1} must be public.
-i18nFieldNotStatic = Internationalization field "{0}" in {1} must be static.
-i18nPropertiesFileNotFound = No variant of the localization file for "{0}" could be found.
-i18nPropertyDuplicate = Duplicate property values were found for property "{0}" in localization file "{1}";
-i18nPropertyMissing = Missing property "{0}" in localization file {1}.
-i18nPropertyUnused = An unused property, "{0}", was found in localization file "{1}".
-
-# Core-related fields
-componentClassnameNotValid = The class name {0} specified for {1} is not a valid Java class name
-componentNotConfigured = The component {0} was not configured and will not be used
-progressMonitorBeginTask = Beginning {0} ({1})
-progressMonitorStatus = {0}
-
-argumentMayNotBeNegative = The {0} argument value, {1}, may not be negative
-argumentMayNotBePositive = The {0} argument value, {1}, may not be positive
-argumentMustBeNegative = The {0} argument value, {1}, must be negative
-argumentMustBePositive = The {0} argument value, {1}, must be positive
-argumentMustBeNumber = The {0} argument value must be a number
-argumentMayNotBeNullOrZeroLength = The {0} argument may not be null or zero-length
-argumentMayNotBeNullOrZeroLengthOrEmpty = The {0} argument may not be empty or contain only whitespace
-argumentMayNotBeNull = The {0} argument may not be null
-argumentMustBeNull = The {0} argument must be null
-argumentMustBeInstanceOf = The {0} argument was an instance of {1} but was expected to be an instance of {2}
-argumentMustBeSameAs = The {0} argument is not the same as "{1}"
-argumentMustNotBeSameAs = The {0} argument is the same as "{1}"
-argumentMustBeEquals = The {0} argument is not equal to {1}
-argumentMustNotBeEquals = The {0} argument is equal to {1}
-argumentMayNotBeEmpty = The {0} argument may not be empty
-argumentDidNotContainObject = "The {0} argument did not contain the expected object {1}
-argumentDidNotContainKey = "The {0} argument did not contain the expected key {1}
-argumentMayNotContainNullValue = The {0} argument may not contain a null value (first null found at position {1})
-
-pathAncestorDegreeIsInvalid = Unable to obtain the {1} ancestor for {0}
-pathIsAlreadyAbsolute = The path {0} is already an absolute path
-pathIsNotAbsolute = The path {0} is not an absolute path
-pathIsNotRelative = The path {0} is not a relative path
-pathCannotBeNormalized = The path {0} is invalid and cannot be normalized
-
-dateParsingFailure = Unable to parse the date "{0}" using the standard ISO 8601 format
-
-passthrough = {0}
-empty =
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -24,7 +24,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.monitor.ProgressMonitor;
/**
@@ -49,7 +49,7 @@
*/
public void doSomething( ProgressMonitor progressMonitor ) {
try {
- progressMonitor.beginTask(1, CoreI18n.passthrough, "Incrementing counter");
+ progressMonitor.beginTask(1, CommonI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
progressMonitor.worked(1);
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -24,7 +24,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.monitor.ProgressMonitor;
/**
@@ -49,7 +49,7 @@
*/
public void doSomething( ProgressMonitor progressMonitor ) {
try {
- progressMonitor.beginTask(1, CoreI18n.passthrough, "Incrementing counter");
+ progressMonitor.beginTask(1, CommonI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
progressMonitor.worked(1);
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -28,7 +28,7 @@
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.SystemFailureException;
import org.junit.Before;
import org.junit.Test;
@@ -74,7 +74,7 @@
try {
I18n.initialize(TestI18nFinalField.class);
} catch (SystemFailureException err) {
- assertThat(err.getMessage(), is(CoreI18n.i18nFieldFinal.text("testMessage", TestI18nFinalField.class)));
+ assertThat(err.getMessage(), is(CommonI18n.i18nFieldFinal.text("testMessage", TestI18nFinalField.class)));
System.err.println(err);
throw err;
}
@@ -85,7 +85,7 @@
try {
I18n.initialize(TestI18nNotPublicField.class);
} catch (RuntimeException err) {
- assertThat(err.getMessage(), is(CoreI18n.i18nFieldNotPublic.text("testMessage", TestI18nNotPublicField.class)));
+ assertThat(err.getMessage(), is(CommonI18n.i18nFieldNotPublic.text("testMessage", TestI18nNotPublicField.class)));
System.err.println(err);
throw err;
}
@@ -96,7 +96,7 @@
try {
I18n.initialize(TestI18nNotStaticField.class);
} catch (RuntimeException err) {
- assertThat(err.getMessage(), is(CoreI18n.i18nFieldNotStatic.text("testMessage", TestI18nNotStaticField.class)));
+ assertThat(err.getMessage(), is(CommonI18n.i18nFieldNotStatic.text("testMessage", TestI18nNotStaticField.class)));
System.err.println(err);
throw err;
}
@@ -123,7 +123,7 @@
try {
I18n.initialize(TestI18nInterface.class);
} catch (IllegalArgumentException err) {
- assertThat(err.getMessage(), is(CoreI18n.i18nClassInterface.text(TestI18nInterface.class.getName())));
+ assertThat(err.getMessage(), is(CommonI18n.i18nClassInterface.text(TestI18nInterface.class.getName())));
System.err.println(err);
throw err;
}
@@ -176,7 +176,7 @@
try {
TestI18n.testMessage1.text();
} catch (IllegalArgumentException err) {
- assertThat(err.getMessage(), is(CoreI18n.i18nArgumentsMismatchedParameter.text(0, "testMessage1", 1, "{0}", "{0}")));
+ assertThat(err.getMessage(), is(CommonI18n.i18nArgumentsMismatchedParameter.text(0, "testMessage1", 1, "{0}", "{0}")));
System.err.println(err);
throw err;
}
@@ -187,7 +187,7 @@
try {
TestI18n.testMessage1.text("Test", "Message");
} catch (IllegalArgumentException err) {
- assertThat(err.getMessage(), is(CoreI18n.i18nArgumentsMismatchedParameter.text(2, "testMessage1", 1, "{0}", "Test")));
+ assertThat(err.getMessage(), is(CommonI18n.i18nArgumentsMismatchedParameter.text(2, "testMessage1", 1, "{0}", "Test")));
System.err.println(err);
throw err;
}
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -28,7 +28,7 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.number.IsCloseTo.closeTo;
import static org.junit.Assert.assertThat;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.junit.Before;
import org.junit.Test;
@@ -64,7 +64,7 @@
@Test
public void shouldHaveProgressOfZeroPercentUponBeginningTask() {
- this.monitor.beginTask(100, CoreI18n.passthrough, validTaskName);
+ this.monitor.beginTask(100, CommonI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -74,7 +74,7 @@
@Test
public void shouldShowProperProgress() {
- this.monitor.beginTask(1000, CoreI18n.passthrough, validTaskName);
+ this.monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -102,7 +102,7 @@
@Test
public void shouldShowProperProgressUsingSubtasks() {
- monitor.beginTask(1000, CoreI18n.passthrough, validTaskName);
+ monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -117,7 +117,7 @@
assertThat(((SubProgressMonitor)subtask).getParent(), is(sameInstance(monitor)));
String subtaskName = "Subtask " + i;
- subtask.beginTask(10, CoreI18n.passthrough, subtaskName); // note the different total work for the subtask
+ subtask.beginTask(10, CommonI18n.passthrough, subtaskName); // note the different total work for the subtask
for (int j = 1; j <= 10; ++j) {
// Work the subtask
subtask.worked(1);
@@ -155,7 +155,7 @@
@Test
public void shouldAllowDoneToBeCalledEvenAfterFinished() {
- monitor.beginTask(1000, CoreI18n.passthrough, validTaskName);
+ monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -184,7 +184,7 @@
@Test
public void shouldAllowCancelToBeRejected() {
- monitor.beginTask(1000, CoreI18n.passthrough, validTaskName);
+ monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
@@ -218,7 +218,7 @@
@Test
public void shouldContinueToRecordWorkEvenWhenCancelled() {
- monitor.beginTask(1000, CoreI18n.passthrough, validTaskName);
+ monitor.beginTask(1000, CommonI18n.passthrough, validTaskName);
ProgressStatus status = monitor.getStatus();
assertThat(status, is(notNullValue()));
assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/stats/HistogramTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/stats/HistogramTest.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/stats/HistogramTest.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -26,7 +26,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.math.FloatOperations;
import org.jboss.dna.common.math.MathOperations;
import org.jboss.dna.common.stats.Histogram;
@@ -55,7 +55,7 @@
}
public static <T extends Number> void writeHistogramToLog( Logger logger, Histogram<T> histogram, int barLength, String description ) {
- logger.info(CoreI18n.passthrough, description != null ? description : "Histogram:");
+ logger.info(CommonI18n.passthrough, description != null ? description : "Histogram:");
List<String> barGraph = histogram.getTextGraph(barLength);
for (String line : barGraph) {
logger.debug(" " + line);
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/util/LogContextTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/util/LogContextTest.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/util/LogContextTest.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -22,7 +22,7 @@
package org.jboss.dna.common.util;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.util.LogContext;
import org.jboss.dna.common.util.Logger;
import org.junit.After;
@@ -46,8 +46,8 @@
@Test
public void shouldAcceptValidKeys() {
LogContext.set("username", "jsmith");
- logger.info(CoreI18n.passthrough, "tracking activity for username");
- logger.info(CoreI18n.passthrough, "A second log message");
+ logger.info(CommonI18n.passthrough, "tracking activity for username");
+ logger.info(CommonI18n.passthrough, "A second log message");
}
}
Modified: trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitBasicFunctionTest.java
===================================================================
--- trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitBasicFunctionTest.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitBasicFunctionTest.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -31,7 +31,7 @@
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.core.TransientRepository;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.util.FileUtil;
import org.jboss.dna.common.util.Logger;
import org.junit.After;
@@ -76,7 +76,7 @@
assertNotNull(session);
String username = session.getUserID();
String name = repository.getDescriptor(Repository.REP_NAME_DESC);
- logger.info(CoreI18n.passthrough, "Logged in as " + username + " to a " + name + " repository");
+ logger.info(CommonI18n.passthrough, "Logged in as " + username + " to a " + name + " repository");
} finally {
if (session != null) session.logout();
}
@@ -91,7 +91,7 @@
assertNotNull(session);
String username = session.getUserID();
String name = repository.getDescriptor(Repository.REP_NAME_DESC);
- logger.info(CoreI18n.passthrough, "Logged in as " + username + " to a " + name + " repository");
+ logger.info(CommonI18n.passthrough, "Logged in as " + username + " to a " + name + " repository");
} finally {
if (session != null) session.logout();
}
@@ -106,7 +106,7 @@
Session session = this.repository.login(creds);
assertNotNull(session);
sessions.add(session);
- logger.info(CoreI18n.passthrough, "Logged in as " + session.getUserID());
+ logger.info(CommonI18n.passthrough, "Logged in as " + session.getUserID());
}
} finally {
while (!sessions.isEmpty()) {
@@ -150,8 +150,8 @@
// Retrieve content ...
Node node = root.getNode("hello/world");
- this.logger.info(CoreI18n.passthrough, "Node 'hello/world' has path: " + node.getPath());
- this.logger.info(CoreI18n.passthrough, "Node 'hello/world' has 'message' property: " + node.getProperty("message").getString());
+ this.logger.info(CommonI18n.passthrough, "Node 'hello/world' has path: " + node.getPath());
+ this.logger.info(CommonI18n.passthrough, "Node 'hello/world' has 'message' property: " + node.getProperty("message").getString());
} finally {
if (session != null) session.logout();
}
@@ -163,11 +163,11 @@
// Retrieve content
Node node = root.getNode("hello/world");
- this.logger.info(CoreI18n.passthrough, "Node 'hello/world' has path: " + node.getPath());
- this.logger.info(CoreI18n.passthrough, "Node 'hello/world' has 'message' property: " + node.getProperty("message").getString());
+ this.logger.info(CommonI18n.passthrough, "Node 'hello/world' has path: " + node.getPath());
+ this.logger.info(CommonI18n.passthrough, "Node 'hello/world' has 'message' property: " + node.getProperty("message").getString());
// Remove content
- this.logger.info(CoreI18n.passthrough, "Node 'hello' is being removed");
+ this.logger.info(CommonI18n.passthrough, "Node 'hello' is being removed");
root.getNode("hello").remove();
session.save();
} finally {
Modified: trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitDerbyStressTest.java
===================================================================
--- trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitDerbyStressTest.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitDerbyStressTest.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -27,7 +27,7 @@
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.core.TransientRepository;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.stats.HistogramTest;
import org.jboss.dna.common.stats.Stopwatch;
import org.jboss.dna.common.util.FileUtil;
@@ -65,7 +65,7 @@
logger = Logger.getLogger(JackrabbitDerbyStressTest.class);
// Set up the transient repository ...
- logger.info(CoreI18n.passthrough, "Creating test repository for stress test and logging in with user " + USERNAME);
+ logger.info(CommonI18n.passthrough, "Creating test repository for stress test and logging in with user " + USERNAME);
this.repository = new TransientRepository(REPOSITORY_CONFIG_PATH, REPOSITORY_DIRECTORY_PATH);
SimpleCredentials creds = new SimpleCredentials(USERNAME, PASSWORD);
@@ -95,7 +95,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(3).setBucketCount(50), 80, "create 100 nodes with no children and no properties");
- this.logger.info(CoreI18n.passthrough, stopwatch.toString());
+ this.logger.info(CommonI18n.passthrough, stopwatch.toString());
}
@Test
@@ -109,7 +109,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(1).setBucketCount(50), 80, "create 1000 nodes with no children and no properties");
- this.logger.info(CoreI18n.passthrough, stopwatch.toString());
+ this.logger.info(CommonI18n.passthrough, stopwatch.toString());
}
@Test
@@ -123,7 +123,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(1).setBucketCount(50), 80, "create 5000 nodes with no children and no properties");
- this.logger.info(CoreI18n.passthrough, stopwatch.toString());
+ this.logger.info(CommonI18n.passthrough, stopwatch.toString());
}
@Test
@@ -137,7 +137,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(1).setBucketCount(50), 80, "create 10000 nodes with no children and no properties");
- this.logger.info(CoreI18n.passthrough, stopwatch.toString());
+ this.logger.info(CommonI18n.passthrough, stopwatch.toString());
}
@Test
@@ -153,7 +153,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, stopwatch.getHistogram(3).setBucketCount(50), 80, "create 100 nodes with no children and several properties");
- this.logger.info(CoreI18n.passthrough, stopwatch.toString());
+ this.logger.info(CommonI18n.passthrough, stopwatch.toString());
}
//
// @Test
Modified: trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitInMemoryTest.java
===================================================================
--- trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitInMemoryTest.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-integration-tests/src/test/java/org/jboss/dna/tests/integration/jackrabbit/JackrabbitInMemoryTest.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -27,7 +27,7 @@
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.core.TransientRepository;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.stats.HistogramTest;
import org.jboss.dna.common.stats.Stopwatch;
import org.jboss.dna.common.util.FileUtil;
@@ -64,7 +64,7 @@
logger = Logger.getLogger(JackrabbitInMemoryTest.class);
// Set up the transient repository ...
- logger.info(CoreI18n.passthrough, "Creating test repository for stress test and logging in with user " + USERNAME);
+ logger.info(CommonI18n.passthrough, "Creating test repository for stress test and logging in with user " + USERNAME);
this.repository = new TransientRepository(REPOSITORY_CONFIG_PATH, REPOSITORY_DIRECTORY_PATH);
SimpleCredentials creds = new SimpleCredentials(USERNAME, PASSWORD);
@@ -119,7 +119,7 @@
}
rootNode.save();
HistogramTest.writeHistogramToLog(logger, nodeStopwatch.getHistogram(3).setBucketCount(50), 80, "create 100 nodes with no children and no properties");
- this.logger.info(CoreI18n.passthrough, nodeStopwatch.toString());
+ this.logger.info(CommonI18n.passthrough, nodeStopwatch.toString());
}
@Test
@@ -133,8 +133,8 @@
HistogramTest.writeHistogramToLog(logger, nodeStopwatch.getHistogram(3).setBucketCount(50), 80, "create tree of " + numNodes + " nodes (2 deep, 10 children at every node)");
HistogramTest.writeHistogramToLog(logger, saveStopwatch.getHistogram(3).setBucketCount(50), 80, "1 save of 2x10 tree of " + numNodes + " nodes");
- this.logger.info(CoreI18n.passthrough, "Node operation times: " + nodeStopwatch.toString());
- this.logger.info(CoreI18n.passthrough, "Save times: " + saveStopwatch.toString());
+ this.logger.info(CommonI18n.passthrough, "Node operation times: " + nodeStopwatch.toString());
+ this.logger.info(CommonI18n.passthrough, "Save times: " + saveStopwatch.toString());
}
@Test
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -28,7 +28,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import javax.jcr.Node;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.monitor.ProgressMonitor;
import org.jboss.dna.repository.observation.NodeChange;
import org.jboss.dna.repository.sequencers.Sequencer;
@@ -67,7 +67,7 @@
*/
public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, ExecutionContext context, ProgressMonitor progress ) {
try {
- progress.beginTask(1, CoreI18n.passthrough, "Incrementing counter");
+ progress.beginTask(1, CommonI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
this.latch.countDown();
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java 2008-04-22 14:59:02 UTC (rev 98)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java 2008-04-22 15:16:43 UTC (rev 99)
@@ -28,7 +28,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import javax.jcr.Node;
import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.monitor.ProgressMonitor;
import org.jboss.dna.repository.observation.NodeChange;
import org.jboss.dna.repository.sequencers.Sequencer;
@@ -67,7 +67,7 @@
*/
public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, ExecutionContext context, ProgressMonitor progress ) {
try {
- progress.beginTask(1, CoreI18n.passthrough, "Incrementing counter");
+ progress.beginTask(1, CommonI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
this.latch.countDown();
16 years
DNA SVN: r98 - in trunk/dna-common/src: main/java/org/jboss/dna/common/i18n and 3 other directories.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-04-22 10:59:02 -0400 (Tue, 22 Apr 2008)
New Revision: 98
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java
trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java
trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties
trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nDuplicateProperty.properties
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nMissingProperty.properties
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nUnusedProperty.properties
Log:
DNA-27: Changed I18n to store errors encountered during the load of localization files in a global map rather than throwing exceptions, allowing these to be handled at a later time without hindering other current development.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java 2008-04-22 14:57:53 UTC (rev 97)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/CoreI18n.java 2008-04-22 14:59:02 UTC (rev 98)
@@ -2,7 +2,7 @@
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
+ * distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
@@ -47,7 +47,9 @@
public static I18n i18nReplaceArgumentMismatchedParameters;
public static I18n i18nReplaceArgumentsMismatchedParameters;
public static I18n i18nClassInterface;
+ public static I18n i18nClassNotPublic;
public static I18n i18nFieldFinal;
+ public static I18n i18nFieldInvalidType;
public static I18n i18nFieldNotPublic;
public static I18n i18nFieldNotStatic;
public static I18n i18nPropertiesFileNotFound;
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java 2008-04-22 14:57:53 UTC (rev 97)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java 2008-04-22 14:59:02 UTC (rev 98)
@@ -2,7 +2,7 @@
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
+ * distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
@@ -26,302 +26,446 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.CoreI18n;
import org.jboss.dna.common.SystemFailureException;
import org.jboss.dna.common.util.ArgCheck;
import org.jboss.dna.common.util.ClassUtil;
+import org.jboss.dna.common.util.HashCode;
/**
* Manages the initialization of internationalization (i18n) files, substitution of values within i18n message placeholders, and
* dynamically reading properties from i18n property files.
+ *
* @author John Verhaeg
* @author Randall Hauch
*/
@ThreadSafe
public final class I18n {
- private static final Pattern PARAMETER_COUNT_PATTERN = Pattern.compile("\\{(\\d+)\\}");
- private static final Object[] EMPTY_ARGUMENTS = new Object[] {};
- private static final LocalizationRepository DEFAULT_LOCALIZATION_REPOSITORY = new ClasspathLocalizationRepository();
- private static LocalizationRepository localizationRepository = DEFAULT_LOCALIZATION_REPOSITORY;
+ private static final Pattern PARAMETER_COUNT_PATTERN = Pattern.compile("\\{(\\d+)\\}");
+ private static final Object[] EMPTY_ARGUMENTS = new Object[] {};
+ private static final LocalizationRepository DEFAULT_LOCALIZATION_REPOSITORY = new ClasspathLocalizationRepository();
+ private static final ConcurrentMap<Localization, Map<String, String>> LOCALIZATION_2_ID_2_ERROR_MAP = new ConcurrentHashMap<Localization, Map<String, String>>();
+ private static final ConcurrentMap<Localization, Map<String, String>> LOCALIZATION_2_ID_2_TEXT_MAP = new ConcurrentHashMap<Localization, Map<String, String>>();
- /**
- * Get the repository of localized messages. By default, this instance uses a {@link ClasspathLocalizationRepository} that
- * uses this class' classloader.
- * @return localizationRepository
- */
- public static LocalizationRepository getLocalizationRepository() {
- return localizationRepository;
- }
+ private static LocalizationRepository localizationRepository = DEFAULT_LOCALIZATION_REPOSITORY;
- /**
- * Set the repository of localized messages. If null, a {@link ClasspathLocalizationRepository} instance that uses this class
- * loader will be used.
- * @param localizationRepository the localization repository to use; may be null if the default repository should be used.
- */
- public static void setLocalizationRepository( LocalizationRepository localizationRepository ) {
- I18n.localizationRepository = localizationRepository != null ? localizationRepository : DEFAULT_LOCALIZATION_REPOSITORY;
- }
+ /**
+ * @param i18nClass An internalization class for which errors should be returned.
+ * @return The errors encountered while initializing the specified internationalization class for the default locale mapped to
+ * the applicable internalization IDs; never <code>null</code>.
+ */
+ public static Map<String, String> getErrorsForDefaultLocale( Class i18nClass ) {
+ return getErrorsForLocale(i18nClass, null);
+ }
- /**
- * Initializes the internationalization fields declared on the specified class. Internationalization fields must be public,
- * static, not final, and of type <code>I18n</code>. The specified class must not be an interface (of course), but has no
- * restrictions as to what class it may extend or what interfaces it must implement.
- * @param i18nClass A class declaring one or more public, static, non-final fields of type <code>I18n</code>.
- */
- public static void initialize( Class i18nClass ) {
- ArgCheck.isNotNull(i18nClass, "i18nClass");
- if (i18nClass.isInterface()) {
- throw new IllegalArgumentException(CoreI18n.i18nClassInterface.text(i18nClass.getName()));
- }
+ /**
+ * @param i18nClass An internalization class for which errors should be returned.
+ * @param locale The locale for which errors should be returned. If <code>null</code>, errors for the the default locale
+ * will be returned.
+ * @return The errors encountered while initializing the specified internationalization class for the specified locale mapped
+ * to the applicable internalization IDs; never <code>null</code>.
+ */
+ public static Map<String, String> getErrorsForLocale( Class i18nClass,
+ Locale locale ) {
+ ArgCheck.isNotNull(i18nClass, "i18nClass");
+ Map<String, String> errors = LOCALIZATION_2_ID_2_ERROR_MAP.get(new Localization(
+ locale == null ? Locale.getDefault() : locale,
+ i18nClass));
+ if (errors == null) {
+ errors = Collections.emptyMap();
+ }
+ return errors;
+ }
- // Find all public static non-final String fields in the specified class and instantiate an I18n object for each.
- try {
- for (Field fld : i18nClass.getDeclaredFields()) {
+ /**
+ * Get the repository of localized messages. By default, this instance uses a {@link ClasspathLocalizationRepository} that
+ * uses this class' classloader.
+ *
+ * @return localizationRepository
+ */
+ public static LocalizationRepository getLocalizationRepository() {
+ return localizationRepository;
+ }
- // Ensure field is of type I18n
- if (fld.getType() == I18n.class) {
+ /**
+ * Set the repository of localized messages. If null, a {@link ClasspathLocalizationRepository} instance that uses this class
+ * loader will be used.
+ *
+ * @param localizationRepository the localization repository to use; may be null if the default repository should be used.
+ */
+ public static void setLocalizationRepository( LocalizationRepository localizationRepository ) {
+ I18n.localizationRepository = localizationRepository != null ? localizationRepository : DEFAULT_LOCALIZATION_REPOSITORY;
+ }
- // Ensure field is not final
- if ((fld.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
- throw new SystemFailureException(CoreI18n.i18nFieldFinal.text(fld.getName(), i18nClass));
- }
+ /**
+ * Initializes the internationalization fields declared on the specified class. Internationalization fields must be public,
+ * static, not final, and of type <code>I18n</code>. The specified class must not be an interface (of course), but has no
+ * restrictions as to what class it may extend or what interfaces it must implement.
+ *
+ * @param i18nClass A class declaring one or more public, static, non-final fields of type <code>I18n</code>.
+ */
+ public static void initialize( Class i18nClass ) {
+ ArgCheck.isNotNull(i18nClass, "i18nClass");
+ if (i18nClass.isInterface()) {
+ throw new IllegalArgumentException(CoreI18n.i18nClassInterface.text(i18nClass.getName()));
+ }
- // Ensure field is public
- if ((fld.getModifiers() & Modifier.PUBLIC) != Modifier.PUBLIC) {
- throw new SystemFailureException(CoreI18n.i18nFieldNotPublic.text(fld.getName(), i18nClass));
- }
+ // Find all public static non-final String fields in the specified class and instantiate an I18n object for each.
+ try {
+ for (Field fld : i18nClass.getDeclaredFields()) {
- // Ensure field is static
- if ((fld.getModifiers() & Modifier.STATIC) != Modifier.STATIC) {
- throw new SystemFailureException(CoreI18n.i18nFieldNotStatic.text(fld.getName(), i18nClass));
- }
+ // Ensure field is of type I18n
+ if (fld.getType() == I18n.class) {
- // Ensure we can access field even if it's in a private class
- ClassUtil.makeAccessible(fld);
+ // Ensure field is not final
+ if ((fld.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
+ throw new SystemFailureException(CoreI18n.i18nFieldFinal.text(fld.getName(), i18nClass));
+ }
- // Initialize field. Do this every time the class is initialized (or re-initialized)
- fld.set(null, new I18n(fld.getName(), i18nClass));
- }
- }
- } catch (IllegalAccessException err) {
- throw new SystemFailureException(err);
- }
- }
+ // Ensure field is public
+ if ((fld.getModifiers() & Modifier.PUBLIC) != Modifier.PUBLIC) {
+ throw new SystemFailureException(CoreI18n.i18nFieldNotPublic.text(fld.getName(), i18nClass));
+ }
- public final String id;
- /* package */final Class i18nClass;
- private final ConcurrentMap<Locale, Map<String, String>> locale2Id2TextMap;
- private final Lock localeLoadingLock = new ReentrantLock();
+ // Ensure field is static
+ if ((fld.getModifiers() & Modifier.STATIC) != Modifier.STATIC) {
+ throw new SystemFailureException(CoreI18n.i18nFieldNotStatic.text(fld.getName(), i18nClass));
+ }
- private I18n( String id, Class i18nClass ) {
- this.id = id;
- this.i18nClass = i18nClass;
- this.locale2Id2TextMap = new ConcurrentHashMap<Locale, Map<String, String>>();
- }
+ // Ensure we can access field even if it's in a private class
+ ClassUtil.makeAccessible(fld);
- protected String rawText( Locale locale ) {
- assert locale != null;
- Map<String, String> id2TextMap = null;
- id2TextMap = locale2Id2TextMap.get(locale);
- if (id2TextMap == null) {
- // Get a lock for loading the locale (this blocks loading all other locales, but not reads for existing locales)
- try {
- this.localeLoadingLock.lock();
- id2TextMap = new HashMap<String, String>();
+ // Initialize field. Do this every time the class is initialized (or re-initialized)
+ fld.set(null, new I18n(fld.getName(), i18nClass));
+ }
+ }
+ } catch (IllegalAccessException err) {
+ throw new IllegalArgumentException(CoreI18n.i18nClassNotPublic.text(i18nClass.getName()));
+ }
+ }
- // Put in the new map and see if there's already one there ...
- Map<String, String> existingId2TextMap = locale2Id2TextMap.putIfAbsent(locale, id2TextMap);
- // If there is already an existing map, then someone beat us to the punch and there's nothing to do ...
- if (existingId2TextMap == null) {
- // We're the first to put in the map for this locale, so populate the one we created...
+ /**
+ * Synchronized on the locale being loaded (this blocks loading all other locales, but not reads for existing locales)
+ *
+ * @param i18nClass The internalization class being initialized
+ * @param localization
+ * @return
+ */
+ private synchronized static Map<String, String> initializeIdToTextMap( final Localization localization ) {
+ Map<String, String> id2TextMap = new HashMap<String, String>();
- // Get the URL to the localization properties file ...
- final LocalizationRepository repos = getLocalizationRepository();
- final String bundleName = i18nClass.getName();
- URL url = null;
- url = repos.getLocalizationBundle(bundleName, locale);
+ // Put in the new map and see if there's already one there ...
+ Map<String, String> existingId2TextMap = LOCALIZATION_2_ID_2_TEXT_MAP.putIfAbsent(localization, id2TextMap);
+ // If there is already an existing map, then someone beat us to the punch and there's nothing to do ...
+ if (existingId2TextMap != null) {
+ return existingId2TextMap;
+ }
+ // We're the first to put in the map for this locale, so populate the one we created...
- // Try the default locale (if it is different than the supplied locale) ...
- if (url == null) {
- // Nothing was found, so try the default locale
- Locale defaultLocale = Locale.getDefault();
- if (defaultLocale != locale) {
- url = repos.getLocalizationBundle(bundleName, defaultLocale);
- }
- }
+ // Get the URL to the localization properties file ...
+ final LocalizationRepository repos = getLocalizationRepository();
+ final String bundleName = localization.i18nClass.getName();
+ URL url = null;
+ Locale locale = new Locale(localization.language, localization.country, localization.variant);
+ url = repos.getLocalizationBundle(bundleName, locale);
- // Abort if no variant of the i18n properties file for the specified class found
- if (url == null) {
- throw new SystemFailureException(CoreI18n.i18nPropertiesFileNotFound.text(bundleName));
- }
+ // Try the default locale (if it is different than the supplied locale) ...
+ if (url == null) {
+ // Nothing was found, so try the default locale
+ Locale defaultLocale = Locale.getDefault();
+ if (!defaultLocale.equals(locale)) {
+ url = repos.getLocalizationBundle(bundleName, defaultLocale);
+ }
+ }
- // Initialize i18n map
- final Map<String, String> finalMap = id2TextMap;
- final URL finalUrl = url;
- Properties props = new Properties() {
+ String bundleMsg = null;
+ if (url == null) {
+ // Record no variant of the i18n properties file for the specified class found
+ bundleMsg = CoreI18n.i18nPropertiesFileNotFound.text(bundleName);
+ } else {
+ // Initialize i18n map
+ final Map<String, String> finalMap = id2TextMap;
+ final URL finalUrl = url;
+ Properties props = new Properties() {
- @Override
- public synchronized Object put( Object key, Object value ) {
- String id = (String)key;
- String text = (String)value;
+ @Override
+ public synchronized Object put( Object key,
+ Object value ) {
+ String id = (String)key;
+ String text = (String)value;
- // Throw error if no corresponding field exists
- try {
- Field fld = i18nClass.getDeclaredField(id);
- if (fld.getType() != I18n.class) {
- throw new SystemFailureException(CoreI18n.i18nPropertyUnused.text(id, finalUrl));
- }
- } catch (Exception err) {
- throw new SystemFailureException(CoreI18n.i18nPropertyUnused.text(id, finalUrl));
- }
+ try {
+ Field fld = localization.i18nClass.getDeclaredField(id);
+ if (fld.getType() != I18n.class) {
+ // Invalid field type
+ mapErrorMessage(localization, id, CoreI18n.i18nFieldInvalidType.text(id,
+ finalUrl,
+ getClass().getName()));
+ }
+ } catch (NoSuchFieldException err) {
+ // No corresponding field exists
+ mapErrorMessage(localization, id, CoreI18n.i18nPropertyUnused.text(id, finalUrl));
+ }
- if (finalMap.put(id, text) != null) {
+ if (finalMap.put(id, text) != null) {
+ // Duplicate id encountered
+ mapErrorMessage(localization, id, CoreI18n.i18nPropertyDuplicate.text(id, finalUrl));
+ }
- // Throw error if duplicate id encountered
- throw new SystemFailureException(CoreI18n.i18nPropertyDuplicate.text(id, finalUrl));
- }
+ return null;
+ }
+ };
- return null;
- }
- };
+ try {
+ InputStream propStream = url.openStream();
+ try {
+ props.load(propStream);
+ } finally {
+ propStream.close();
+ }
+ } catch (IOException err) {
+ bundleMsg = err.getMessage();
+ }
+ }
- try {
- InputStream propStream = url.openStream();
- try {
- props.load(propStream);
- } finally {
- propStream.close();
- }
- } catch (IOException err) {
- throw new SystemFailureException(err);
- }
+ // Check for uninitialized fields
+ for (Field fld : localization.i18nClass.getDeclaredFields()) {
+ if (fld.getType() == I18n.class && id2TextMap.get(fld.getName()) == null) {
+ mapErrorMessage(localization,
+ fld.getName(),
+ bundleMsg == null ? CoreI18n.i18nPropertyMissing.text(fld.getName(), url) : bundleMsg);
+ }
+ }
- // Check for uninitialized fields
- for (Field fld : i18nClass.getDeclaredFields()) {
- if (fld.getType() == I18n.class && id2TextMap.get(fld.getName()) == null) {
- throw new SystemFailureException(CoreI18n.i18nPropertyMissing.text(fld.getName(), url));
- }
- }
+ return id2TextMap;
+ }
- }
- } finally {
- this.localeLoadingLock.unlock();
- } // end of locale loading ...
- }
+ static void mapErrorMessage( Localization localization,
+ String id,
+ String message ) {
+ Map<String, String> id2ErrorMap = new ConcurrentHashMap<String, String>();
+ Map<String, String> existingId2ErrorMap = LOCALIZATION_2_ID_2_ERROR_MAP.putIfAbsent(localization, id2ErrorMap);
+ if (existingId2ErrorMap != null) {
+ id2ErrorMap = existingId2ErrorMap;
+ }
+ message = id2ErrorMap.put(id, message);
+ assert message == null;
+ }
- String text = id2TextMap.get(id);
- assert text != null;
- return text;
- }
+ /**
+ * Substitute the arguments into the message, ensuring that the number of arguments matches the number of parameters in the
+ * text.
+ *
+ * @param id the id of the internationalization object
+ * @param text
+ * @param arguments
+ * @return the text with parameters replaced
+ */
+ protected static String replaceParameters( String id,
+ String text,
+ Object... arguments ) {
+ if (arguments == null) arguments = EMPTY_ARGUMENTS;
+ Matcher matcher = PARAMETER_COUNT_PATTERN.matcher(text);
+ StringBuffer newText = new StringBuffer();
+ int argCount = 0;
+ boolean err = false;
+ while (matcher.find()) {
+ int ndx = Integer.valueOf(matcher.group(1));
+ if (argCount <= ndx) {
+ argCount = ndx + 1;
+ }
+ if (ndx >= arguments.length) {
+ err = true;
+ matcher.appendReplacement(newText, matcher.group());
+ } else {
+ Object arg = arguments[ndx];
+ if (arg != null) {
+ matcher.appendReplacement(newText, Matcher.quoteReplacement(arg.toString()));
+ } else {
+ matcher.appendReplacement(newText, Matcher.quoteReplacement("null"));
+ }
+ }
+ }
+ if (err || argCount < arguments.length) {
+ I18n msg = null;
+ if (id != null) {
+ if (arguments.length == 1) {
+ msg = CoreI18n.i18nArgumentMismatchedParameters;
+ } else if (argCount == 1) {
+ msg = CoreI18n.i18nArgumentsMismatchedParameter;
+ } else {
+ msg = CoreI18n.i18nArgumentsMismatchedParameters;
+ }
+ throw new IllegalArgumentException(msg.text(arguments.length, id, argCount, text, newText.toString()));
+ }
+ if (arguments.length == 1) {
+ msg = CoreI18n.i18nReplaceArgumentMismatchedParameters;
+ } else if (argCount == 1) {
+ msg = CoreI18n.i18nReplaceArgumentsMismatchedParameter;
+ } else {
+ msg = CoreI18n.i18nReplaceArgumentsMismatchedParameters;
+ }
+ throw new IllegalArgumentException(msg.text(arguments.length, argCount, text, newText.toString()));
+ }
+ matcher.appendTail(newText);
- /**
- * Get the internationalized text localized to the {@link Locale#getDefault() current (default) locale}, replacing the
- * parameters in the text with those supplied.
- * @param arguments the arguments for the parameter replacement; may be null or empty
- * @return the localized text
- */
- public String text( Object... arguments ) {
- String rawText = rawText(Locale.getDefault());
- return replaceParameters(id, rawText, arguments);
- }
+ return newText.toString();
+ }
- /**
- * Get the internationalized text localized to the supplied locale, replacing the parameters in the text with those supplied.
- * @param locale the locale, or null if the {@link Locale#getDefault() current (default) locale} should be used
- * @param arguments the arguments for the parameter replacement; may be null or empty
- * @return the localized text
- */
- public String text( Locale locale, Object... arguments ) {
- String rawText = rawText(locale != null ? locale : Locale.getDefault());
- return replaceParameters(id, rawText, arguments);
- }
+ /**
+ * Substitute the arguments into the message, ensuring that the number of arguments matches the number of parameters in the
+ * text.
+ *
+ * @param text
+ * @param arguments
+ * @return the text with parameters replaced
+ */
+ public static String replaceParameters( String text,
+ Object... arguments ) {
+ return replaceParameters(null, text, arguments);
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return rawText(Locale.getDefault());
- }
+ final String id;
+ private final Class i18nClass;
- /**
- * Substitute the arguments into the message, ensuring that the number of arguments matches the number of parameters in the
- * text.
- * @param id the id of the internationalization object
- * @param text
- * @param arguments
- * @return the text with parameters replaced
- */
- protected static String replaceParameters( String id, String text, Object... arguments ) {
- if (arguments == null) arguments = EMPTY_ARGUMENTS;
- Matcher matcher = PARAMETER_COUNT_PATTERN.matcher(text);
- StringBuffer newText = new StringBuffer();
- int argCount = 0;
- boolean err = false;
- while (matcher.find()) {
- int ndx = Integer.valueOf(matcher.group(1));
- if (argCount <= ndx) {
- argCount = ndx + 1;
- }
- if (ndx >= arguments.length) {
- err = true;
- matcher.appendReplacement(newText, matcher.group());
- } else {
- Object arg = arguments[ndx];
- if (arg != null) {
- matcher.appendReplacement(newText, Matcher.quoteReplacement(arg.toString()));
- } else {
- matcher.appendReplacement(newText, Matcher.quoteReplacement("null"));
- }
- }
- }
- if (err || argCount < arguments.length) {
- I18n msg = null;
- if (id != null) {
- if (arguments.length == 1) {
- msg = CoreI18n.i18nArgumentMismatchedParameters;
- } else if (argCount == 1) {
- msg = CoreI18n.i18nArgumentsMismatchedParameter;
- } else {
- msg = CoreI18n.i18nArgumentsMismatchedParameters;
- }
- throw new IllegalArgumentException(msg.text(arguments.length, id, argCount, text, newText.toString()));
- }
- if (arguments.length == 1) {
- msg = CoreI18n.i18nReplaceArgumentMismatchedParameters;
- } else if (argCount == 1) {
- msg = CoreI18n.i18nReplaceArgumentsMismatchedParameter;
- } else {
- msg = CoreI18n.i18nReplaceArgumentsMismatchedParameters;
- }
- throw new IllegalArgumentException(msg.text(arguments.length, argCount, text, newText.toString()));
- }
- matcher.appendTail(newText);
+ private I18n( String id,
+ Class i18nClass ) {
+ this.id = id;
+ this.i18nClass = i18nClass;
+ }
- return newText.toString();
- }
+ private String rawText( Locale locale ) {
+ assert locale != null;
+ Map<String, String> id2TextMap = null;
+ final Localization localization = new Localization(locale, i18nClass);
+ id2TextMap = LOCALIZATION_2_ID_2_TEXT_MAP.get(localization);
+ if (id2TextMap == null) {
+ id2TextMap = initializeIdToTextMap(localization);
+ }
- /**
- * Substitute the arguments into the message, ensuring that the number of arguments matches the number of parameters in the
- * text.
- * @param text
- * @param arguments
- * @return the text with parameters replaced
- */
- public static String replaceParameters( String text, Object... arguments ) {
- return replaceParameters(null, text, arguments);
- }
+ String text = id2TextMap.get(id);
+ assert text != null;
+ return text;
+ }
+ /**
+ * Get the internationalized text localized to the {@link Locale#getDefault() current (default) locale}, replacing the
+ * parameters in the text with those supplied.
+ *
+ * @param arguments the arguments for the parameter replacement; may be null or empty
+ * @return the localized text
+ */
+ public String text( Object... arguments ) {
+ return text(null, arguments);
+ }
+
+ /**
+ * Get the internationalized text localized to the supplied locale, replacing the parameters in the text with those supplied.
+ *
+ * @param locale the locale, or null if the {@link Locale#getDefault() current (default) locale} should be used
+ * @param arguments the arguments for the parameter replacement; may be null or empty
+ * @return the localized text
+ */
+ public String text( Locale locale,
+ Object... arguments ) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ String rawText = rawText(locale);
+ if (rawText == null) {
+ Map<String, String> id2ErrorMap = LOCALIZATION_2_ID_2_ERROR_MAP.get(new Localization(locale, i18nClass));
+ if (id2ErrorMap != null) {
+ String msg = id2ErrorMap.get(id);
+ if (msg != null) {
+ return '<' + msg + '>';
+ }
+ }
+ }
+ return replaceParameters(id, rawText, arguments);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return rawText(Locale.getDefault());
+ }
+
+ @Immutable
+ private static class Localization {
+
+ final String language;
+ final String country;
+ final String variant;
+ final Class i18nClass;
+
+ Localization( Locale locale,
+ Class i18nClass ) {
+ this.language = locale.getLanguage();
+ this.country = locale.getCountry();
+ this.variant = locale.getVariant();
+ this.i18nClass = i18nClass;
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.compute(country, i18nClass, language, variant);
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ Localization other = (Localization)obj;
+ if (country == null) {
+ if (other.country != null) return false;
+ } else if (!country.equals(other.country)) {
+ return false;
+ }
+ if (i18nClass == null) {
+ if (other.i18nClass != null) return false;
+ } else if (!i18nClass.equals(other.i18nClass)) {
+ return false;
+ }
+ if (language == null) {
+ if (other.language != null) return false;
+ } else if (!language.equals(other.language)) {
+ return false;
+ }
+ if (variant == null) {
+ if (other.variant != null) return false;
+ } else if (!variant.equals(other.variant)) {
+ return false;
+ }
+ return true;
+ }
+ }
}
Modified: trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties
===================================================================
--- trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties 2008-04-22 14:57:53 UTC (rev 97)
+++ trunk/dna-common/src/main/resources/org/jboss/dna/common/CoreI18n.properties 2008-04-22 14:59:02 UTC (rev 98)
@@ -8,16 +8,18 @@
i18nReplaceArgumentMismatchedParameters = {0} argument was specified, but {1} parameters are required: "{2}" => "{3}"
i18nReplaceArgumentsMismatchedParameters = {0} arguments were specified, but {1} parameters are required: "{2}" => "{3}"
i18nClassInterface = Class {0} must not be an interface.
+i18nClassNotPublic = Class {0} must be public.
i18nFieldFinal = Internationalization field "{0}" in {1} must not be final.
+i18nFieldInvalidType = Internationalization field "{0}" in {1} must be of type {2}.
i18nFieldNotPublic = Internationalization field "{0}" in {1} must be public.
i18nFieldNotStatic = Internationalization field "{0}" in {1} must be static.
-i18nPropertiesFileNotFound = No variant of the i18n properties file for "{0}" could be found.
-i18nPropertyDuplicate = Duplicate property values were found for property "{0}" in internationalization properties file "{1}";
-i18nPropertyMissing = Missing property "{0}" in internationalization properties file {1}.
-i18nPropertyUnused = An unused property, "{0}", was found in internationalization properties file "{1}".
+i18nPropertiesFileNotFound = No variant of the localization file for "{0}" could be found.
+i18nPropertyDuplicate = Duplicate property values were found for property "{0}" in localization file "{1}";
+i18nPropertyMissing = Missing property "{0}" in localization file {1}.
+i18nPropertyUnused = An unused property, "{0}", was found in localization file "{1}".
# Core-related fields
-componentClassnameNotValid = The classname {0} specified for {1} is not a valid Java classname
+componentClassnameNotValid = The class name {0} specified for {1} is not a valid Java class name
componentNotConfigured = The component {0} was not configured and will not be used
progressMonitorBeginTask = Beginning {0} ({1})
progressMonitorStatus = {0}
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java 2008-04-22 14:57:53 UTC (rev 97)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java 2008-04-22 14:59:02 UTC (rev 98)
@@ -2,7 +2,7 @@
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
+ * distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
@@ -24,6 +24,8 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import org.jboss.dna.common.CoreI18n;
@@ -43,6 +45,21 @@
}
@Test( expected = IllegalArgumentException.class )
+ public void getErrorsForDefaultLocaleShouldFailIfClassIsNull() {
+ I18n.getErrorsForDefaultLocale(null);
+ }
+
+ @Test
+ public void getErrorsForLocaleShouldAllNullLocale() {
+ I18n.getErrorsForLocale(TestI18n.class, null);
+ }
+
+ @Test
+ public void getErrorsForDefaultLocaleShouldNotReturnNull() {
+ assertThat(I18n.getErrorsForDefaultLocale(TestI18n.class), notNullValue());
+ }
+
+ @Test( expected = IllegalArgumentException.class )
public void initializeShouldFailIfClassIsNull() {
I18n.initialize(null);
}
@@ -122,37 +139,31 @@
assertThat(TestI18n.testMessage.id, is("testMessage"));
}
- @Test( expected = RuntimeException.class )
- public void i18nTextShouldFailIfPropertyDuplicate() throws Exception {
+ @Test
+ public void i18nTextShouldHandleIfPropertyDuplicate() throws Exception {
I18n.initialize(TestI18nDuplicateProperty.class);
- try {
- TestI18nDuplicateProperty.testMessage.text();
- } catch (RuntimeException err) {
- System.err.println(err);
- throw err;
- }
+ String text = TestI18nDuplicateProperty.testMessage.text("test");
+ assertThat(text.charAt(0), not('<'));
+ assertThat(I18n.getErrorsForDefaultLocale(TestI18nDuplicateProperty.class).size(), is(1));
+ System.out.println(text);
}
- @Test( expected = RuntimeException.class )
- public void i18nTextShouldFailIfPropertyMissing() throws Exception {
+ @Test
+ public void i18nTextShouldHandleIfPropertyMissing() throws Exception {
I18n.initialize(TestI18nMissingProperty.class);
- try {
- TestI18nMissingProperty.testMessage.text();
- } catch (RuntimeException err) {
- System.err.println(err);
- throw err;
- }
+ String text = TestI18nMissingProperty.testMessage1.text();
+ assertThat(text.charAt(0), is('<'));
+ assertThat(I18n.getErrorsForDefaultLocale(TestI18nDuplicateProperty.class).size(), is(1));
+ System.out.println(text);
}
- @Test( expected = RuntimeException.class )
- public void i18nTextShouldFailIfPropertyUnused() throws Exception {
+ @Test
+ public void i18nTextShouldHandleIfPropertyUnused() throws Exception {
I18n.initialize(TestI18nUnusedProperty.class);
- try {
- TestI18nUnusedProperty.testMessage.text();
- } catch (RuntimeException err) {
- System.err.println(err);
- throw err;
- }
+ String text = TestI18nUnusedProperty.testMessage.text("test");
+ assertThat(text.charAt(0), not('<'));
+ assertThat(I18n.getErrorsForDefaultLocale(TestI18nDuplicateProperty.class).size(), is(1));
+ System.out.println(text);
}
@Test
Modified: trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nDuplicateProperty.properties
===================================================================
--- trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nDuplicateProperty.properties 2008-04-22 14:57:53 UTC (rev 97)
+++ trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nDuplicateProperty.properties 2008-04-22 14:59:02 UTC (rev 98)
@@ -1,2 +1,2 @@
-testMessage = Test Message
-testMessage = Test Message
+testMessage = Message {0}
+testMessage = Message {0}
Modified: trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nMissingProperty.properties
===================================================================
--- trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nMissingProperty.properties 2008-04-22 14:57:53 UTC (rev 97)
+++ trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nMissingProperty.properties 2008-04-22 14:59:02 UTC (rev 98)
@@ -1 +1 @@
-testMessage = Test Message
+testMessage = Message {0}
Modified: trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nUnusedProperty.properties
===================================================================
--- trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nUnusedProperty.properties 2008-04-22 14:57:53 UTC (rev 97)
+++ trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18nUnusedProperty.properties 2008-04-22 14:59:02 UTC (rev 98)
@@ -1,2 +1,2 @@
-testMessage = Test Message
-testMessage1 = Test Message 1
+testMessage = Message {0}
+testMessage1 = Message {0} 1
16 years
DNA SVN: r96 - in trunk: dna-common/src/main/java/org/jboss/dna/common/collection and 38 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-04-21 22:47:53 -0400 (Mon, 21 Apr 2008)
New Revision: 96
Added:
trunk/dna-common/src/main/java/org/jboss/dna/common/collection/Problem.java
trunk/dna-common/src/main/java/org/jboss/dna/common/collection/Problems.java
trunk/dna-repository/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChange.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChangeListener.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChanges.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/ObservationService.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/InvalidRuleSetException.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleService.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSet.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSetRepositoryMonitor.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/InvalidSequencerPathExpression.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/Sequencer.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerConfig.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerException.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerOutputMap.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerPathExpression.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapter.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AdministeredService.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/ExecutionContext.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JcrTools.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JndiSessionFactory.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/RepositoryNodePath.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SessionFactory.java
trunk/dna-repository/src/main/resources/org/jboss/dna/repository/
trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
trunk/dna-repository/src/test/java/org/jboss/dna/repository/
trunk/dna-repository/src/test/java/org/jboss/dna/repository/observation/
trunk/dna-repository/src/test/java/org/jboss/dna/repository/observation/NodeChangeTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/
trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleInput.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleResult.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleServiceTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleSetTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerConfigTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerPathExpressionTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencingServiceTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapterTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/
trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/SimpleExecutionContext.java
trunk/dna-spi/
trunk/dna-spi/.classpath
trunk/dna-spi/.project
trunk/dna-spi/pom.xml
trunk/dna-spi/src/
trunk/dna-spi/src/main/
trunk/dna-spi/src/main/java/
trunk/dna-spi/src/main/java/org/
trunk/dna-spi/src/main/java/org/jboss/
trunk/dna-spi/src/main/java/org/jboss/dna/
trunk/dna-spi/src/main/java/org/jboss/dna/spi/
trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/
trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/SequencerOutput.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/StreamSequencer.java
trunk/dna-spi/src/main/resources/
trunk/dna-spi/src/test/
trunk/dna-spi/src/test/java/
trunk/dna-spi/src/test/java/org/
trunk/dna-spi/src/test/java/org/jboss/
trunk/dna-spi/src/test/java/org/jboss/dna/
trunk/dna-spi/src/test/java/org/jboss/dna/spi/
trunk/dna-spi/src/test/java/org/jboss/dna/spi/sequencers/
trunk/dna-spi/src/test/resources/
trunk/dna-spi/src/test/resources/log4j.properties
Removed:
trunk/dna-repository/src/main/java/org/jboss/dna/services/AbstractServiceAdministrator.java
trunk/dna-repository/src/main/java/org/jboss/dna/services/AdministeredService.java
trunk/dna-repository/src/main/java/org/jboss/dna/services/ExecutionContext.java
trunk/dna-repository/src/main/java/org/jboss/dna/services/JndiSessionFactory.java
trunk/dna-repository/src/main/java/org/jboss/dna/services/RepositoryNodePath.java
trunk/dna-repository/src/main/java/org/jboss/dna/services/ServiceAdministrator.java
trunk/dna-repository/src/main/java/org/jboss/dna/services/ServicesI18n.java
trunk/dna-repository/src/main/java/org/jboss/dna/services/SessionFactory.java
trunk/dna-repository/src/main/java/org/jboss/dna/services/observation/
trunk/dna-repository/src/main/java/org/jboss/dna/services/rules/
trunk/dna-repository/src/main/java/org/jboss/dna/services/sequencers/
trunk/dna-repository/src/main/java/org/jboss/dna/services/util/
trunk/dna-repository/src/main/resources/org/jboss/dna/services/
trunk/dna-repository/src/test/java/org/jboss/dna/services/JndiSessionFactoryTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/services/SimpleExecutionContext.java
trunk/dna-repository/src/test/java/org/jboss/dna/services/observation/
trunk/dna-repository/src/test/java/org/jboss/dna/services/rules/
trunk/dna-repository/src/test/java/org/jboss/dna/services/sequencers/
trunk/dna-services/
Modified:
trunk/
trunk/dna-integration-tests/pom.xml
trunk/dna-repository/.project
trunk/dna-repository/pom.xml
trunk/dna-repository/src/test/resources/log4j.properties
trunk/dna-repository/src/test/resources/rule_test.dslr
trunk/pom.xml
trunk/sequencers/dna-sequencer-images/pom.xml
trunk/sequencers/dna-sequencer-images/src/main/java/org/jboss/dna/sequencer/images/ImageMetadataSequencer.java
Log:
DNA-57: Refactor codebase to clearly and cleanly separate SPI and API
Property changes on: trunk
___________________________________________________________________
Name: svn:ignore
+ target
Added: trunk/dna-common/src/main/java/org/jboss/dna/common/collection/Problem.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/collection/Problem.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/collection/Problem.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,120 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.common.collection;
+
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.ArgCheck;
+
+/**
+ * @author Randall Hauch
+ */
+@Immutable
+public class Problem {
+
+ public static final int DEFAULT_CODE = 0;
+
+ public enum Status {
+ ERROR,
+ WARNING,
+ INFO;
+ }
+
+ private final Status status;
+ private final I18n message;
+ private final Object[] parameters;
+ private final Throwable throwable;
+ private final int code;
+ private final String resource;
+ private final String location;
+
+ public Problem( Status status, int code, I18n message, Object... params ) {
+ this(status, code, message, params, null, null, null);
+ }
+
+ public Problem( Status status, int code, I18n message, Object[] params, String resource, String location, Throwable throwable ) {
+ ArgCheck.isNotNull(status, "status");
+ ArgCheck.isNotNull(message, "message");
+ this.status = status;
+ this.code = code;
+ this.message = message;
+ this.parameters = params;
+ this.resource = resource != null ? resource.trim() : null;
+ this.location = location != null ? location.trim() : null;
+ this.throwable = throwable;
+ }
+
+ /**
+ * @return code
+ */
+ public int getCode() {
+ return this.code;
+ }
+
+ /**
+ * @return location
+ */
+ public String getLocation() {
+ return this.location;
+ }
+
+ /**
+ * Get the message written in the current locale.
+ * @return the message
+ */
+ public String getMessageString() {
+ return this.message.text(this.parameters);
+ }
+
+ /**
+ * @return message
+ */
+ public I18n getMessage() {
+ return this.message;
+ }
+
+ public Object[] getParameters() {
+ return this.parameters;
+ }
+
+ /**
+ * @return resource
+ */
+ public String getResource() {
+ return this.resource;
+ }
+
+ /**
+ * @return status
+ */
+ public Status getStatus() {
+ return this.status;
+ }
+
+ /**
+ * @return throwable
+ */
+ public Throwable getThrowable() {
+ return this.throwable;
+ }
+
+}
Added: trunk/dna-common/src/main/java/org/jboss/dna/common/collection/Problems.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/collection/Problems.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/collection/Problems.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,187 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.common.collection;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class Problems implements Iterable<Problem> {
+
+ private List<Problem> problems;
+
+ public Problems() {
+ }
+
+ public void addError( I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.ERROR, Problem.DEFAULT_CODE, message, params));
+ }
+
+ public void addError( Throwable throwable, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.ERROR, Problem.DEFAULT_CODE, message, null, null, throwable));
+ }
+
+ public void addError( I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.ERROR, Problem.DEFAULT_CODE, message, resource, location));
+ }
+
+ public void addError( Throwable throwable, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.ERROR, Problem.DEFAULT_CODE, message, resource, location, throwable));
+ }
+
+ public void addError( int code, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.ERROR, code, message));
+ }
+
+ public void addError( Throwable throwable, int code, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.ERROR, code, message, null, null, throwable));
+ }
+
+ public void addError( int code, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.ERROR, code, message, resource, location));
+ }
+
+ public void addError( Throwable throwable, int code, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.ERROR, code, message, resource, location, throwable));
+ }
+
+ public void addWarning( I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.WARNING, Problem.DEFAULT_CODE, message));
+ }
+
+ public void addWarning( Throwable throwable, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.WARNING, Problem.DEFAULT_CODE, message, null, null, throwable));
+ }
+
+ public void addWarning( I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.WARNING, Problem.DEFAULT_CODE, message, resource, location));
+ }
+
+ public void addWarning( Throwable throwable, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.WARNING, Problem.DEFAULT_CODE, message, resource, location, throwable));
+ }
+
+ public void addWarning( int code, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.WARNING, code, message));
+ }
+
+ public void addWarning( Throwable throwable, int code, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.WARNING, code, message, null, null, throwable));
+ }
+
+ public void addWarning( int code, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.WARNING, code, message, resource, location));
+ }
+
+ public void addWarning( Throwable throwable, int code, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.WARNING, code, message, resource, location, throwable));
+ }
+
+ public void addInfo( I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.INFO, Problem.DEFAULT_CODE, message));
+ }
+
+ public void addInfo( Throwable throwable, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.INFO, Problem.DEFAULT_CODE, message, null, null, throwable));
+ }
+
+ public void addInfo( I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.INFO, Problem.DEFAULT_CODE, message, resource, location));
+ }
+
+ public void addInfo( Throwable throwable, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.INFO, Problem.DEFAULT_CODE, message, resource, location, throwable));
+ }
+
+ public void addInfo( int code, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.INFO, code, message));
+ }
+
+ public void addInfo( Throwable throwable, int code, I18n message, Object... params ) {
+ addProblem(new Problem(Problem.Status.INFO, code, message, null, null, throwable));
+ }
+
+ public void addInfo( int code, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.INFO, code, message, resource, location));
+ }
+
+ public void addInfo( Throwable throwable, int code, I18n message, String resource, String location, Object... params ) {
+ addProblem(new Problem(Problem.Status.INFO, code, message, resource, location, throwable));
+ }
+
+ public boolean hasProblems() {
+ return this.problems != null && this.problems.size() > 0;
+ }
+
+ public boolean hasErrors() {
+ if (this.problems == null) return false;
+ for (Problem problem : this.problems) {
+ if (problem.getStatus() == Problem.Status.ERROR) return true;
+ }
+ return false;
+ }
+
+ public boolean hasWarnings() {
+ if (this.problems == null) return false;
+ for (Problem problem : this.problems) {
+ if (problem.getStatus() == Problem.Status.WARNING) return true;
+ }
+ return false;
+ }
+
+ public boolean hasInfo() {
+ if (this.problems == null) return false;
+ for (Problem problem : this.problems) {
+ if (problem.getStatus() == Problem.Status.INFO) return true;
+ }
+ return false;
+ }
+
+ public boolean isEmpty() {
+ return this.problems == null || this.problems.isEmpty();
+ }
+
+ public int size() {
+ if (this.problems == null) return 0;
+ return this.problems.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<Problem> iterator() {
+ return problems.iterator();
+ }
+
+ protected void addProblem( Problem problem ) {
+ if (problem == null) return;
+ if (problems == null) problems = new LinkedList<Problem>();
+ problems.add(problem);
+ }
+
+}
Modified: trunk/dna-integration-tests/pom.xml
===================================================================
--- trunk/dna-integration-tests/pom.xml 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-integration-tests/pom.xml 2008-04-22 02:47:53 UTC (rev 96)
@@ -31,7 +31,7 @@
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
- <artifactId>dna-services</artifactId>
+ <artifactId>dna-repository</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
Copied: trunk/dna-repository (from rev 95, trunk/dna-services)
Modified: trunk/dna-repository/.project
===================================================================
--- trunk/dna-services/.project 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/.project 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>dna-services</name>
+ <name>dna-repository</name>
<comment></comment>
<projects>
</projects>
Modified: trunk/dna-repository/pom.xml
===================================================================
--- trunk/dna-services/pom.xml 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/pom.xml 2008-04-22 02:47:53 UTC (rev 96)
@@ -6,10 +6,10 @@
<version>0.1-SNAPSHOT</version>
</parent>
<!-- The groupId and version values are inherited from parent -->
- <artifactId>dna-services</artifactId>
+ <artifactId>dna-repository</artifactId>
<packaging>jar</packaging>
- <name>JBoss DNA Services</name>
- <description>JBoss DNA Engine library with main service components</description>
+ <name>JBoss DNA Repository</name>
+ <description>JBoss DNA Repository library</description>
<url>http://labs.jboss.org/dna</url>
<!--
Define the dependencies. Note that all version and scopes default to those
@@ -33,6 +33,11 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </dependency>
<!--
Rules
-->
@@ -43,10 +48,12 @@
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-jsr94</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
+ <scope>test</scope>
</dependency>
<!--
Testing (note the scope)
@@ -54,14 +61,17 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.jmock</groupId>
<artifactId>jmock-junit4</artifactId>
+ <scope>test</scope>
</dependency>
<!--
Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for testing)
@@ -73,10 +83,12 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
+ <scope>test</scope>
</dependency>
<!--
Java Concurrency in Practice annotations
@@ -98,10 +110,12 @@
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-api</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-core</artifactId>
+ <scope>test</scope>
</dependency>
</dependencies>
</project>
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository;
+
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author Randall Hauch
+ */
+public final class RepositoryI18n {
+
+ static {
+ try {
+ I18n.initialize(RepositoryI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static I18n invalidStateString;
+ public static I18n serviceShutdowAndMayNotBeStarted;
+ public static I18n serviceShutdowAndMayNotBePaused;
+ public static I18n unableToFindRepositoryInJndi;
+ public static I18n errorProcessingEvents;
+ public static I18n errorFindingPropertyNameInPropertyAddedEvent;
+ public static I18n errorFindingPropertyNameInPropertyChangedEvent;
+ public static I18n errorFindingPropertyNameInPropertyRemovedEvent;
+
+ public static I18n unableToObtainJsr94RuleAdministrator;
+ public static I18n errorUsingJsr94RuleAdministrator;
+ public static I18n unableToObtainJsr94ServiceProvider;
+ public static I18n errorAddingOrUpdatingRuleSet;
+ public static I18n errorRollingBackRuleSetAfterUpdateFailed;
+ public static I18n errorReadingRulesAndProperties;
+ public static I18n errorDeregisteringRuleSetBeforeUpdatingIt;
+ public static I18n errorRecreatingRuleSet;
+ public static I18n errorRemovingRuleSet;
+ public static I18n errorRemovingRuleSetUponShutdown;
+ public static I18n unableToFindRuleSet;
+ public static I18n errorExecutingRuleSetWithGlobalsAndFacts;
+ public static I18n unableToBuildRuleSetRegularExpressionPattern;
+
+ public static I18n errorObtainingSessionToRepositoryWorkspace;
+ public static I18n errorWritingProblemsOnRuleSet;
+
+ public static I18n sequencingServiceName;
+ public static I18n unableToChangeExecutionContextWhileRunning;
+ public static I18n unableToStartSequencingServiceWithoutExecutionContext;
+ public static I18n errorWhileSequencingNode;
+ public static I18n errorInRepositoryWhileSequencingNode;
+ public static I18n errorFindingSequencersToRunAgainstNode;
+ public static I18n errorInRepositoryWhileFindingSequencersToRunAgainstNode;
+ public static I18n executionContextHasBeenClosed;
+ public static I18n sequencerTask;
+ public static I18n sequencerSubtask;
+ public static I18n unableToFindPropertyForSequencing;
+ public static I18n sequencingPropertyOnNode;
+ public static I18n writingOutputSequencedFromPropertyOnNodes;
+
+ public static I18n errorReadingPropertiesFromContainerNode;
+ public static I18n requiredPropertyOnNodeWasExpectedToBeStringValue;
+ public static I18n optionalPropertyOnNodeWasExpectedToBeStringValue;
+ public static I18n requiredPropertyOnNodeWasExpectedToBeStringArrayValue;
+ public static I18n optionalPropertyOnNodeWasExpectedToBeStringArrayValue;
+ public static I18n requiredPropertyOnNodeCouldNotBeRead;
+ public static I18n optionalPropertyOnNodeCouldNotBeRead;
+ public static I18n requiredPropertyIsMissingFromNode;
+ public static I18n errorGettingRequiredPropertyFromNode;
+ public static I18n errorGettingOptionalPropertyFromNode;
+ public static I18n errorClosingBinaryStreamForPropertyFromNode;
+ public static I18n requiredNodeDoesNotExistRelativeToNode;
+ public static I18n errorGettingNodeRelativeToNode;
+ public static I18n unknownPropertyValueType;
+
+ public static I18n pathExpressionIsInvalid;
+ public static I18n pathExpressionMayNotBeBlank;
+ public static I18n pathExpressionHasInvalidSelect;
+ public static I18n pathExpressionHasInvalidMatch;
+
+ public static I18n invalidRepositoryNodePath;
+
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChange.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChange.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChange.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,176 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.observation;
+
+import java.util.Collections;
+import java.util.Set;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.HashCode;
+
+/**
+ * A notification of changes to a node.
+ * @author Randall Hauch
+ */
+@Immutable
+public class NodeChange {
+
+ private final String repositoryWorkspaceName;
+ private final String absolutePath;
+ private final int eventTypes;
+ private final Set<String> modifiedProperties;
+ private final Set<String> removedProperties;
+ private final int hc;
+
+ public NodeChange( String repositoryWorkspaceName, String absolutePath, int eventTypes, Set<String> modifiedProperties, Set<String> removedProperties ) {
+ assert repositoryWorkspaceName != null;
+ assert absolutePath != null;
+ this.repositoryWorkspaceName = repositoryWorkspaceName;
+ this.absolutePath = absolutePath.trim();
+ this.hc = HashCode.compute(this.repositoryWorkspaceName, this.absolutePath);
+ this.eventTypes = eventTypes;
+ if (modifiedProperties == null) modifiedProperties = Collections.emptySet();
+ if (removedProperties == null) removedProperties = Collections.emptySet();
+ this.modifiedProperties = Collections.unmodifiableSet(modifiedProperties);
+ this.removedProperties = Collections.unmodifiableSet(removedProperties);
+ }
+
+ /**
+ * @return absolutePath
+ */
+ public String getAbsolutePath() {
+ return this.absolutePath;
+ }
+
+ /**
+ * @return repositoryWorkspaceName
+ */
+ public String getRepositoryWorkspaceName() {
+ return this.repositoryWorkspaceName;
+ }
+
+ /**
+ * @return modifiedProperties
+ */
+ public Set<String> getModifiedProperties() {
+ return this.modifiedProperties;
+ }
+
+ /**
+ * @return removedProperties
+ */
+ public Set<String> getRemovedProperties() {
+ return this.removedProperties;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return this.hc;
+ }
+
+ public boolean includesAllEventTypes( int... jcrEventTypes ) {
+ for (int jcrEventType : jcrEventTypes) {
+ if ((this.eventTypes & jcrEventType) == 0) return false;
+ }
+ return true;
+ }
+
+ public boolean includesEventTypes( int... jcrEventTypes ) {
+ for (int jcrEventType : jcrEventTypes) {
+ if ((this.eventTypes & jcrEventType) != 0) return true;
+ }
+ return false;
+ }
+
+ public boolean isSameNode( NodeChange that ) {
+ if (that == this) return true;
+ if (this.hc != that.hc) return false;
+ if (!this.repositoryWorkspaceName.equals(that.repositoryWorkspaceName)) return false;
+ if (!this.absolutePath.equals(that.absolutePath)) return false;
+ return true;
+ }
+
+ /**
+ * Return whether this node change occurs on a node on the supplied path.
+ * @param absolutePath the path
+ * @return true if the node is on the supplied absolute path, or false otherwise
+ * @see #isNotOnPath(String)
+ */
+ public boolean isOnPath( String absolutePath ) {
+ if (absolutePath == null) return false;
+ if (this.getAbsolutePath().startsWith(absolutePath)) return true;
+ return false;
+ }
+
+ /**
+ * Return whether this node change occurs on a node on a different path than that supplied.
+ * @param absolutePath the path
+ * @return true if the node is on a different path, or false if it is on the same path
+ * @see #isOnPath(String)
+ */
+ public boolean isNotOnPath( String absolutePath ) {
+ return !isOnPath(absolutePath);
+ }
+
+ /**
+ * Determine whether this node change includes the setting of new value(s) for the supplied property.
+ * @param property the name of the property
+ * @return true if the named property has a new value on this node, or false otherwise
+ */
+ public boolean isPropertyModified( String property ) {
+ return this.modifiedProperties.contains(property);
+ }
+
+ /**
+ * Determine whether this node change includes the removal of the supplied property.
+ * @param property the name of the property
+ * @return true if the named property was removed from this node, or false otherwise
+ */
+ public boolean isPropertyRemoved( String property ) {
+ return this.removedProperties.contains(property);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof NodeChange) {
+ NodeChange that = (NodeChange)obj;
+ if (!this.isSameNode(that)) return false;
+ if (this.eventTypes != that.eventTypes) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return this.repositoryWorkspaceName + "=>" + this.absolutePath;
+ }
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChangeListener.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChangeListener.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChangeListener.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,31 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.observation;
+
+/**
+ * @author Randall Hauch
+ */
+public interface NodeChangeListener {
+
+ void onNodeChanges( NodeChanges changes );
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChanges.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChanges.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/NodeChanges.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,195 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.observation;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.repository.RepositoryI18n;
+
+/**
+ * A utility class that builds node changes from a sequence of events.
+ * @author Randall Hauch
+ */
+public class NodeChanges implements Iterable<NodeChange> {
+
+ public static NodeChanges create( final String repositoryWorkspaceName, Iterable<Event> events ) throws RepositoryException {
+ Map<String, NodeChangeDetails> detailsByNodePath = new HashMap<String, NodeChangeDetails>();
+ // Process each of the events, extracting the node path and property details for each ...
+ for (Event event : events) {
+ final int eventType = event.getType();
+ final String eventPath = event.getPath();
+ if (eventType == Event.PROPERTY_ADDED || eventType == Event.PROPERTY_CHANGED || eventType == Event.PROPERTY_REMOVED) {
+ // Extract the node's path and property name from the even path ...
+ int lastDelim = eventPath.lastIndexOf('/');
+ if (lastDelim < 1 || lastDelim == (eventPath.length() - 1)) {
+ // The last delimiter doesn't exist, is the first character, or is the last character...
+ I18n msg =
+ eventType == Event.PROPERTY_ADDED ? RepositoryI18n.errorFindingPropertyNameInPropertyAddedEvent : eventType == Event.PROPERTY_CHANGED ? RepositoryI18n.errorFindingPropertyNameInPropertyChangedEvent : RepositoryI18n.errorFindingPropertyNameInPropertyRemovedEvent;
+ Logger.getLogger(NodeChanges.class).error(msg, eventPath);
+ continue;
+ }
+ String nodePath = eventPath.substring(0, lastDelim); // excludes the last delim
+ String propertyName = eventPath.substring(lastDelim + 1);
+ // Record the details ...
+ NodeChangeDetails details = detailsByNodePath.get(nodePath);
+ if (details == null) {
+ details = new NodeChangeDetails(nodePath);
+ detailsByNodePath.put(nodePath, details);
+ }
+ switch (eventType) {
+ case Event.PROPERTY_ADDED: {
+ details.addProperty(propertyName);
+ break;
+ }
+ case Event.PROPERTY_CHANGED: {
+ details.changeProperty(propertyName);
+ break;
+ }
+ case Event.PROPERTY_REMOVED: {
+ details.removeProperty(propertyName);
+ break;
+ }
+ }
+ } else if (eventType == Event.NODE_ADDED || eventType == Event.NODE_REMOVED) {
+ // Remove the last delimiter if it appears at the end of the path ...
+ String nodePath = eventPath;
+ if (nodePath.length() > 1 && nodePath.charAt(nodePath.length() - 1) == '/') {
+ nodePath = nodePath.substring(0, nodePath.length() - 1);
+ }
+ // Record the details ...
+ NodeChangeDetails details = detailsByNodePath.get(nodePath);
+ if (details == null) {
+ details = new NodeChangeDetails(nodePath);
+ detailsByNodePath.put(nodePath, details);
+ }
+ details.addEventType(eventType);
+ }
+ }
+
+ // Create the node changes ...
+ List<NodeChange> result = new ArrayList<NodeChange>(detailsByNodePath.size());
+ for (NodeChangeDetails detail : detailsByNodePath.values()) {
+ NodeChange change = new NodeChange(repositoryWorkspaceName, detail.getNodePath(), detail.getEventTypes(), detail.getModifiedProperties(), detail.getRemovedProperties());
+ result.add(change);
+ }
+ return new NodeChanges(result);
+ }
+
+ protected static class NodeChangeDetails {
+
+ private final String nodePath;
+ private final Set<String> modifiedProperties = new HashSet<String>();
+ private final Set<String> removedProperties = new HashSet<String>();
+ private int eventTypes;
+
+ protected NodeChangeDetails( String nodePath ) {
+ this.nodePath = nodePath;
+ }
+
+ public void addEventType( int eventType ) {
+ this.eventTypes |= eventType;
+ }
+
+ public void addProperty( String propertyName ) {
+ this.modifiedProperties.add(propertyName);
+ this.eventTypes |= Event.PROPERTY_ADDED;
+ }
+
+ public void changeProperty( String propertyName ) {
+ this.modifiedProperties.add(propertyName);
+ this.eventTypes |= Event.PROPERTY_CHANGED;
+ }
+
+ public void removeProperty( String propertyName ) {
+ this.removedProperties.add(propertyName);
+ this.eventTypes |= Event.PROPERTY_REMOVED;
+ }
+
+ /**
+ * @return nodeAction
+ */
+ public int getEventTypes() {
+ return this.eventTypes;
+ }
+
+ /**
+ * @return nodePath
+ */
+ public String getNodePath() {
+ return this.nodePath;
+ }
+
+ /**
+ * @return addedProperties
+ */
+ public Set<String> getModifiedProperties() {
+ return this.modifiedProperties;
+ }
+
+ /**
+ * @return removedProperties
+ */
+ public Set<String> getRemovedProperties() {
+ return this.removedProperties;
+ }
+ }
+
+ protected static final Comparator<NodeChange> PRE_ORDER = new Comparator<NodeChange>() {
+
+ public int compare( NodeChange change1, NodeChange change2 ) {
+ return change1.getAbsolutePath().compareTo(change2.getAbsolutePath());
+ }
+ };
+
+ private final List<NodeChange> changesInPreOrder;
+
+ protected NodeChanges( List<NodeChange> changes ) {
+ this.changesInPreOrder = Collections.unmodifiableList(changes);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<NodeChange> iterator() {
+ return this.changesInPreOrder.iterator();
+ }
+
+ public Iterator<NodeChange> getPreOrder() {
+ return this.changesInPreOrder.iterator();
+ }
+
+ public int size() {
+ return this.changesInPreOrder.size();
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/ObservationService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/ObservationService.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/ObservationService.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,722 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.observation;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+import net.jcip.annotations.GuardedBy;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.repository.services.AbstractServiceAdministrator;
+import org.jboss.dna.repository.services.AdministeredService;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.repository.util.SessionFactory;
+
+/**
+ * @author Randall Hauch
+ */
+public class ObservationService implements AdministeredService {
+
+ /**
+ * Interface to which problems with particular events are logged.
+ * @author Randall Hauch
+ */
+ public static interface ProblemLog {
+
+ void error( String repositoryWorkspaceName, Throwable t );
+ }
+
+ /**
+ * Problem log implementation that records problems in the log.
+ * @author Randall Hauch
+ */
+ public class DefaultProblemLog implements ProblemLog {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void error( String repositoryWorkspaceName, Throwable t ) {
+ getLogger().error(t, RepositoryI18n.errorProcessingEvents, repositoryWorkspaceName);
+ }
+ }
+
+ protected static class NoOpProblemLog implements ProblemLog {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void error( String repositoryWorkspaceName, Throwable t ) {
+ }
+ }
+
+ public static final ProblemLog NO_OP_PROBLEM_LOG = new NoOpProblemLog();
+
+ /**
+ * The administrative component for this service.
+ * @author Randall Hauch
+ */
+ protected class Administrator extends AbstractServiceAdministrator {
+
+ protected Administrator() {
+ super(State.STARTED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String serviceName() {
+ return "ObservationService";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean awaitTermination( long timeout, TimeUnit unit ) {
+ return true;
+ }
+
+ }
+
+ private Logger logger = Logger.getLogger(this.getClass());
+ private ProblemLog problemLog = new DefaultProblemLog();
+ private final Statistics statistics = new Statistics();
+ private final SessionFactory sessionFactory;
+ private final CopyOnWriteArrayList<EventListener> eventListeners = new CopyOnWriteArrayList<EventListener>();
+ private final CopyOnWriteArrayList<NodeChangeListener> nodeChangeListeners = new CopyOnWriteArrayList<NodeChangeListener>();
+ private final Administrator administrator = new Administrator();
+
+ public ObservationService( SessionFactory sessionFactory ) {
+ ArgCheck.isNotNull(sessionFactory, "session factory");
+ this.sessionFactory = sessionFactory;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ServiceAdministrator getAdministrator() {
+ return this.administrator;
+ }
+
+ /**
+ * @return sessionFactory
+ */
+ public SessionFactory getSessionFactory() {
+ return this.sessionFactory;
+ }
+
+ /**
+ * Get the statistics for this system.
+ * @return the statistics, which are updated as the system is used
+ */
+ public Statistics getStatistics() {
+ return this.statistics;
+ }
+
+ /**
+ * Get the logger for this system
+ * @return the logger
+ */
+ public Logger getLogger() {
+ return this.logger;
+ }
+
+ /**
+ * Set the logger for this system.
+ * @param logger the logger, or null if the standard logging should be used
+ */
+ public void setLogger( Logger logger ) {
+ this.logger = logger != null ? logger : Logger.getLogger(this.getClass());
+ }
+
+ /**
+ * @return problemLog
+ */
+ public ProblemLog getProblemLog() {
+ return this.problemLog;
+ }
+
+ /**
+ * Set the problem log that will be notified of problems handling events. By default, such problems are sent to the log.
+ * @param problemLog the new problem log implementation; if null, then the default problem log is used
+ */
+ public void setProblemLog( ProblemLog problemLog ) {
+ this.problemLog = problemLog != null ? problemLog : new DefaultProblemLog();
+ }
+
+ public boolean addListener( EventListener listener ) {
+ if (listener == null) return false;
+ return this.eventListeners.addIfAbsent(listener);
+ }
+
+ public boolean removeListener( EventListener listener ) {
+ if (listener == null) return false;
+ return this.eventListeners.remove(listener);
+ }
+
+ public boolean addListener( NodeChangeListener listener ) {
+ return this.nodeChangeListeners.addIfAbsent(listener);
+ }
+
+ public boolean removeListener( NodeChangeListener listener ) {
+ if (listener == null) return false;
+ return this.nodeChangeListeners.remove(listener);
+ }
+
+ /**
+ * Monitor the supplied workspace for events of the given type on any node at or under the supplied path.
+ * <p>
+ * Monitoring is accomplished by registering a listener on the workspace, so this monitoring only has access to the
+ * information that visible to the session created by the {@link #getSessionFactory() session factory} for the given
+ * repository and workspace name.
+ * </p>
+ * <p>
+ * The listener returned from this method is not managed by this SequencingService instance. If the listener is no longer
+ * needed, it simply must be {@link ObservationManager#removeEventListener(EventListener) removed} as a listener of the
+ * workspace and garbage collected. If this service is {@link ServiceAdministrator#shutdown() shutdown} while there are still
+ * active listeners, those listeners will disconnect themselves from this service and the workspace with which they're
+ * registered when they attempt to forward the next events.
+ * </p>
+ * <p>
+ * The set of events that are monitored can be filtered by specifying restrictions based on characteristics of the node
+ * associated with the event. In the case of event types {@link Event#NODE_ADDED NODE_ADDED} and
+ * {@link Event#NODE_REMOVED NODE_REMOVED}, the node associated with an event is the node at (or formerly at) the path
+ * returned by {@link Event#getPath() Event.getPath()}. In the case of event types
+ * {@link Event#PROPERTY_ADDED PROPERTY_ADDED}, {@link Event#PROPERTY_REMOVED PROPERTY_REMOVED} and
+ * {@link Event#PROPERTY_CHANGED PROPERTY_CHANGED}, the node associated with an event is the parent node of the property at
+ * (or formerly at) the path returned by <code>Event.getPath</code>:
+ * <ul>
+ * <li> <code>absolutePath</code>, <code>isDeep</code>: Only events whose associated node is at
+ * <code>absolutePath</code> (or within its subtree, if <code>isDeep</code> is <code>true</code>) will be received. It
+ * is permissible to register a listener for a path where no node currently exists. </li>
+ * <li> <code>uuids</code>: Only events whose associated node has one of the UUIDs in this list will be received. If his
+ * parameter is <code>null</code> then no UUID-related restriction is placed on events received. </li>
+ * <li> <code>nodeTypeNames</code>: Only events whose associated node has one of the node types (or a subtype of one of the
+ * node types) in this list will be received. If this parameter is <code>null</code> then no node type-related restriction
+ * is placed on events received. </li>
+ * </ul>
+ * The restrictions are "ANDed" together. In other words, for a particular node to be "listened to" it must meet all the
+ * restrictions.
+ * </p>
+ * <p>
+ * Additionally, if <code>noLocal</code> is <code>true</code>, then events generated by the session through which the
+ * listener was registered are ignored. Otherwise, they are not ignored.
+ * </p>
+ * <p>
+ * The filters of an already-registered {@link WorkspaceListener} can be changed at runtime by changing the attributes and
+ * {@link WorkspaceListener#reregister() registering}.
+ * </p>
+ * @param repositoryWorkspaceName the name to be used with the session factory to obtain a session to the repository and
+ * workspace that is to be monitored
+ * @param absolutePath the absolute path of the node at or below which changes are to be monitored; may be null if all nodes
+ * in the workspace are to be monitored
+ * @param eventTypes the bitmask of the {@link Event} types that are to be monitored
+ * @param isDeep true if events below the node given by the <code>absolutePath</code> or by the <code>uuids</code> are to
+ * be processed, or false if only the events at the node
+ * @param uuids array of UUIDs of nodes that are to be monitored; may be null or empty if the UUIDs are not known
+ * @param nodeTypeNames array of node type names that are to be monitored; may be null or empty if the monitoring has no node
+ * type restrictions
+ * @param noLocal true if the events originating in the supplied workspace are to be ignored, or false if they are also to be
+ * processed.
+ * @return the listener that was created and registered to perform the monitoring
+ * @throws RepositoryException if there is a problem registering the listener
+ */
+ public WorkspaceListener monitor( String repositoryWorkspaceName, String absolutePath, int eventTypes, boolean isDeep, String[] uuids, String[] nodeTypeNames, boolean noLocal )
+ throws RepositoryException {
+ WorkspaceListener listener = new WorkspaceListener(repositoryWorkspaceName, eventTypes, absolutePath, isDeep, uuids, nodeTypeNames, noLocal);
+ listener.register();
+ return listener;
+ }
+
+ /**
+ * Monitor the supplied workspace for {@link WorkspaceListener#DEFAULT_EVENT_TYPES default event types} on any node at or
+ * under the supplied path.
+ * <p>
+ * Monitoring is accomplished by registering a listener on the workspace, so this monitoring only has access to the
+ * information that visible to the session created by the {@link #getSessionFactory() session factory} for the given
+ * repository and workspace name.
+ * </p>
+ * <p>
+ * The listener returned from this method is not managed by this SequencingService instance. If the listener is no longer
+ * needed, it simply must be {@link ObservationManager#removeEventListener(EventListener) removed} as a listener of the
+ * workspace and garbage collected.
+ * </p>
+ * @param repositoryWorkspaceName the name to be used with the session factory to obtain a session to the repository and
+ * workspace that is to be monitored
+ * @param absolutePath the absolute path of the node at or below which changes are to be monitored; may be null if all nodes
+ * in the workspace are to be monitored
+ * @param nodeTypeNames the names of the node types that are to be monitored; may be null or empty if the monitoring has no
+ * node type restrictions
+ * @return the listener that was created and registered to perform the monitoring
+ * @throws RepositoryException if there is a problem registering the listener
+ */
+ public WorkspaceListener monitor( String repositoryWorkspaceName, String absolutePath, String... nodeTypeNames ) throws RepositoryException {
+ return monitor(repositoryWorkspaceName, absolutePath, WorkspaceListener.DEFAULT_EVENT_TYPES, WorkspaceListener.DEFAULT_IS_DEEP, null, nodeTypeNames, WorkspaceListener.DEFAULT_NO_LOCAL);
+ }
+
+ /**
+ * Monitor the supplied workspace for the supplied event types on any node in the workspace.
+ * <p>
+ * Monitoring is accomplished by registering a listener on the workspace, so this monitoring only has access to the
+ * information that visible to the session created by the {@link #getSessionFactory() session factory} for the given
+ * repository and workspace name.
+ * </p>
+ * <p>
+ * The listener returned from this method is not managed by this SequencingService instance. If the listener is no longer
+ * needed, it simply must be {@link ObservationManager#removeEventListener(EventListener) removed} as a listener of the
+ * workspace and garbage collected.
+ * </p>
+ * @param repositoryWorkspaceName the name to be used with the session factory to obtain a session to the repository and
+ * workspace that is to be monitored
+ * @param eventTypes the bitmask of the {@link Event} types that are to be monitored
+ * @param nodeTypeNames the names of the node types that are to be monitored; may be null or empty if the monitoring has no
+ * node type restrictions
+ * @return the listener that was created and registered to perform the monitoring
+ * @throws RepositoryException if there is a problem registering the listener
+ */
+ public WorkspaceListener monitor( String repositoryWorkspaceName, int eventTypes, String... nodeTypeNames ) throws RepositoryException {
+ return monitor(repositoryWorkspaceName, WorkspaceListener.DEFAULT_ABSOLUTE_PATH, eventTypes, WorkspaceListener.DEFAULT_IS_DEEP, null, nodeTypeNames, WorkspaceListener.DEFAULT_NO_LOCAL);
+ }
+
+ /**
+ * From section 2.8.8 of the JSR-170 specification:
+ * <p>
+ * On each persistent change, those listeners that are entitled to receive one or more events will have their onEvent method
+ * called and be passed an EventIterator. The EventIterator will contain the event bundle reflecting the persistent changes
+ * made but excluding those to which that particular listener is not entitled, according to the listeners access permissions
+ * and filters.
+ * </p>
+ * @param events
+ * @param listener
+ */
+ protected void processEvents( EventIterator eventIterator, WorkspaceListener listener ) {
+ if (eventIterator == null) return;
+ List<Event> events = new ArrayList<Event>();
+ // Copy the events ...
+ while (eventIterator.hasNext()) {
+ events.add((Event)eventIterator.next());
+ }
+ if (!getAdministrator().isStarted()) {
+ this.statistics.recordIgnoredEventSet(events.size());
+ return;
+ }
+
+ // Notify the event listeners ...
+ boolean notifiedSomebody = false;
+ List<EventListener> eventListeners = this.eventListeners; // use one consistent snapshot
+ if (!eventListeners.isEmpty()) {
+ DelegatingEventIterator eventIter = new DelegatingEventIterator(events.iterator(), events.size());
+ for (EventListener eventListener : eventListeners) {
+ eventListener.onEvent(eventIter);
+ }
+ notifiedSomebody = true;
+ }
+
+ // Now create the node change events ...
+ List<NodeChangeListener> nodeChangeListeners = this.nodeChangeListeners; // use one consistent snapshot
+ if (!nodeChangeListeners.isEmpty()) {
+ final String repositoryWorkspaceName = listener.getRepositoryWorkspaceName();
+ try {
+ NodeChanges nodeChanges = NodeChanges.create(repositoryWorkspaceName, events);
+
+ // And notify the node change listeners ...
+ int nodeChangeCount = nodeChanges.size();
+ this.statistics.recordNodesChanged(nodeChangeCount);
+ for (NodeChangeListener nodeChangeListener : nodeChangeListeners) {
+ nodeChangeListener.onNodeChanges(nodeChanges);
+ }
+ } catch (Throwable t) {
+ getProblemLog().error(repositoryWorkspaceName, t);
+ }
+ notifiedSomebody = true;
+ }
+
+ if (notifiedSomebody) {
+ this.statistics.recordEventSet(events.size());
+ } else {
+ this.statistics.recordIgnoredEventSet(events.size());
+ }
+ }
+
+ protected class DelegatingEventIterator implements EventIterator {
+
+ private final Iterator<Event> events;
+ private final int size;
+ private int position = 0;
+
+ protected DelegatingEventIterator( Iterator<Event> events, int size ) {
+ this.events = events;
+ this.size = size;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Event nextEvent() {
+ ++position;
+ return events.next();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getPosition() {
+ return position;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getSize() {
+ return size;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void skip( long skipNum ) {
+ for (int i = 0; i != skipNum; ++i) {
+ next();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNext() {
+ return events.hasNext();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object next() {
+ return events.next();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void remove() {
+ // does nothing
+ }
+
+ }
+
+ /**
+ * Implementation of the {@link EventListener JCR EventListener} interface, returned by the sequencing system.
+ * @author Randall Hauch
+ */
+ @ThreadSafe
+ public class WorkspaceListener implements EventListener {
+
+ public static final boolean DEFAULT_IS_DEEP = true;
+ public static final boolean DEFAULT_NO_LOCAL = false;
+ public static final int DEFAULT_EVENT_TYPES = Event.NODE_ADDED | /* Event.NODE_REMOVED| */Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED /* |Event.PROPERTY_REMOVED */;
+ public static final String DEFAULT_ABSOLUTE_PATH = "/";
+
+ private final String repositoryWorkspaceName;
+ private final Set<String> uuids;
+ private final Set<String> nodeTypeNames;
+ private final int eventTypes;
+ private final String absolutePath;
+ private final boolean deep;
+ private final boolean noLocal;
+ @GuardedBy( "this" )
+ private transient Session session;
+
+ protected WorkspaceListener( String repositoryWorkspaceName, int eventTypes, String absPath, boolean isDeep, String[] uuids, String[] nodeTypeNames, boolean noLocal ) {
+ this.repositoryWorkspaceName = repositoryWorkspaceName;
+ this.eventTypes = eventTypes;
+ this.deep = isDeep;
+ this.noLocal = noLocal;
+ this.absolutePath = absPath != null && absPath.trim().length() != 0 ? absPath.trim() : null;
+ // Set the UUIDs ...
+ Set<String> newUuids = new HashSet<String>();
+ if (uuids != null) {
+ for (String uuid : uuids) {
+ if (uuid != null && uuid.trim().length() != 0) newUuids.add(uuid.trim());
+ }
+ }
+ this.uuids = Collections.unmodifiableSet(newUuids);
+ // Set the node type names
+ Set<String> newNodeTypeNames = new HashSet<String>();
+ if (nodeTypeNames != null) {
+ for (String nodeTypeName : nodeTypeNames) {
+ if (nodeTypeName != null && nodeTypeName.trim().length() != 0) newNodeTypeNames.add(nodeTypeName.trim());
+ }
+ }
+ this.nodeTypeNames = Collections.unmodifiableSet(newNodeTypeNames);
+ }
+
+ /**
+ * @return repositoryWorkspaceName
+ */
+ public String getRepositoryWorkspaceName() {
+ return this.repositoryWorkspaceName;
+ }
+
+ /**
+ * @return eventTypes
+ */
+ public int getEventTypes() {
+ return this.eventTypes;
+ }
+
+ /**
+ * @return absolutePath
+ */
+ public String getAbsolutePath() {
+ return this.absolutePath;
+ }
+
+ /**
+ * @return deep
+ */
+ public boolean isDeep() {
+ return this.deep;
+ }
+
+ /**
+ * @return noLocal
+ */
+ public boolean isNoLocal() {
+ return this.noLocal;
+ }
+
+ /**
+ * @return uuids
+ */
+ public Set<String> getUuids() {
+ return this.uuids;
+ }
+
+ /**
+ * @return nodeTypeNames
+ */
+ public Set<String> getNodeTypeNames() {
+ return this.nodeTypeNames;
+ }
+
+ public synchronized boolean isRegistered() {
+ if (this.session != null && getAdministrator().isShutdown()) {
+ // This sequencing system has been shutdown, so unregister this listener
+ try {
+ unregister();
+ } catch (RepositoryException re) {
+ String msg = "Error unregistering workspace listener after sequencing system has been shutdow.";
+ Logger.getLogger(this.getClass()).debug(re, msg);
+ }
+ }
+ return this.session != null;
+ }
+
+ public synchronized WorkspaceListener register() throws UnsupportedRepositoryOperationException, RepositoryException {
+ if (this.session != null) return this;
+ this.session = ObservationService.this.getSessionFactory().createSession(this.repositoryWorkspaceName);
+ String[] uuids = this.uuids.isEmpty() ? null : this.uuids.toArray(new String[this.uuids.size()]);
+ String[] nodeTypeNames = this.nodeTypeNames.isEmpty() ? null : this.nodeTypeNames.toArray(new String[this.nodeTypeNames.size()]);
+ this.session.getWorkspace().getObservationManager().addEventListener(this, eventTypes, absolutePath, deep, uuids, nodeTypeNames, noLocal);
+ return this;
+ }
+
+ public synchronized WorkspaceListener unregister() throws UnsupportedRepositoryOperationException, RepositoryException {
+ if (this.session == null) return this;
+ try {
+ this.session.getWorkspace().getObservationManager().removeEventListener(this);
+ this.session.logout();
+ } finally {
+ this.session = null;
+ }
+ return this;
+ }
+
+ public synchronized WorkspaceListener reregister() throws UnsupportedRepositoryOperationException, RepositoryException {
+ unregister();
+ register();
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onEvent( EventIterator events ) {
+ if (events != null) {
+ if (getAdministrator().isShutdown()) {
+ // This sequencing system has been shutdown, so unregister this listener
+ try {
+ unregister();
+ } catch (RepositoryException re) {
+ String msg = "Error unregistering workspace listener after sequencing system has been shutdow.";
+ Logger.getLogger(this.getClass()).debug(re, msg);
+ }
+ } else {
+ ObservationService.this.processEvents(events, this);
+ }
+ }
+ }
+ }
+
+ /**
+ * The statistics for the system. Each sequencing system has an instance of this class that is updated.
+ * @author Randall Hauch
+ */
+ @ThreadSafe
+ public class Statistics {
+
+ @GuardedBy( "lock" )
+ private long numberOfEventsIgnored;
+ @GuardedBy( "lock" )
+ private long numberOfEventsEnqueued;
+ @GuardedBy( "lock" )
+ private long numberOfEventSetsIgnored;
+ @GuardedBy( "lock" )
+ private long numberOfEventSetsEnqueued;
+ private final AtomicLong numberOfNodeChangesEnqueued = new AtomicLong(0);
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final AtomicLong startTime;
+
+ protected Statistics() {
+ startTime = new AtomicLong(System.currentTimeMillis());
+ }
+
+ public Statistics reset() {
+ try {
+ lock.writeLock().lock();
+ this.startTime.set(System.currentTimeMillis());
+ this.numberOfEventsIgnored = 0;
+ this.numberOfEventsEnqueued = 0;
+ this.numberOfEventSetsIgnored = 0;
+ this.numberOfEventSetsEnqueued = 0;
+ this.numberOfNodeChangesEnqueued.set(0);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ return this;
+ }
+
+ /**
+ * @return the system time when the statistics were started
+ */
+ public long getStartTime() {
+ return this.startTime.get();
+ }
+
+ /**
+ * @return the number of node changes that were processed
+ */
+ public long getNumberOfNodeChangesEnqueued() {
+ return this.numberOfNodeChangesEnqueued.get();
+ }
+
+ /**
+ * @return the number of events that were ignored because the system was not running
+ */
+ public long getNumberOfEventsIgnored() {
+ try {
+ lock.readLock().lock();
+ return this.numberOfEventsIgnored;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * @return the number of events that were enqueued for processing
+ */
+ public long getNumberOfEventsEnqueued() {
+ try {
+ lock.readLock().lock();
+ return this.numberOfEventsEnqueued;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * @return the number of event sets (transactions) that were enqueued for processing
+ */
+ public long getNumberOfEventSetsEnqueued() {
+ try {
+ lock.readLock().lock();
+ return this.numberOfEventSetsEnqueued;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * @return the number of event sets (transactions) that were ignored because the system was not running
+ */
+ public long getNumberOfEventSetsIgnored() {
+ try {
+ lock.readLock().lock();
+ return this.numberOfEventSetsIgnored;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ protected void recordNodesChanged( long changeCount ) {
+ this.numberOfNodeChangesEnqueued.addAndGet(changeCount);
+ }
+
+ protected void recordEventSet( long eventsInSet ) {
+ try {
+ lock.writeLock().lock();
+ this.numberOfEventsEnqueued += eventsInSet;
+ ++this.numberOfEventSetsEnqueued;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ protected void recordIgnoredEventSet( long eventsInSet ) {
+ try {
+ lock.writeLock().lock();
+ this.numberOfEventsIgnored += eventsInSet;
+ this.numberOfEventSetsIgnored += 1;
+ ++this.numberOfEventSetsEnqueued;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+ }
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/InvalidRuleSetException.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/InvalidRuleSetException.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/InvalidRuleSetException.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.rules;
+
+/**
+ * @author Randall Hauch
+ */
+public class InvalidRuleSetException extends RuntimeException {
+
+ /**
+ *
+ */
+ public InvalidRuleSetException() {
+ }
+
+ /**
+ * @param message
+ */
+ public InvalidRuleSetException( String message ) {
+ super(message);
+
+ }
+
+ /**
+ * @param cause
+ */
+ public InvalidRuleSetException( Throwable cause ) {
+ super(cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public InvalidRuleSetException( String message, Throwable cause ) {
+ super(message, cause);
+
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleService.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleService.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,468 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.rules;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.rules.ConfigurationException;
+import javax.rules.RuleRuntime;
+import javax.rules.RuleServiceProvider;
+import javax.rules.RuleServiceProviderManager;
+import javax.rules.RuleSession;
+import javax.rules.StatelessRuleSession;
+import javax.rules.admin.LocalRuleExecutionSetProvider;
+import javax.rules.admin.RuleAdministrator;
+import javax.rules.admin.RuleExecutionSet;
+import javax.rules.admin.RuleExecutionSetCreateException;
+import javax.rules.admin.RuleExecutionSetDeregistrationException;
+import net.jcip.annotations.GuardedBy;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.SystemFailureException;
+import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.component.StandardClassLoaderFactory;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.repository.services.AbstractServiceAdministrator;
+import org.jboss.dna.repository.services.AdministeredService;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+
+/**
+ * A rule service that is capable of executing rule sets using one or more JSR-94 rule engines. Sets of rules are
+ * {@link #addRuleSet(RuleSet) added}, {@link #updateRuleSet(RuleSet) updated}, and {@link #removeRuleSet(String) removed}
+ * (usually by some other component), and then these named rule sets can be {@link #executeRules(String, Map, Object...) run} with
+ * inputs and facts to obtain output.
+ * <p>
+ * This service is thread safe. While multiple rule sets can be safely {@link #executeRules(String, Map, Object...) executed} at
+ * the same time, all executions will be properly synchronized with methods to {@link #addRuleSet(RuleSet) add},
+ * {@link #updateRuleSet(RuleSet) update}, and {@link #removeRuleSet(String) remove} rule sets.
+ * </p>
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class RuleService implements AdministeredService {
+
+ protected static final ClassLoaderFactory DEFAULT_CLASSLOADER_FACTORY = new StandardClassLoaderFactory(RuleService.class.getClassLoader());
+
+ /**
+ * The administrative component for this service.
+ * @author Randall Hauch
+ */
+ protected class Administrator extends AbstractServiceAdministrator {
+
+ protected Administrator() {
+ super(State.PAUSED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String serviceName() {
+ return "RuleService";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doShutdown( State fromState ) {
+ super.doShutdown(fromState);
+ // Remove all rule sets ...
+ removeAllRuleSets();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
+ return doAwaitTermination(timeout, unit);
+ }
+
+ }
+
+ private Logger logger;
+ private ClassLoaderFactory classLoaderFactory = DEFAULT_CLASSLOADER_FACTORY;
+ private final Administrator administrator = new Administrator();
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ @GuardedBy( "lock" )
+ private final Map<String, RuleSet> ruleSets = new HashMap<String, RuleSet>();
+ private final CountDownLatch shutdownLatch = new CountDownLatch(1);
+
+ /**
+ * Create a new rule service, configured with no rule sets. Upon construction, the system is
+ * {@link ServiceAdministrator#isPaused() paused} and must be configured and then {@link ServiceAdministrator#start() started}.
+ */
+ public RuleService() {
+ this.logger = Logger.getLogger(this.getClass());
+ }
+
+ /**
+ * Return the administrative component for this service.
+ * @return the administrative component; never null
+ */
+ public ServiceAdministrator getAdministrator() {
+ return this.administrator;
+ }
+
+ /**
+ * Get the class loader factory that should be used to load sequencers. By default, this service uses a factory that will
+ * return either the {@link Thread#getContextClassLoader() current thread's context class loader} (if not null) or the class
+ * loader that loaded this class.
+ * @return the class loader factory; never null
+ * @see #setClassLoaderFactory(ClassLoaderFactory)
+ */
+ public ClassLoaderFactory getClassLoaderFactory() {
+ return this.classLoaderFactory;
+ }
+
+ /**
+ * Set the Maven Repository that should be used to load the sequencer classes. By default, this service uses a class loader
+ * factory that will return either the {@link Thread#getContextClassLoader() current thread's context class loader} (if not
+ * null) or the class loader that loaded this class.
+ * @param classLoaderFactory the class loader factory reference, or null if the default class loader factory should be used.
+ * @see #getClassLoaderFactory()
+ */
+ public void setClassLoaderFactory( ClassLoaderFactory classLoaderFactory ) {
+ this.classLoaderFactory = classLoaderFactory != null ? classLoaderFactory : DEFAULT_CLASSLOADER_FACTORY;
+ }
+
+ /**
+ * Obtain the rule sets that are currently available in this service.
+ * @return an unmodifiable copy of the rule sets; never null, but possibly empty ...
+ */
+ public Collection<RuleSet> getRuleSets() {
+ List<RuleSet> results = new ArrayList<RuleSet>();
+ try {
+ this.lock.readLock().lock();
+ // Make a copy of the rule sets ...
+ if (ruleSets.size() != 0) results.addAll(this.ruleSets.values());
+ } finally {
+ this.lock.readLock().unlock();
+ }
+ return Collections.unmodifiableList(results);
+ }
+
+ /**
+ * Add a rule set, or update any existing one that represents the {@link RuleSet#equals(Object) same rule set}
+ * @param ruleSet the new rule set
+ * @return true if the rule set was added, or false if the rule set was not added (because it wasn't necessary)
+ * @throws IllegalArgumentException if <code>ruleSet</code> is null
+ * @throws InvalidRuleSetException if the supplied rule set is invalid, incomplete, incorrectly defined, or uses a JSR-94
+ * service provider that cannot be found
+ * @see #updateRuleSet(RuleSet)
+ * @see #removeRuleSet(String)
+ */
+ public boolean addRuleSet( RuleSet ruleSet ) {
+ ArgCheck.isNotNull(ruleSet, "rule set");
+ final String providerUri = ruleSet.getProviderUri();
+ final String ruleSetName = ruleSet.getName();
+ final String rules = ruleSet.getRules();
+ final Map<?, ?> properties = ruleSet.getExecutionSetProperties();
+ final Reader ruleReader = new StringReader(rules);
+ boolean updatedRuleSets = false;
+ try {
+ this.lock.writeLock().lock();
+
+ // Make sure the rule service provider is available ...
+ RuleServiceProvider ruleServiceProvider = findRuleServiceProvider(ruleSet);
+ assert ruleServiceProvider != null;
+
+ // Now register a new execution set ...
+ RuleAdministrator ruleAdmin = ruleServiceProvider.getRuleAdministrator();
+ if (ruleAdmin == null) {
+ throw new InvalidRuleSetException(RepositoryI18n.unableToObtainJsr94RuleAdministrator.text(providerUri, ruleSet.getComponentClassname(), ruleSetName));
+ }
+
+ // Is there is an existing rule set and, if so, whether it has changed ...
+ RuleSet existing = this.ruleSets.get(ruleSetName);
+
+ // Create the rule execution set (do this before deregistering, in case there is a problem)...
+ LocalRuleExecutionSetProvider ruleExecutionSetProvider = ruleAdmin.getLocalRuleExecutionSetProvider(null);
+ RuleExecutionSet executionSet = ruleExecutionSetProvider.createRuleExecutionSet(ruleReader, properties);
+
+ // We should add the execiting rule set if there wasn't one or if the rule set has changed ...
+ boolean shouldAdd = existing == null || ruleSet.hasChanged(existing);
+ if (existing != null && shouldAdd) {
+ // There is an existing execution set and it needs to be updated, so deregister it ...
+ ruleServiceProvider = deregister(ruleSet);
+ }
+ if (shouldAdd) {
+ boolean rollback = false;
+ try {
+ // Now register the new execution set and update the rule set managed by this service ...
+ ruleAdmin.registerRuleExecutionSet(ruleSetName, executionSet, null);
+ this.ruleSets.remove(ruleSet.getName());
+ this.ruleSets.put(ruleSet.getName(), ruleSet);
+ updatedRuleSets = true;
+ } catch (Throwable t) {
+ rollback = true;
+ throw new InvalidRuleSetException(RepositoryI18n.errorAddingOrUpdatingRuleSet.text(ruleSet.getName()), t);
+ } finally {
+ if (rollback) {
+ try {
+ // There was a problem, so re-register the original existing rule set ...
+ if (existing != null) {
+ final String oldRules = existing.getRules();
+ final Map<?, ?> oldProperties = existing.getExecutionSetProperties();
+ final Reader oldRuleReader = new StringReader(oldRules);
+ ruleServiceProvider = findRuleServiceProvider(existing);
+ assert ruleServiceProvider != null;
+ executionSet = ruleExecutionSetProvider.createRuleExecutionSet(oldRuleReader, oldProperties);
+ ruleAdmin.registerRuleExecutionSet(ruleSetName, executionSet, null);
+ this.ruleSets.remove(ruleSetName);
+ this.ruleSets.put(ruleSetName, existing);
+ }
+ } catch (Throwable rollbackError) {
+ // There was a problem rolling back to the existing rule set, and we're going to throw the
+ // exception associated with the updated/new rule set, so just log this problem
+ this.logger.error(rollbackError, RepositoryI18n.errorRollingBackRuleSetAfterUpdateFailed, ruleSetName);
+ }
+ }
+ }
+ }
+ } catch (InvalidRuleSetException e) {
+ throw e;
+ } catch (ConfigurationException t) {
+ throw new InvalidRuleSetException(RepositoryI18n.unableToObtainJsr94RuleAdministrator.text(providerUri, ruleSet.getComponentClassname(), ruleSetName));
+ } catch (RemoteException t) {
+ throw new InvalidRuleSetException(RepositoryI18n.errorUsingJsr94RuleAdministrator.text(providerUri, ruleSet.getComponentClassname(), ruleSetName));
+ } catch (IOException t) {
+ throw new InvalidRuleSetException(RepositoryI18n.errorReadingRulesAndProperties.text(ruleSetName));
+ } catch (RuleExecutionSetDeregistrationException t) {
+ throw new InvalidRuleSetException(RepositoryI18n.errorDeregisteringRuleSetBeforeUpdatingIt.text(ruleSetName));
+ } catch (RuleExecutionSetCreateException t) {
+ throw new InvalidRuleSetException(RepositoryI18n.errorRecreatingRuleSet.text(ruleSetName));
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ return updatedRuleSets;
+ }
+
+ /**
+ * Update the configuration for a sequencer, or add it if there is no {@link RuleSet#equals(Object) matching configuration}.
+ * @param ruleSet the rule set to be updated
+ * @return true if the rule set was updated, or false if the rule set was not updated (because it wasn't necessary)
+ * @throws InvalidRuleSetException if the supplied rule set is invalid, incomplete, incorrectly defined, or uses a JSR-94
+ * service provider that cannot be found
+ * @see #addRuleSet(RuleSet)
+ * @see #removeRuleSet(String)
+ */
+ public boolean updateRuleSet( RuleSet ruleSet ) {
+ return addRuleSet(ruleSet);
+ }
+
+ /**
+ * Remove a rule set.
+ * @param ruleSetName the name of the rule set to be removed
+ * @return true if the rule set was removed, or if it was not an existing rule set
+ * @throws IllegalArgumentException if <code>ruleSetName</code> is null or empty
+ * @throws SystemFailureException if the rule set was found but there was a problem removing it
+ * @see #addRuleSet(RuleSet)
+ * @see #updateRuleSet(RuleSet)
+ */
+ public boolean removeRuleSet( String ruleSetName ) {
+ ArgCheck.isNotEmpty(ruleSetName, "rule set");
+ try {
+ this.lock.writeLock().lock();
+ RuleSet ruleSet = this.ruleSets.remove(ruleSetName);
+ if (ruleSet != null) {
+ try {
+ deregister(ruleSet);
+ } catch (Throwable t) {
+ // There was a problem deregistering the rule set, so put it back ...
+ this.ruleSets.put(ruleSetName, ruleSet);
+ }
+ return true;
+ }
+ } catch (Throwable t) {
+ throw new SystemFailureException(RepositoryI18n.errorRemovingRuleSet.text(ruleSetName), t);
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ return false;
+ }
+
+ /**
+ * Get the logger for this system
+ * @return the logger
+ */
+ public Logger getLogger() {
+ return this.logger;
+ }
+
+ /**
+ * Set the logger for this system.
+ * @param logger the logger, or null if the standard logging should be used
+ */
+ public void setLogger( Logger logger ) {
+ this.logger = logger != null ? logger : Logger.getLogger(this.getClass());
+ }
+
+ /**
+ * Execute the set of rules defined by the supplied rule set name. This method is safe to be concurrently called by multiple
+ * threads, and is properly synchronized with the methods to {@link #addRuleSet(RuleSet) add},
+ * {@link #updateRuleSet(RuleSet) update}, and {@link #removeRuleSet(String) remove} rule sets.
+ * @param ruleSetName the {@link RuleSet#getName() name} of the {@link RuleSet} that should be used
+ * @param globals the global variables
+ * @param facts the facts
+ * @return the results of executing the rule set
+ * @throws IllegalArgumentException if the rule set name is null, empty or blank, or if there is no rule set with the given
+ * name
+ * @throws SystemFailureException if there is no JSR-94 rule service provider with the
+ * {@link RuleSet#getProviderUri() RuleSet's provider URI}.
+ */
+ public List<?> executeRules( String ruleSetName, Map<String, Object> globals, Object... facts ) {
+ ArgCheck.isNotEmpty(ruleSetName, "rule set name");
+ List<?> result = null;
+ List<?> factList = Arrays.asList(facts);
+ try {
+ this.lock.readLock().lock();
+
+ // Find the rule set ...
+ RuleSet ruleSet = this.ruleSets.get(ruleSetName);
+ if (ruleSet == null) {
+ throw new IllegalArgumentException(RepositoryI18n.unableToFindRuleSet.text(ruleSetName));
+ }
+
+ // Look up the provider ...
+ RuleServiceProvider ruleServiceProvider = findRuleServiceProvider(ruleSet);
+ assert ruleServiceProvider != null;
+
+ // Create the rule session ...
+ RuleRuntime ruleRuntime = ruleServiceProvider.getRuleRuntime();
+ String executionSetName = ruleSet.getRuleSetUri();
+ RuleSession session = ruleRuntime.createRuleSession(executionSetName, globals, RuleRuntime.STATELESS_SESSION_TYPE);
+ try {
+ StatelessRuleSession statelessSession = (StatelessRuleSession)session;
+ result = statelessSession.executeRules(factList);
+ } finally {
+ session.release();
+ }
+ if (this.logger.isTraceEnabled()) {
+ String msg = "Executed rule set '{1}' with globals {2} and facts {3} resulting in {4}";
+ this.logger.trace(msg, ruleSetName, StringUtil.readableString(globals), StringUtil.readableString(facts), StringUtil.readableString(result));
+ }
+ } catch (Throwable t) {
+ throw new SystemFailureException(RepositoryI18n.errorExecutingRuleSetWithGlobalsAndFacts.text(ruleSetName, StringUtil.readableString(globals), StringUtil.readableString(facts)), t);
+ } finally {
+ this.lock.readLock().unlock();
+ }
+ return result;
+ }
+
+ protected void removeAllRuleSets() {
+ try {
+ lock.writeLock().lock();
+ for (RuleSet ruleSet : ruleSets.values()) {
+ try {
+ deregister(ruleSet);
+ } catch (Throwable t) {
+ logger.error(t, RepositoryI18n.errorRemovingRuleSetUponShutdown, ruleSet.getName());
+ }
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ this.shutdownLatch.countDown();
+ }
+
+ protected boolean doAwaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
+ return this.shutdownLatch.await(timeout, unit);
+ }
+
+ /**
+ * Finds the JSR-94 service provider instance and returns it. If it could not be found, this method attempts to load it.
+ * @param ruleSet the rule set for which the service provider is to be found; may not be null
+ * @return the rule service provider; never null
+ * @throws ConfigurationException if there is a problem loading the service provider
+ * @throws InvalidRuleSetException if the service provider could not be found
+ */
+ private RuleServiceProvider findRuleServiceProvider( RuleSet ruleSet ) throws ConfigurationException {
+ assert ruleSet != null;
+ String providerUri = ruleSet.getProviderUri();
+ RuleServiceProvider ruleServiceProvider = null;
+ try {
+ // If the provider could not be found, then a ConfigurationException will be thrown ...
+ ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider(providerUri);
+ } catch (ConfigurationException e) {
+ try {
+ // Use JSR-94 to load the RuleServiceProvider instance ...
+ ClassLoader loader = this.classLoaderFactory.getClassLoader(ruleSet.getComponentClasspathArray());
+ // Don't call ClassLoader.loadClass(String), as this doesn't initialize the class!!
+ Class.forName(ruleSet.getComponentClassname(), true, loader);
+ ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider(providerUri);
+ this.logger.debug("Loaded the rule service provider {0} ({1})", providerUri, ruleSet.getComponentClassname());
+ } catch (ConfigurationException ce) {
+ throw ce;
+ } catch (Throwable t) {
+ throw new InvalidRuleSetException(RepositoryI18n.unableToObtainJsr94ServiceProvider.text(providerUri, ruleSet.getComponentClassname()), t);
+ }
+ }
+ if (ruleServiceProvider == null) {
+ throw new InvalidRuleSetException(RepositoryI18n.unableToObtainJsr94ServiceProvider.text(providerUri, ruleSet.getComponentClassname()));
+ }
+ return ruleServiceProvider;
+ }
+
+ /**
+ * Deregister the supplied rule set, if it could be found. This method does nothing if any of the service provider components
+ * could not be found.
+ * @param ruleSet the rule set to be deregistered; may not be null
+ * @return the service provider reference, or null if the service provider could not be found ...
+ * @throws ConfigurationException
+ * @throws RuleExecutionSetDeregistrationException
+ * @throws RemoteException
+ */
+ private RuleServiceProvider deregister( RuleSet ruleSet ) throws ConfigurationException, RuleExecutionSetDeregistrationException, RemoteException {
+ assert ruleSet != null;
+ // Look up the provider ...
+ String providerUri = ruleSet.getProviderUri();
+ assert providerUri != null;
+
+ // Look for the provider ...
+ RuleServiceProvider ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider(providerUri);
+ if (ruleServiceProvider != null) {
+ // Deregister the rule set ...
+ RuleAdministrator ruleAdmin = ruleServiceProvider.getRuleAdministrator();
+ if (ruleAdmin != null) {
+ ruleAdmin.deregisterRuleExecutionSet(ruleSet.getRuleSetUri(), null);
+ }
+ }
+ return ruleServiceProvider;
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSet.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSet.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSet.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,152 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.rules;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.rules.RuleServiceProvider;
+import javax.rules.admin.RuleExecutionSet;
+import javax.rules.admin.RuleExecutionSetProvider;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.component.ComponentConfig;
+import org.jboss.dna.common.util.ArgCheck;
+
+/**
+ * A description of a set of rules compatible with a JSR-94 rule engine.
+ * @author Randall Hauch
+ */
+@Immutable
+public class RuleSet extends ComponentConfig implements Cloneable {
+
+ private final String providerUri;
+ private final String ruleSetUri;
+ private final String rules;
+ private final Map<String, Object> properties;
+
+ /**
+ * Create a JSR-94 rule set definition.
+ * @param name the name of the rule set, which is considered the unique identifier
+ * @param description the description
+ * @param classname the name of the Java class used for the component
+ * @param classpath the optional classpath (defined in a way compatible with a {@link ClassLoaderFactory}
+ * @param providerUri the URI of the JSR-94 {@link RuleServiceProvider} implementation to use
+ * @param ruleSetUri the URI of the JSR-94 {@link RuleExecutionSet} represented by this object; if null, the name is used
+ * @param rules the string containing the rules in a provider-specific language
+ * @param properties the provider-specific properties, whose values should be strings or byte arrays (the latter if the
+ * provider expects an {@link Reader} with the value)
+ * @throws IllegalArgumentException if any of the name, classname, provider URI, or rules parameters are null, empty or blank,
+ * or if the classname is not a valid Java classname
+ */
+ public RuleSet( String name, String description, String classname, String[] classpath, String providerUri, String ruleSetUri, String rules, Map<String, Object> properties ) {
+ super(name, description, System.currentTimeMillis(), classname, classpath);
+ if (ruleSetUri == null) ruleSetUri = name.trim();
+ ArgCheck.isNotEmpty(ruleSetUri, "rule set URI");
+ ArgCheck.isNotEmpty(providerUri, "provider URI");
+ ArgCheck.isNotEmpty(rules, "rules");
+ this.providerUri = providerUri;
+ this.ruleSetUri = ruleSetUri;
+ this.rules = rules;
+ if (properties == null) properties = Collections.emptyMap();
+ this.properties = Collections.unmodifiableMap(properties);
+ }
+
+ /**
+ * Get the URI of the JSR-94 {@link RuleServiceProvider} implementation that should be used.
+ * @return the URI of the JSR-94 implementation; never null, empty or blank
+ */
+ public String getProviderUri() {
+ return this.providerUri;
+ }
+
+ /**
+ * Get the URI of this rule set. The value must be valid as defined by JSR-94 {@link RuleExecutionSet}.
+ * @return the rule set's URI; never null, empty or blank
+ */
+ public String getRuleSetUri() {
+ return this.ruleSetUri;
+ }
+
+ /**
+ * Get the rules defined in terms of the language reqired by the {@link #getProviderUri() provider}.
+ * @return the rules for this rule set
+ */
+ public String getRules() {
+ return this.rules;
+ }
+
+ /**
+ * Get this rule set's properties as an unmodifiable map. Note that the values of these properties are either strings if the
+ * value is to be {@link #getExecutionSetProperties() passed} literally, or a byte array if the value is to be
+ * {@link #getExecutionSetProperties() passed} as an InputStream.
+ * @return the unmodifiable properties; never null but possible empty
+ */
+ public Map<String, Object> getProperties() {
+ return this.properties;
+ }
+
+ /**
+ * Get the properties for this rule set that can be passed to an {@link RuleExecutionSetProvider}'s
+ * {@link RuleExecutionSetProvider#createRuleExecutionSet(String, Map) createRuleExecutionSet} method.
+ * <p>
+ * This method converts any byte array value in the {@link #getProperties() properties} into an {@link Reader}. Since
+ * {@link ByteArrayInputStream} is used, there is no need to close these stream.
+ * </p>
+ * @return the properties; never null but possible empty
+ */
+ public Map<Object, Object> getExecutionSetProperties() {
+ Map<Object, Object> props = new HashMap<Object, Object>();
+ for (Map.Entry<String, Object> entry : this.properties.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (value instanceof byte[]) {
+ value = new InputStreamReader(new ByteArrayInputStream((byte[])value));
+ }
+ props.put(key, value);
+ }
+ return props;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean hasChanged( ComponentConfig obj ) {
+ if (super.hasChanged(obj)) return true;
+ RuleSet that = (RuleSet)obj;
+ if (!this.providerUri.equals(that.providerUri)) return true;
+ if (!this.ruleSetUri.equals(that.ruleSetUri)) return true;
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public RuleSet clone() {
+ return new RuleSet(this.getName(), this.getDescription(), this.getComponentClassname(), this.getComponentClasspathArray(), this.providerUri, this.ruleSetUri, this.rules, this.properties);
+ }
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSetRepositoryMonitor.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSetRepositoryMonitor.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSetRepositoryMonitor.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,257 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.rules;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.repository.observation.NodeChange;
+import org.jboss.dna.repository.observation.NodeChangeListener;
+import org.jboss.dna.repository.observation.NodeChanges;
+import org.jboss.dna.repository.observation.ObservationService;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.JcrTools;
+
+/**
+ * A component that can listen to a JCR repository and keep the {@link RuleSet} instances of a {@link RuleService} synchronized
+ * with that repository.
+ * <p>
+ * This class is a {@link NodeChangeListener} that can {@link ObservationService#addListener(NodeChangeListener) subscribe} to
+ * changes in one or more JCR repositories being monitored by an {@link ObservationService}. As changes under the rule sets
+ * branch are discovered, they are processed asynchronously. This ensure that the processing of the repository contents does not
+ * block the other listeners of the {@link ObservationService}.
+ * </p>
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class RuleSetRepositoryMonitor implements NodeChangeListener {
+
+ public static final String DEFAULT_JCR_ABSOLUTE_PATH = "/dna:system/dna:ruleSets/";
+
+ protected static final String JCR_PATH_DELIM = "/";
+
+ private final ExecutionContext executionContext;
+ private final RuleService ruleService;
+ private final String jcrAbsolutePath;
+ private final Pattern ruleSetNamePattern;
+ private final ExecutorService executorService;
+ private Logger logger;
+
+ /**
+ * Create an instance that can listen to the {@link RuleSet} definitions stored in a JCR repository and ensure that the
+ * {@link RuleSet} instances of a {@link RuleService} reflect the definitions in the repository.
+ * @param ruleService the rule service that should be kept in sync with the JCR repository.
+ * @param jcrAbsolutePath the absolute path to the branch where the rule sets are defined; if null or empty, the
+ * {@link #DEFAULT_JCR_ABSOLUTE_PATH default path} is used
+ * @param executionContext the context in which this monitor is to execute
+ * @throws IllegalArgumentException if the rule service or execution context is null, or if the supplied
+ * <code>jcrAbsolutePath</code> is invalid
+ */
+ public RuleSetRepositoryMonitor( RuleService ruleService, String jcrAbsolutePath, ExecutionContext executionContext ) {
+ ArgCheck.isNotNull(ruleService, "rule service");
+ ArgCheck.isNotNull(executionContext, "execution context");
+ this.ruleService = ruleService;
+ this.executionContext = executionContext;
+ this.executorService = Executors.newSingleThreadExecutor();
+ this.logger = Logger.getLogger(this.getClass());
+ if (jcrAbsolutePath != null) jcrAbsolutePath = jcrAbsolutePath.trim();
+ this.jcrAbsolutePath = jcrAbsolutePath != null && jcrAbsolutePath.length() != 0 ? jcrAbsolutePath : DEFAULT_JCR_ABSOLUTE_PATH;
+ try {
+ // Create the pattern to extract the rule set name from the absolute path ...
+ String leadingPath = this.jcrAbsolutePath;
+ if (!leadingPath.endsWith(JCR_PATH_DELIM)) leadingPath = leadingPath + JCR_PATH_DELIM;
+ this.ruleSetNamePattern = Pattern.compile(leadingPath + "([^/]+)/?.*");
+ } catch (PatternSyntaxException e) {
+ throw new IllegalArgumentException(RepositoryI18n.unableToBuildRuleSetRegularExpressionPattern.text(e.getPattern(), jcrAbsolutePath, e.getDescription()));
+ }
+ }
+
+ /**
+ * @return ruleService
+ */
+ public RuleService getRuleService() {
+ return this.ruleService;
+ }
+
+ /**
+ * @return jcrAbsolutePath
+ */
+ public String getAbsolutePathToRuleSets() {
+ return this.jcrAbsolutePath;
+ }
+
+ /**
+ * @return logger
+ */
+ public Logger getLogger() {
+ return this.logger;
+ }
+
+ /**
+ * @param logger Sets logger to the specified value.
+ */
+ public void setLogger( Logger logger ) {
+ this.logger = logger;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onNodeChanges( NodeChanges changes ) {
+ final Map<String, Set<String>> ruleSetNamesByWorkspaceName = new HashMap<String, Set<String>>();
+ for (NodeChange nodeChange : changes) {
+ if (nodeChange.isNotOnPath(this.jcrAbsolutePath)) continue;
+ // Use a regular expression on the absolute path to get the name of the rule set that is affected ...
+ Matcher matcher = this.ruleSetNamePattern.matcher(nodeChange.getAbsolutePath());
+ if (!matcher.matches()) continue;
+ String ruleSetName = matcher.group(1);
+ // Record the repository name ...
+ String workspaceName = nodeChange.getRepositoryWorkspaceName();
+ Set<String> ruleSetNames = ruleSetNamesByWorkspaceName.get(workspaceName);
+ if (ruleSetNames == null) {
+ ruleSetNames = new HashSet<String>();
+ ruleSetNamesByWorkspaceName.put(workspaceName, ruleSetNames);
+ }
+ // Record the rule set name ...
+ ruleSetNames.add(ruleSetName);
+
+ }
+ if (ruleSetNamesByWorkspaceName.isEmpty()) return;
+ // Otherwise there are changes, so submit the names to the executor service ...
+ this.executorService.execute(new Runnable() {
+
+ public void run() {
+ processRuleSets(ruleSetNamesByWorkspaceName);
+ }
+ });
+ }
+
+ /**
+ * Process the rule sets given by the supplied names, keyed by the repository workspace name.
+ * @param ruleSetNamesByWorkspaceName the set of rule set names keyed by the repository workspace name
+ */
+ protected void processRuleSets( Map<String, Set<String>> ruleSetNamesByWorkspaceName ) {
+ final JcrTools tools = this.executionContext.getTools();
+ final String relPathToRuleSets = getAbsolutePathToRuleSets().substring(1);
+ for (Map.Entry<String, Set<String>> entry : ruleSetNamesByWorkspaceName.entrySet()) {
+ String workspaceName = entry.getKey();
+ Session session = null;
+ try {
+ session = this.executionContext.getSessionFactory().createSession(workspaceName);
+ // Look up the node that represents the parent of the rule set nodes ...
+ Node ruleSetsNode = session.getRootNode().getNode(relPathToRuleSets);
+
+ for (String ruleSetName : entry.getValue()) {
+ // Look up the node that represents the rule set...
+ if (ruleSetsNode.hasNode(ruleSetName)) {
+ // We don't handle multiple siblings with the same name, so this should grab the first one ...
+ Node ruleSetNode = ruleSetsNode.getNode(ruleSetName);
+ RuleSet ruleSet = buildRuleSet(ruleSetName, ruleSetNode, tools);
+ if (ruleSet != null) {
+ // Only do something if the RuleSet was instantiated ...
+ getRuleService().addRuleSet(ruleSet);
+ }
+ } else {
+ // The node doesn't exist, so remove the rule set ...
+ getRuleService().removeRuleSet(ruleSetName);
+ }
+ }
+ } catch (RepositoryException e) {
+ getLogger().error(e, RepositoryI18n.errorObtainingSessionToRepositoryWorkspace, workspaceName);
+ } finally {
+ if (session != null) session.logout();
+ }
+ }
+ }
+
+ /**
+ * Create a rule set from the supplied node. This is called whenever a branch of the repository is changed.
+ * <p>
+ * This implementation expects a node of type 'dna:ruleSet' and the following properties (expressed as XPath statements
+ * relative to the supplied node):
+ * <ul>
+ * <li>The {@link RuleSet#getDescription() description} is obtained from the "<code>./@jcr:description</code>" string
+ * property. This property is optional.</li>
+ * <li>The {@link RuleSet#getComponentClassname() classname} is obtained from the "<code>./@dna:classname</code>" string
+ * property. This property is required.</li>
+ * <li>The {@link RuleSet#getComponentClasspath() classpath} is obtained from the "<code>./@dna:classpath</code>" string
+ * property. This property is optional, and if abscent then the classpath will be assumed from the current context.</li>
+ * <li>The {@link RuleSet#getProviderUri() provider URI} is obtained from the "<code>./@dna:serviceProviderUri</code>"
+ * string property, and corresponds to the URI of the JSR-94 rules engine service provider. This property is required.</li>
+ * <li>The {@link RuleSet#getRuleSetUri() rule set URI} is obtained from the "<code>./@dna:ruleSetUri</code>" string
+ * property. This property is optional and defaults to the node name (e.g., "<code>./@jcr:name</code>").</li>
+ * <li>The {@link RuleSet#getRules() definition of the rules} is obtained from the "<code>./@dna:rules</code>" string
+ * property. This property is required and must be in a form suitable for the JSR-94 rules engine.</li>
+ * <li>The {@link RuleSet#getProperties() properties} are obtained from the "<code>./dna:properties[contains(@jcr:mixinTypes,'dna:propertyContainer')]/*[@jcr:nodeType='dna:property']</code>"
+ * property nodes, where the name of the property is extracted from the property node's "<code>./@jcr:name</code>" string
+ * property and the value of the property is extracted from the property node's "<code>./@dna:propertyValue</code>" string
+ * property. Rule set properties are optional.</li>
+ * </ul>
+ * </p>
+ * @param name the name of the rule set; never null
+ * @param ruleSetNode the node representing the rule set; null if the rule set doesn't exist
+ * @return the rule set for the information stored in the repository, or null if the rule set does not exist or has errors
+ */
+ protected RuleSet buildRuleSet( String name, Node ruleSetNode, JcrTools tools ) {
+ if (ruleSetNode == null) return null;
+
+ Problems problems = new Problems();
+ String description = tools.getPropertyAsString(ruleSetNode, "jcr:description", false, problems);
+ String classname = tools.getPropertyAsString(ruleSetNode, "dna:classname", true, problems);
+ String[] classpath = tools.getPropertyAsStringArray(ruleSetNode, "dna:classpath", false, problems);
+ String providerUri = tools.getPropertyAsString(ruleSetNode, "dna:serviceProviderUri", true, problems);
+ String ruleSetUri = tools.getPropertyAsString(ruleSetNode, "dna:ruleSetUri", true, name, problems);
+ String rules = tools.getPropertyAsString(ruleSetNode, "dna:rules", true, problems);
+ Map<String, Object> properties = tools.loadProperties(ruleSetNode, problems);
+ if (problems.hasProblems()) {
+ // There are problems, so store and save them, and then return null ...
+ try {
+ if (tools.storeProblems(ruleSetNode, problems)) ruleSetNode.save();
+ } catch (RepositoryException e) {
+ this.logger.error(e, RepositoryI18n.errorWritingProblemsOnRuleSet, tools.getReadable(ruleSetNode));
+ }
+ return null;
+ }
+ // There are no problems with this rule set, so make sure that there are no persisted problems anymore ...
+ try {
+ if (tools.removeProblems(ruleSetNode)) ruleSetNode.save();
+ } catch (RepositoryException e) {
+ this.logger.error(e, RepositoryI18n.errorWritingProblemsOnRuleSet, tools.getReadable(ruleSetNode));
+ }
+ return new RuleSet(name, description, classname, classpath, providerUri, ruleSetUri, rules, properties);
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/InvalidSequencerPathExpression.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/InvalidSequencerPathExpression.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/InvalidSequencerPathExpression.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,62 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+
+/**
+ *
+ * @author Randall Hauch
+ */
+public class InvalidSequencerPathExpression extends RuntimeException {
+
+ /**
+ *
+ */
+ public InvalidSequencerPathExpression() {
+ }
+
+ /**
+ * @param message
+ */
+ public InvalidSequencerPathExpression( String message ) {
+ super(message);
+
+ }
+
+ /**
+ * @param cause
+ */
+ public InvalidSequencerPathExpression( Throwable cause ) {
+ super(cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public InvalidSequencerPathExpression( String message, Throwable cause ) {
+ super(message, cause);
+
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/Sequencer.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/Sequencer.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/Sequencer.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,100 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.util.Set;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.component.Component;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.repository.observation.NodeChange;
+import org.jboss.dna.repository.observation.NodeChangeListener;
+import org.jboss.dna.repository.observation.NodeChanges;
+import org.jboss.dna.repository.observation.ObservationService;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.RepositoryNodePath;
+
+/**
+ * The interface for a DNA sequencer, which sequences nodes and their content to extract additional information from the
+ * information.
+ * <p>
+ * Implementations must provide a no-argument constructor.
+ * </p>
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public interface Sequencer extends Component<SequencerConfig> {
+
+ /**
+ * Execute the sequencing operation on the supplied node, which has recently been created or changed. The implementation of
+ * this method is responsible for {@link ExecutionContext#getSessionFactory() getting sessions}, modifying the appropriate
+ * nodes, {@link Session#save() saving} any changes made by this sequencer, and {@link Session#logout() closing} all sessions
+ * (and any other acquired resources), even in the case of {@link ProgressMonitor#isCancelled() cancellation} or exceptions.
+ * <p>
+ * The {@link SequencingService} determines the sequencers that should be executed by monitoring the changes to one or more
+ * workspaces (it is a {@link NodeChangeListener} registered with the {@link ObservationService}). Changes in those
+ * workspaces are aggregated for each transaction, and organized into {@link NodeChanges changes for each node}. The
+ * SequencingService then determines for each {@link NodeChange set of changes to a node} the set of full paths to the
+ * properties that have changed and whether those paths {@link SequencerPathExpression#matcher(String) match} the sequencer's
+ * {@link SequencerConfig#getPathExpressions() path expressions}. Each path expression produces the path to the output node,
+ * and these output paths are accumulated and (with the original node that changed, the node change summary, and other
+ * information) supplied to the sequencer via this method.
+ * <p>
+ * It is possible that a sequencer is configured to apply to multiple properties on a node. So, in cases where multiple
+ * properties are changed on a single node (within a single repository transaction), the sequencer will only be executed once.
+ * Also, in such cases the sequencer's configuration may imply multiple output nodes, so it is left to the sequencer to define
+ * the behavior in such cases.
+ * </p>
+ * <p>
+ * This operation should report progress to the supplied {@link ProgressMonitor}. At the beginning of the operation, call
+ * {@link ProgressMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, Object...)} with a meaningful message describing
+ * the operation and a total for the amount of work that will be done by this sequencer. Then perform the sequencing work,
+ * periodically reporting work by specifying the {@link ProgressMonitor#worked(double) amount of work} that has was just
+ * completed or by {@link ProgressMonitor#createSubtask(double) creating a subtask} and reporting work against that subtask
+ * monitor.
+ * </p>
+ * <p>
+ * The implementation should also periodically check whether the operation has been
+ * {@link ProgressMonitor#isCancelled() cancelled}. If this method returns true, the implementation should abort all work as
+ * soon as possible and close any resources that were acquired or opened.
+ * </p>
+ * <p>
+ * Finally, the implementation should call {@link ProgressMonitor#done()} when the operation has finished.
+ * </p>
+ * @param input the node that has recently been created or changed; never null
+ * @param sequencedPropertyName the name of the property that caused this sequencer to be executed; never null and never empty
+ * @param changes the immutable summary of changes that occurred on the <code>input</code> node within the transaction;
+ * never null
+ * @param outputPaths the paths to the nodes where the sequencing content should be placed; never null and never empty, but
+ * the set may contain paths for non-existant nodes or may reference the <code>input</code> node
+ * @param context the context in which this sequencer is executing; never null
+ * @param progress the progress monitor that should be kept updated with the sequencer's progress and that should be
+ * frequently consulted as to whether this operation has been {@link ProgressMonitor#isCancelled() cancelled}.
+ * @throws RepositoryException if there is a problem while working with the repository
+ * @throws SequencerException if there is an error in this sequencer
+ */
+ void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, ExecutionContext context, ProgressMonitor progress )
+ throws RepositoryException, SequencerException;
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerConfig.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerConfig.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerConfig.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.component.ComponentConfig;
+
+/**
+ * @author Randall Hauch
+ */
+@Immutable
+public class SequencerConfig extends ComponentConfig {
+
+ private final Set<SequencerPathExpression> pathExpressions;
+
+ public SequencerConfig( String name, String description, String classname, String[] classpath, String... pathExpressions ) {
+ this(name, description, System.currentTimeMillis(), classname, classpath, pathExpressions);
+ }
+
+ public SequencerConfig( String name, String description, long timestamp, String classname, String[] classpath, String... pathExpressions ) {
+ super(name, description, timestamp, classname, classpath);
+ this.pathExpressions = buildPathExpressionSet(pathExpressions);
+ }
+
+ /* package */static Set<SequencerPathExpression> buildPathExpressionSet( String... pathExpressions ) {
+ Set<SequencerPathExpression> result = null;
+ if (pathExpressions != null) {
+ result = new LinkedHashSet<SequencerPathExpression>();
+ for (String pathExpression : pathExpressions) {
+ if (pathExpression == null) continue;
+ pathExpression = pathExpression.trim();
+ if (pathExpression.length() == 0) continue;
+ result.add(SequencerPathExpression.compile(pathExpression));
+ }
+ result = Collections.unmodifiableSet(result);
+ } else {
+ result = Collections.emptySet(); // already immutable
+ }
+ return result;
+ }
+
+ public Collection<SequencerPathExpression> getPathExpressions() {
+ return Collections.unmodifiableSet(this.pathExpressions);
+ }
+
+ public boolean hasChanged( SequencerConfig that ) {
+ if (super.hasChanged(that)) return true;
+ if (!this.getPathExpressions().equals(that.getPathExpressions())) return true;
+ return false;
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerException.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerException.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerException.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+/**
+ * @author Randall Hauch
+ */
+public class SequencerException extends RuntimeException {
+
+ /**
+ */
+ public SequencerException() {
+ }
+
+ /**
+ * @param message
+ */
+ public SequencerException( String message ) {
+ super(message);
+ }
+
+ /**
+ * @param cause
+ */
+ public SequencerException( Throwable cause ) {
+ super(cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public SequencerException( String message, Throwable cause ) {
+ super(message, cause);
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerOutputMap.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerOutputMap.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerOutputMap.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,316 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import net.jcip.annotations.Immutable;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.jcr.Path;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.spi.sequencers.SequencerOutput;
+
+/**
+ * A basic {@link SequencerOutput} that records all information in-memory and which organizes the properties by
+ * {@link Path node paths} and provides access to the nodes in a natural path-order.
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class SequencerOutputMap implements SequencerOutput, Iterable<SequencerOutputMap.Entry> {
+
+ private static final String JCR_PRIMARY_TYPE_PROPERTY_NAME = "jcr:primaryType";
+ private static final String JCR_NAME_PROPERTY_NAME = "jcr:name";
+
+ private final Map<Path, List<PropertyValue>> data;
+ private boolean valuesSorted = true;
+
+ public SequencerOutputMap() {
+ this.data = new HashMap<Path, List<PropertyValue>>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setProperty( String nodePath, String property, Object... values ) {
+ property = property.trim();
+ if (JCR_NAME_PROPERTY_NAME.equals(property)) return; // ignore the "jcr:name" property
+ nodePath = nodePath.trim();
+ if (nodePath.endsWith("/")) nodePath = nodePath.replaceFirst("/+$", "");
+
+ // Find or create the entry for this node ...
+ Path path = new Path(nodePath);
+ List<PropertyValue> properties = this.data.get(path);
+ if (properties == null) {
+ if (values == null || values.length == 0) return; // do nothing
+ properties = new ArrayList<PropertyValue>();
+ this.data.put(path, properties);
+ }
+ if (values == null || values.length == 0) {
+ properties.remove(new PropertyValue(property, null));
+ } else {
+ Object propValue = values.length == 1 ? values[0] : values;
+ PropertyValue value = new PropertyValue(property, propValue);
+ properties.add(value);
+ valuesSorted = false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setReference( String nodePath, String property, String... paths ) {
+ if (paths == null || paths.length == 0) {
+ setProperty(nodePath, property, (Object[])null);
+ } else if (paths.length == 1) {
+ setProperty(nodePath, property, new Path(paths[0]));
+ } else {
+ Path[] pathsArray = new Path[paths.length];
+ for (int i = 0; i != paths.length; ++i) {
+ pathsArray[i] = new Path(paths[i]);
+ }
+ setProperty(nodePath, property, (Object[])pathsArray);
+ }
+ }
+
+ /**
+ * Return the number of node entries in this map.
+ * @return the number of entries
+ */
+ public int size() {
+ return this.data.size();
+ }
+
+ /**
+ * Return whether there are no entries
+ * @return true if this container is empty, or false otherwise
+ */
+ public boolean isEmpty() {
+ return this.data.isEmpty();
+ }
+
+ protected List<PropertyValue> removeProperties( Path nodePath ) {
+ return this.data.remove(nodePath);
+ }
+
+ /**
+ * Get the properties for the node given by the supplied path.
+ * @param nodePath the path to the node
+ * @return the property values, or null if there are none
+ */
+ protected List<PropertyValue> getProperties( Path nodePath ) {
+ return data.get(nodePath);
+ }
+
+ /**
+ * Return the entries in this output in an order with shorter paths first.
+ * <p>
+ * {@inheritDoc}
+ */
+ public Iterator<Entry> iterator() {
+ LinkedList<Path> paths = new LinkedList<Path>(data.keySet());
+ Collections.sort(paths);
+ sortValues();
+ return new EntryIterator(paths.iterator());
+ }
+
+ protected void sortValues() {
+ if (!valuesSorted) {
+ for (List<PropertyValue> values : this.data.values()) {
+ if (values.size() > 1) Collections.sort(values);
+ }
+ valuesSorted = true;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return StringUtil.readableString(this.data);
+ }
+
+ /**
+ * A property name and value pair. PropertyValue instances have a natural order where the <code>jcr:primaryType</code> is
+ * first, followed by all other properties in ascending lexicographical order according to the {@link #getName() name}.
+ * @author Randall Hauch
+ */
+ @Immutable
+ public class PropertyValue implements Comparable<PropertyValue> {
+
+ private final String name;
+ private final Object value;
+
+ protected PropertyValue( String propertyName, Object value ) {
+ this.name = propertyName;
+ this.value = value;
+ }
+
+ /**
+ * Get the property name.
+ * @return the property name; never null
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Get the property value, which is either a single value or an array of values.
+ * @return the property value
+ */
+ public Object getValue() {
+ return this.value;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo( PropertyValue that ) {
+ if (this == that) return 0;
+ if (this.name.equals(JCR_PRIMARY_TYPE_PROPERTY_NAME)) return -1;
+ if (that.name.equals(JCR_PRIMARY_TYPE_PROPERTY_NAME)) return 1;
+ return this.name.compareTo(that.name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return this.name.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PropertyValue) {
+ PropertyValue that = (PropertyValue)obj;
+ if (!this.getName().equals(that.getName())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "[" + this.name + "=" + StringUtil.readableString(value) + "]";
+ }
+ }
+
+ /**
+ * An entry in a SequencerOutputMap, which contains the path of the node and the {@link #getPropertyValues() property values}
+ * on the node.
+ * @author Randall Hauch
+ */
+ @Immutable
+ public class Entry {
+
+ private final Path path;
+ private final String primaryType;
+ private final List<PropertyValue> properties;
+
+ protected Entry( Path path, List<PropertyValue> properties ) {
+ assert path != null;
+ assert properties != null;
+ this.path = path;
+ this.properties = properties;
+ if (this.properties.size() > 0 && this.properties.get(0).getName().equals("jcr:primaryType")) {
+ PropertyValue primaryTypeProperty = this.properties.remove(0);
+ this.primaryType = primaryTypeProperty.getValue().toString();
+ } else {
+ this.primaryType = null;
+ }
+ }
+
+ /**
+ * @return path
+ */
+ public Path getPath() {
+ return this.path;
+ }
+
+ /**
+ * Get the primary type specified for this node, or null if the type was not specified
+ * @return the primary type, or null
+ */
+ public String getPrimaryTypeValue() {
+ return this.primaryType;
+ }
+
+ /**
+ * Get the property values, which may be empty
+ * @return value
+ */
+ public List<PropertyValue> getPropertyValues() {
+ return getProperties(path);
+ }
+ }
+
+ protected class EntryIterator implements Iterator<Entry> {
+
+ private Path last;
+ private final Iterator<Path> iter;
+
+ protected EntryIterator( Iterator<Path> iter ) {
+ this.iter = iter;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Entry next() {
+ this.last = iter.next();
+ return new Entry(last, getProperties(last));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void remove() {
+ if (last == null) throw new IllegalStateException();
+ try {
+ removeProperties(last);
+ } finally {
+ last = null;
+ }
+ }
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerPathExpression.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerPathExpression.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerPathExpression.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,476 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.repository.RepositoryI18n;
+
+/**
+ * An expression that defines a selection of some change in the repository that signals a sequencing operation should be run, and
+ * the location where the sequencing output should be placed. Sequencer path expressions are used within the
+ * {@link SequencerConfig sequencer configurations} and used to determine whether information in the repository needs to be
+ * sequenced.
+ * <p>
+ * A simple example is the following:
+ *
+ * <pre>
+ * /a/b/c@title => /d/e/f
+ * </pre>
+ *
+ * which means that a sequencer (that uses this expression in its configuration) should be run any time there is a new or modified
+ * <code>title</code> property on the <code>/a/b/c</code> node, and that the output of the sequencing should be placed at
+ * <code>/d/e/f</code>.
+ * </p>
+ * @author Randall Hauch
+ */
+@Immutable
+public class SequencerPathExpression implements Serializable {
+
+ /**
+ * The pattern used to break the initial input string into the two major parts, the selection and output expressions. Group 1
+ * contains the selection expression, and group 2 contains the output expression.
+ */
+ private static final Pattern TWO_PART_PATTERN = Pattern.compile("((?:[^=]|=(?!>))+)(?:=>(.+))?");
+
+ protected static final String DEFAULT_OUTPUT_EXPRESSION = ".";
+
+ private static final String REPLACEMENT_VARIABLE_PATTERN_STRING = "(?<!\\\\)\\$(\\d+)"; // (?<!\\)\$(\d+)
+ private static final Pattern REPLACEMENT_VARIABLE_PATTERN = Pattern.compile(REPLACEMENT_VARIABLE_PATTERN_STRING);
+
+ private static final String PARENT_PATTERN_STRING = "[^/]+/\\.\\./"; // [^/]+/\.\./
+ private static final Pattern PARENT_PATTERN = Pattern.compile(PARENT_PATTERN_STRING);
+
+ private static final String SEQUENCE_PATTERN_STRING = "\\[(\\d+(?:,\\d+)*)\\]"; // \[(\d+(,\d+)*)\]
+ private static final Pattern SEQUENCE_PATTERN = Pattern.compile(SEQUENCE_PATTERN_STRING);
+
+ /**
+ * Regular expression used to find unusable XPath predicates within an expression. This pattern results in unusable predicates
+ * in group 1. Note that some predicates may be valid at the end but not valid elsewhere.
+ * <p>
+ * Currently, only index-like predicates (including sequences) are allowed everywhere. Predicates with paths and properties
+ * are allowed only as the last predicate. Predicates with any operators are unused.
+ * </p>
+ * <p>
+ * Nested predicates are not currently allowed.
+ * </p>
+ */
+ // \[(?:(?:\d+(?:,\d+)*)|\*)\]|(?:\[[^\]\+\-\*=\!><'"\s]+\])$|(\[[^\]]+\])
+ private static final String UNUSABLE_PREDICATE_PATTERN_STRING = "\\[(?:(?:\\d+(?:,\\d+)*)|\\*)\\]|(?:\\[[^\\]\\+\\-\\*=\\!><'\"\\s]+\\])$|(\\[[^\\]]+\\])";
+ private static final Pattern UNUSABLE_PREDICATE_PATTERN = Pattern.compile(UNUSABLE_PREDICATE_PATTERN_STRING);
+
+ /**
+ * Regular expression used to find all XPath predicates except index and sequence patterns. This pattern results in the
+ * predicates to be removed in group 1.
+ */
+ // \[(?:(?:\d+(?:,\d+)*)|\*)\]|(\[[^\]]+\])
+ private static final String NON_INDEX_PREDICATE_PATTERN_STRING = "\\[(?:(?:\\d+(?:,\\d+)*)|\\*)\\]|(\\[[^\\]]+\\])";
+ private static final Pattern NON_INDEX_PREDICATE_PATTERN = Pattern.compile(NON_INDEX_PREDICATE_PATTERN_STRING);
+
+ /**
+ * Compile the supplied expression and return the resulting SequencerPathExpression2 instance.
+ * @param expression the expression
+ * @return the path expression; never null
+ * @throws IllegalArgumentException if the expression is null
+ * @throws InvalidSequencerPathExpression if the expression is blank or is not a valid expression
+ */
+ public static final SequencerPathExpression compile( String expression ) throws InvalidSequencerPathExpression {
+ ArgCheck.isNotNull(expression, "sequencer path expression");
+ expression = expression.trim();
+ if (expression.length() == 0) {
+ throw new InvalidSequencerPathExpression(RepositoryI18n.pathExpressionMayNotBeBlank.text());
+ }
+ java.util.regex.Matcher matcher = TWO_PART_PATTERN.matcher(expression);
+ if (!matcher.matches()) {
+ throw new InvalidSequencerPathExpression(RepositoryI18n.pathExpressionIsInvalid.text(expression));
+ }
+ String selectExpression = matcher.group(1);
+ String outputExpression = matcher.group(2);
+ return new SequencerPathExpression(selectExpression, outputExpression);
+ }
+
+ private final String selectExpression;
+ private final String outputExpression;
+ private final Pattern matchPattern;
+ private final Pattern selectPattern;
+ private final int hc;
+
+ protected SequencerPathExpression( String selectExpression, String outputExpression ) throws InvalidSequencerPathExpression {
+ ArgCheck.isNotNull(selectExpression, "select expression");
+ this.selectExpression = selectExpression.trim();
+ this.outputExpression = outputExpression != null ? outputExpression.trim() : DEFAULT_OUTPUT_EXPRESSION;
+ this.hc = HashCode.compute(this.selectExpression, this.outputExpression);
+
+ // Build the match pattern, which determines whether a path matches the condition ...
+ String matchString = this.selectExpression;
+ try {
+ matchString = removeUnusedPredicates(matchString);
+ matchString = replaceXPathPatterns(matchString);
+ this.matchPattern = Pattern.compile(matchString, Pattern.CASE_INSENSITIVE);
+ } catch (PatternSyntaxException e) {
+ String msg = RepositoryI18n.pathExpressionHasInvalidMatch.text(matchString, this.selectExpression, this.outputExpression);
+ throw new InvalidSequencerPathExpression(msg, e);
+ }
+ // Build the select pattern, which determines the path that will be selected ...
+ String selectString = this.selectExpression.trim();
+ try {
+ selectString = removeAllPredicatesExceptIndexes(selectString);
+ selectString = replaceXPathPatterns(selectString);
+ selectString = "(" + selectString + ").*"; // group 1 will have selected path ...
+ this.selectPattern = Pattern.compile(selectString, Pattern.CASE_INSENSITIVE);
+ } catch (PatternSyntaxException e) {
+ String msg = RepositoryI18n.pathExpressionHasInvalidSelect.text(selectString, this.selectExpression, this.outputExpression);
+ throw new InvalidSequencerPathExpression(msg, e);
+ }
+ }
+
+ /**
+ * Replace certain XPath patterns that are not used or understood.
+ * @param expression the input regular expressions string; may not be null
+ * @return the regular expression with all unused XPath patterns removed; never null
+ */
+ protected String removeUnusedPredicates( String expression ) {
+ assert expression != null;
+ java.util.regex.Matcher matcher = UNUSABLE_PREDICATE_PATTERN.matcher(expression);
+ StringBuffer sb = new StringBuffer();
+ if (matcher.find()) {
+ do {
+ // Remove those predicates that show up in group 1 ...
+ String predicateStr = matcher.group(0);
+ String unusablePredicateStr = matcher.group(1);
+ if (unusablePredicateStr != null) {
+ predicateStr = "";
+ }
+ matcher.appendReplacement(sb, predicateStr);
+ } while (matcher.find());
+ matcher.appendTail(sb);
+ expression = sb.toString();
+ }
+ return expression;
+ }
+
+ /**
+ * Remove all XPath predicates from the supplied regular expression string.
+ * @param expression the input regular expressions string; may not be null
+ * @return the regular expression with all XPath predicates removed; never null
+ */
+ protected String removeAllPredicatesExceptIndexes( String expression ) {
+ assert expression != null;
+ java.util.regex.Matcher matcher = NON_INDEX_PREDICATE_PATTERN.matcher(expression);
+ StringBuffer sb = new StringBuffer();
+ if (matcher.find()) {
+ do {
+ // Remove those predicates that show up in group 1 ...
+ String predicateStr = matcher.group(0);
+ String unusablePredicateStr = matcher.group(1);
+ if (unusablePredicateStr != null) {
+ predicateStr = "";
+ }
+ matcher.appendReplacement(sb, predicateStr);
+ } while (matcher.find());
+ matcher.appendTail(sb);
+ expression = sb.toString();
+ }
+ return expression;
+ }
+
+ /**
+ * Replace certain XPath patterns, including some predicates, with substrings that are compatible with regular expressions.
+ * @param expression the input regular expressions string; may not be null
+ * @return the regular expression with XPath patterns replaced with regular expression fragments; never null
+ */
+ protected String replaceXPathPatterns( String expression ) {
+ assert expression != null;
+ // replace 2 or more sequential '|' characters in an OR expression
+ expression = expression.replaceAll("[\\|]{2,}", "|");
+ // if there is an empty expression in an OR expression, make the whole segment optional ...
+ // (e.g., "/a/b/(c|)/d" => "a/b(/(c))?/d"
+ expression = expression.replaceAll("/(\\([^|]+)(\\|){2,}([^)]+\\))", "(/$1$2$3)?");
+ expression = expression.replaceAll("/\\(\\|+([^)]+)\\)", "(/($1))?");
+ expression = expression.replaceAll("/\\((([^|]+)(\\|[^|]+)*)\\|+\\)", "(/($1))?");
+
+ // // Allow any path (that doesn't contain an explicit counter) to contain a counter,
+ // // done by replacing any '/' or '|' that isn't preceded by ']' or '*' or '/' or '(' with '(\[\d+\])?/'...
+ // input = input.replaceAll("(?<=[^\\]\\*/(])([/|])", "(?:\\\\[\\\\d+\\\\])?$1");
+
+ // Does the path contain any '[]' or '[*]' or '[0]' or '[n]' (where n is any positive integers)...
+ // '[*]/' => '(\[\d+\])?/'
+ expression = expression.replaceAll("\\[\\]", "(?:\\\\[\\\\d+\\\\])?"); // index is optional
+ // '[]/' => '(\[\d+\])?/'
+ expression = expression.replaceAll("\\[[*]\\]", "(?:\\\\[\\\\d+\\\\])?"); // index is optional
+ // '[0]/' => '(\[0\])?/'
+ expression = expression.replaceAll("\\[0\\]", "(?:\\\\[0\\\\])?"); // index is optional
+ // '[n]/' => '\[n\]/'
+ expression = expression.replaceAll("\\[([1-9]\\d*)\\]", "\\\\[$1\\\\]"); // index is required
+
+ // Change any other end predicates to not be wrapped by braces but to begin with a slash ...
+ // ...'[x]' => ...'/x'
+ expression = expression.replaceAll("(?<!\\\\)\\[([^\\]]*)\\]$", "/$1");
+
+ // Replace all '[n,m,o,p]' type sequences with '[(n|m|o|p)]'
+ java.util.regex.Matcher matcher = SEQUENCE_PATTERN.matcher(expression);
+ StringBuffer sb = new StringBuffer();
+ boolean result = matcher.find();
+ if (result) {
+ do {
+ String sequenceStr = matcher.group(1);
+ boolean optional = false;
+ if (sequenceStr.startsWith("0,")) {
+ sequenceStr = sequenceStr.replaceFirst("^0,", "");
+ optional = true;
+ }
+ if (sequenceStr.endsWith(",0")) {
+ sequenceStr = sequenceStr.replaceFirst(",0$", "");
+ optional = true;
+ }
+ if (sequenceStr.contains(",0,")) {
+ sequenceStr = sequenceStr.replaceAll(",0,", ",");
+ optional = true;
+ }
+ sequenceStr = sequenceStr.replaceAll(",", "|");
+ String replacement = "\\\\[(?:" + sequenceStr + ")\\\\]";
+ if (optional) {
+ replacement = "(?:" + replacement + ")?";
+ }
+ matcher.appendReplacement(sb, replacement);
+ result = matcher.find();
+ } while (result);
+ matcher.appendTail(sb);
+ expression = sb.toString();
+ }
+
+ // Order is important here
+ expression = expression.replaceAll("[*]", "[^/]*");
+ expression = expression.replaceAll("[/]{2,}", "(/[^/]*)*/");
+ return expression;
+ }
+
+ /**
+ * @return selectExpression
+ */
+ public String getSelectExpression() {
+ return this.selectExpression;
+ }
+
+ /**
+ * @return outputExpression
+ */
+ public String getOutputExpression() {
+ return this.outputExpression;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return this.hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof SequencerPathExpression) {
+ SequencerPathExpression that = (SequencerPathExpression)obj;
+ if (!this.selectExpression.equalsIgnoreCase(that.selectExpression)) return false;
+ if (!this.outputExpression.equalsIgnoreCase(that.outputExpression)) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return this.selectExpression + "=>" + this.outputExpression;
+ }
+
+ /**
+ * @param absolutePath
+ * @return the matcher
+ */
+ public Matcher matcher( String absolutePath ) {
+ // Determine if the input path match the select expression ...
+ String originalAbsolutePath = absolutePath;
+ // if (!absolutePath.endsWith("/")) absolutePath = absolutePath + "/";
+ // Remove all trailing '/' ...
+ absolutePath = absolutePath.replaceAll("/+$", "");
+
+ // See if the supplied absolute path matches the pattern ...
+ final java.util.regex.Matcher matcher = this.matchPattern.matcher(absolutePath);
+ if (!matcher.matches()) {
+ // No match, so return immediately ...
+ return new Matcher(originalAbsolutePath, null, null);
+ }
+ Map<Integer, String> replacements = new HashMap<Integer, String>();
+ for (int i = 0, count = matcher.groupCount(); i <= count; ++i) {
+ replacements.put(i, matcher.group(i));
+ }
+
+ // The absolute path does match the pattern, so use the select pattern and try to grab the selected path ...
+ final java.util.regex.Matcher selectMatcher = this.selectPattern.matcher(absolutePath);
+ if (!selectMatcher.matches()) {
+ // Nothing can be selected, so return immediately ...
+ return new Matcher(originalAbsolutePath, null, null);
+ }
+ // Grab the selected path ...
+ String selectedPath = selectMatcher.group(1);
+
+ // Remove the trailing '/@property' ...
+ selectedPath = selectedPath.replaceAll("/@[^/\\[\\]]+$", "");
+
+ // Find the output path using the groups from the match pattern ...
+ String outputPath = this.outputExpression;
+ if (!DEFAULT_OUTPUT_EXPRESSION.equals(outputPath)) {
+ java.util.regex.Matcher replacementMatcher = REPLACEMENT_VARIABLE_PATTERN.matcher(outputPath);
+ StringBuffer sb = new StringBuffer();
+ if (replacementMatcher.find()) {
+ do {
+ String variable = replacementMatcher.group(1);
+ String replacement = replacements.get(Integer.valueOf(variable));
+ if (replacement == null) replacement = replacementMatcher.group(0);
+ replacementMatcher.appendReplacement(sb, replacement);
+ } while (replacementMatcher.find());
+ replacementMatcher.appendTail(sb);
+ outputPath = sb.toString();
+ }
+ // Make sure there is a trailing '/' ...
+ if (!outputPath.endsWith("/")) outputPath = outputPath + "/";
+
+ // Replace all references to "/./" with "/" ...
+ outputPath = outputPath.replaceAll("/\\./", "/");
+
+ // Remove any path segment followed by a parent reference ...
+ java.util.regex.Matcher parentMatcher = PARENT_PATTERN.matcher(outputPath);
+ while (parentMatcher.find()) {
+ outputPath = parentMatcher.replaceAll("");
+ // Make sure there is a trailing '/' ...
+ if (!outputPath.endsWith("/")) outputPath = outputPath + "/";
+ parentMatcher = PARENT_PATTERN.matcher(outputPath);
+ }
+
+ // Remove all multiple occurrences of '/' ...
+ outputPath = outputPath.replaceAll("/{2,}", "/");
+
+ // Remove the trailing '/@property' ...
+ outputPath = outputPath.replaceAll("/@[^/\\[\\]]+$", "");
+
+ // Remove a trailing '/' ...
+ outputPath = outputPath.replaceAll("/$", "");
+
+ // If the output path is blank, then use the default output expression ...
+ if (outputPath.length() == 0) outputPath = DEFAULT_OUTPUT_EXPRESSION;
+
+ }
+ if (DEFAULT_OUTPUT_EXPRESSION.equals(outputPath)) {
+ // The output path is the default expression, so use the selected path ...
+ outputPath = selectedPath;
+ }
+
+ return new Matcher(originalAbsolutePath, selectedPath, outputPath);
+ }
+
+ @Immutable
+ public static class Matcher {
+
+ private final String inputPath;
+ private final String selectedPath;
+ private final String outputPath;
+ private final int hc;
+
+ protected Matcher( String inputPath, String selectedPath, String outputPath ) {
+ this.inputPath = inputPath;
+ this.selectedPath = selectedPath;
+ this.outputPath = outputPath;
+ this.hc = HashCode.compute(this.inputPath, this.selectedPath, this.outputPath);
+ }
+
+ public boolean matches() {
+ return this.selectedPath != null && this.outputPath != null;
+ }
+
+ /**
+ * @return inputPath
+ */
+ public String getInputPath() {
+ return this.inputPath;
+ }
+
+ /**
+ * @return selectPattern
+ */
+ public String getSelectedPath() {
+ return this.selectedPath;
+ }
+
+ /**
+ * @return outputPath
+ */
+ public String getOutputPath() {
+ return this.outputPath;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return this.hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof SequencerPathExpression.Matcher) {
+ SequencerPathExpression.Matcher that = (SequencerPathExpression.Matcher)obj;
+ if (!this.inputPath.equalsIgnoreCase(that.inputPath)) return false;
+ if (!this.selectedPath.equalsIgnoreCase(that.selectedPath)) return false;
+ if (!this.outputPath.equalsIgnoreCase(that.outputPath)) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return this.selectedPath + " => " + this.outputPath;
+ }
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,710 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import net.jcip.annotations.Immutable;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.component.ComponentLibrary;
+import org.jboss.dna.common.component.StandardClassLoaderFactory;
+import org.jboss.dna.common.monitor.LoggingProgressMonitor;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.SimpleProgressMonitor;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.repository.observation.NodeChange;
+import org.jboss.dna.repository.observation.NodeChangeListener;
+import org.jboss.dna.repository.observation.NodeChanges;
+import org.jboss.dna.repository.services.AbstractServiceAdministrator;
+import org.jboss.dna.repository.services.AdministeredService;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.JcrTools;
+import org.jboss.dna.repository.util.RepositoryNodePath;
+import org.jboss.dna.repository.util.SessionFactory;
+
+/**
+ * A sequencing system is used to monitor changes in the content of {@link Repository JCR repositories} and to sequence the
+ * content to extract or to generate structured information.
+ * @author Randall Hauch
+ */
+public class SequencingService implements AdministeredService, NodeChangeListener {
+
+ /**
+ * Interface used to select the set of {@link Sequencer} instances that should be run.
+ * @author Randall Hauch
+ */
+ public static interface Selector {
+
+ /**
+ * Select the sequencers that should be used to sequence the supplied node.
+ * @param sequencers the list of all sequencers available at the moment; never null
+ * @param node the node to be sequenced; never null
+ * @param nodeChange the set of node changes; never null
+ * @return the list of sequencers that should be used; may not be null
+ */
+ List<Sequencer> selectSequencers( List<Sequencer> sequencers, Node node, NodeChange nodeChange );
+ }
+
+ /**
+ * The default {@link Selector} implementation that selects every sequencer every time it's called, regardless of the node (or
+ * logger) supplied.
+ * @author Randall Hauch
+ */
+ protected static class DefaultSelector implements Selector {
+
+ public List<Sequencer> selectSequencers( List<Sequencer> sequencers, Node node, NodeChange nodeChange ) {
+ return sequencers;
+ }
+ }
+
+ /**
+ * Interface used to determine whether a {@link NodeChange} should be processed.
+ * @author Randall Hauch
+ */
+ public static interface NodeFilter {
+
+ /**
+ * Determine whether the node represented by the supplied change should be submitted for sequencing.
+ * @param nodeChange the node change event
+ * @return true if the node should be submitted for sequencing, or false if the change should be ignored
+ */
+ boolean accept( NodeChange nodeChange );
+ }
+
+ /**
+ * The default filter implementation, which accepts only new nodes or nodes that have new or changed properties.
+ * @author Randall Hauch
+ */
+ protected static class DefaultNodeFilter implements NodeFilter {
+
+ public boolean accept( NodeChange nodeChange ) {
+ // Only care about new nodes or nodes that have new/changed properies ...
+ return nodeChange.includesEventTypes(Event.NODE_ADDED, Event.PROPERTY_ADDED, Event.PROPERTY_CHANGED);
+ }
+ }
+
+ /**
+ * The default {@link Selector} that considers every {@link Sequencer} to be used for every node.
+ * @see SequencingService#setSequencerSelector(org.jboss.dna.repository.sequencers.SequencingService.Selector)
+ */
+ public static final Selector DEFAULT_SEQUENCER_SELECTOR = new DefaultSelector();
+ /**
+ * The default {@link NodeFilter} that accepts new nodes or nodes that have new/changed properties.
+ * @see SequencingService#setSequencerSelector(org.jboss.dna.repository.sequencers.SequencingService.Selector)
+ */
+ public static final NodeFilter DEFAULT_NODE_FILTER = new DefaultNodeFilter();
+
+ /**
+ * Class loader factory instance that always returns the
+ * {@link Thread#getContextClassLoader() current thread's context class loader} (if not null) or component library's class
+ * loader.
+ */
+ protected static final ClassLoaderFactory DEFAULT_CLASSLOADER_FACTORY = new StandardClassLoaderFactory(SequencingService.class.getClassLoader());
+
+ /**
+ * The administrative component for this service.
+ * @author Randall Hauch
+ */
+ protected class Administrator extends AbstractServiceAdministrator {
+
+ protected Administrator() {
+ super(State.PAUSED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String serviceName() {
+ return RepositoryI18n.sequencingServiceName.text();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doStart( State fromState ) {
+ super.doStart(fromState);
+ startService();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doShutdown( State fromState ) {
+ super.doShutdown(fromState);
+ shutdownService();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
+ return doAwaitTermination(timeout, unit);
+ }
+
+ }
+
+ private ExecutionContext executionContext;
+ private ComponentLibrary<Sequencer, SequencerConfig> sequencerLibrary = new ComponentLibrary<Sequencer, SequencerConfig>();
+ private Selector sequencerSelector = DEFAULT_SEQUENCER_SELECTOR;
+ private NodeFilter nodeFilter = DEFAULT_NODE_FILTER;
+ private ExecutorService executorService;
+ private Logger logger = Logger.getLogger(this.getClass());
+ private final Statistics statistics = new Statistics();
+ private final Administrator administrator = new Administrator();
+
+ /**
+ * Create a new sequencing system, configured with no sequencers and not monitoring any workspaces. Upon construction, the
+ * system is {@link ServiceAdministrator#isPaused() paused} and must be configured and then
+ * {@link ServiceAdministrator#start() started}.
+ */
+ public SequencingService() {
+ this.sequencerLibrary.setClassLoaderFactory(DEFAULT_CLASSLOADER_FACTORY);
+ }
+
+ /**
+ * Return the administrative component for this service.
+ * @return the administrative component; never null
+ */
+ public ServiceAdministrator getAdministrator() {
+ return this.administrator;
+ }
+
+ /**
+ * Get the statistics for this system.
+ * @return statistics
+ */
+ public Statistics getStatistics() {
+ return this.statistics;
+ }
+
+ /**
+ * @return sequencerLibrary
+ */
+ protected ComponentLibrary<Sequencer, SequencerConfig> getSequencerLibrary() {
+ return this.sequencerLibrary;
+ }
+
+ /**
+ * Get the class loader factory that should be used to load sequencers. By default, this service uses a factory that will
+ * return either the {@link Thread#getContextClassLoader() current thread's context class loader} (if not null) or the class
+ * loader that loaded this class.
+ * @return the class loader factory; never null
+ * @see #setClassLoaderFactory(ClassLoaderFactory)
+ */
+ public ClassLoaderFactory getClassLoaderFactory() {
+ return this.sequencerLibrary.getClassLoaderFactory();
+ }
+
+ /**
+ * Set the Maven Repository that should be used to load the sequencer classes. By default, this service uses a class loader
+ * factory that will return either the {@link Thread#getContextClassLoader() current thread's context class loader} (if not
+ * null) or the class loader that loaded this class.
+ * @param classLoaderFactory the class loader factory reference, or null if the default class loader factory should be used.
+ * @see #getClassLoaderFactory()
+ */
+ public void setClassLoaderFactory( ClassLoaderFactory classLoaderFactory ) {
+ this.sequencerLibrary.setClassLoaderFactory(classLoaderFactory != null ? classLoaderFactory : DEFAULT_CLASSLOADER_FACTORY);
+ }
+
+ /**
+ * Add the configuration for a sequencer, or update any existing one that represents the
+ * {@link SequencerConfig#equals(Object) same configuration}
+ * @param config the new configuration
+ * @return true if the sequencer was added, or false if there already was an existing and
+ * {@link SequencerConfig#hasChanged(SequencerConfig) unchanged} sequencer configuration
+ * @throws IllegalArgumentException if <code>config</code> is null
+ * @see #updateSequencer(SequencerConfig)
+ * @see #removeSequencer(SequencerConfig)
+ */
+ public boolean addSequencer( SequencerConfig config ) {
+ return this.sequencerLibrary.add(config);
+ }
+
+ /**
+ * Update the configuration for a sequencer, or add it if there is no
+ * {@link SequencerConfig#equals(Object) matching configuration}.
+ * @param config the updated (or new) configuration
+ * @return true if the sequencer was updated, or false if there already was an existing and
+ * {@link SequencerConfig#hasChanged(SequencerConfig) unchanged} sequencer configuration
+ * @throws IllegalArgumentException if <code>config</code> is null
+ * @see #addSequencer(SequencerConfig)
+ * @see #removeSequencer(SequencerConfig)
+ */
+ public boolean updateSequencer( SequencerConfig config ) {
+ return this.sequencerLibrary.update(config);
+ }
+
+ /**
+ * Remove the configuration for a sequencer.
+ * @param config the configuration to be removed
+ * @return true if the sequencer was removed, or false if there was no existing sequencer
+ * @throws IllegalArgumentException if <code>config</code> is null
+ * @see #addSequencer(SequencerConfig)
+ * @see #updateSequencer(SequencerConfig)
+ */
+ public boolean removeSequencer( SequencerConfig config ) {
+ return this.sequencerLibrary.remove(config);
+ }
+
+ /**
+ * Get the logger for this system
+ * @return the logger
+ */
+ public Logger getLogger() {
+ return this.logger;
+ }
+
+ /**
+ * Set the logger for this system.
+ * @param logger the logger, or null if the standard logging should be used
+ */
+ public void setLogger( Logger logger ) {
+ this.logger = logger != null ? logger : Logger.getLogger(this.getClass());
+ }
+
+ /**
+ * @return executionContext
+ */
+ public ExecutionContext getExecutionContext() {
+ return this.executionContext;
+ }
+
+ /**
+ * @param executionContext Sets executionContext to the specified value.
+ */
+ public void setExecutionContext( ExecutionContext executionContext ) {
+ ArgCheck.isNotNull(executionContext, "execution context");
+ if (this.getAdministrator().isStarted()) {
+ throw new IllegalStateException(RepositoryI18n.unableToChangeExecutionContextWhileRunning.text());
+ }
+ this.executionContext = executionContext;
+ }
+
+ /**
+ * Get the executor service used to run the sequencers.
+ * @return the executor service
+ * @see #setExecutorService(ExecutorService)
+ */
+ public ExecutorService getExecutorService() {
+ return this.executorService;
+ }
+
+ /**
+ * Set the executor service that should be used by this system. By default, the system is set up with a
+ * {@link Executors#newSingleThreadExecutor() executor that uses a single thread}.
+ * @param executorService the executor service
+ * @see #getExecutorService()
+ * @see Executors#newCachedThreadPool()
+ * @see Executors#newCachedThreadPool(java.util.concurrent.ThreadFactory)
+ * @see Executors#newFixedThreadPool(int)
+ * @see Executors#newFixedThreadPool(int, java.util.concurrent.ThreadFactory)
+ * @see Executors#newScheduledThreadPool(int)
+ * @see Executors#newScheduledThreadPool(int, java.util.concurrent.ThreadFactory)
+ * @see Executors#newSingleThreadExecutor()
+ * @see Executors#newSingleThreadExecutor(java.util.concurrent.ThreadFactory)
+ * @see Executors#newSingleThreadScheduledExecutor()
+ * @see Executors#newSingleThreadScheduledExecutor(java.util.concurrent.ThreadFactory)
+ */
+ public void setExecutorService( ExecutorService executorService ) {
+ ArgCheck.isNotNull(executorService, "executor service");
+ if (this.getAdministrator().isStarted()) {
+ throw new IllegalStateException(RepositoryI18n.unableToChangeExecutionContextWhileRunning.text());
+ }
+ this.executorService = executorService;
+ }
+
+ /**
+ * Override this method to creates a different kind of default executor service. This method is called when the system is
+ * {@link #start() started} without an executor service being {@link #setExecutorService(ExecutorService) set}.
+ * <p>
+ * This method creates a {@link Executors#newSingleThreadExecutor() single-threaded executor}.
+ * </p>
+ * @return
+ */
+ protected ExecutorService createDefaultExecutorService() {
+ return Executors.newSingleThreadExecutor();
+ }
+
+ protected void startService() {
+ if (this.getExecutionContext() == null) {
+ throw new IllegalStateException(RepositoryI18n.unableToStartSequencingServiceWithoutExecutionContext.text());
+ }
+ if (this.executorService == null) {
+ this.executorService = createDefaultExecutorService();
+ }
+ assert this.executorService != null;
+ assert this.sequencerSelector != null;
+ assert this.nodeFilter != null;
+ assert this.sequencerLibrary != null;
+ }
+
+ protected void shutdownService() {
+ if (this.executorService != null) {
+ this.executorService.shutdown();
+ }
+ }
+
+ protected boolean doAwaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
+ if (this.executorService.isShutdown()) return true;
+ return this.executorService.awaitTermination(timeout, unit);
+ }
+
+ /**
+ * Get the sequencing selector used by this system.
+ * @return the sequencing selector
+ */
+ public Selector getSequencerSelector() {
+ return this.sequencerSelector;
+ }
+
+ /**
+ * Set the sequencer selector, or null if the {@link #DEFAULT_SEQUENCER_SELECTOR default sequencer selector} should be used.
+ * @param sequencerSelector the selector
+ */
+ public void setSequencerSelector( Selector sequencerSelector ) {
+ this.sequencerSelector = sequencerSelector != null ? sequencerSelector : DEFAULT_SEQUENCER_SELECTOR;
+ }
+
+ /**
+ * Get the node filter used by this system.
+ * @return the node filter
+ */
+ public NodeFilter getNodeFilter() {
+ return this.nodeFilter;
+ }
+
+ /**
+ * Set the filter that checks which nodes are to be sequenced, or null if the {@link #DEFAULT_NODE_FILTER default node filter}
+ * should be used.
+ * @param nodeFilter the new node filter
+ */
+ public void setNodeFilter( NodeFilter nodeFilter ) {
+ this.nodeFilter = nodeFilter != null ? nodeFilter : DEFAULT_NODE_FILTER;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onNodeChanges( NodeChanges changes ) {
+ NodeFilter filter = this.getNodeFilter();
+ for (final NodeChange changedNode : changes) {
+ // Only care about new nodes or nodes that have new/changed properies ...
+ if (filter.accept(changedNode)) {
+ this.executorService.execute(new Runnable() {
+
+ public void run() {
+ processChangedNode(changedNode);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Do the work of processing by sequencing the node. This method is called by the {@link #executorService executor service}
+ * when it performs it's work on the enqueued {@link ChangedNode ChangedNode runnable objects}.
+ * @param node the node to be processed.
+ */
+ protected void processChangedNode( NodeChange changedNode ) {
+ try {
+ final String repositoryWorkspaceName = changedNode.getRepositoryWorkspaceName();
+ Session session = null;
+ try {
+ // Figure out which sequencers accept this path,
+ // and track which output nodes should be passed to each sequencer...
+ final String nodePath = changedNode.getAbsolutePath();
+ Map<SequencerCall, Set<RepositoryNodePath>> sequencerCalls = new HashMap<SequencerCall, Set<RepositoryNodePath>>();
+ List<Sequencer> allSequencers = this.sequencerLibrary.getInstances();
+ List<Sequencer> sequencers = new ArrayList<Sequencer>(allSequencers.size());
+ for (Sequencer sequencer : allSequencers) {
+ final SequencerConfig config = sequencer.getConfiguration();
+ for (SequencerPathExpression pathExpression : config.getPathExpressions()) {
+ for (String propertyName : changedNode.getModifiedProperties()) {
+ String path = nodePath + "/@" + propertyName;
+ SequencerPathExpression.Matcher matcher = pathExpression.matcher(path);
+ if (matcher.matches()) {
+ // String selectedPath = matcher.getSelectedPath();
+ RepositoryNodePath outputPath = RepositoryNodePath.parse(matcher.getOutputPath(), repositoryWorkspaceName);
+ SequencerCall call = new SequencerCall(sequencer, propertyName);
+ // Record the output path ...
+ Set<RepositoryNodePath> outputPaths = sequencerCalls.get(call);
+ if (outputPaths == null) {
+ outputPaths = new HashSet<RepositoryNodePath>();
+ sequencerCalls.put(call, outputPaths);
+ }
+ outputPaths.add(outputPath);
+ sequencers.add(sequencer);
+ break;
+ }
+ }
+ }
+ }
+
+ Node node = null;
+ if (!sequencers.isEmpty()) {
+ // Create a session that we'll use for all sequencing ...
+ session = this.getExecutionContext().getSessionFactory().createSession(repositoryWorkspaceName);
+
+ // Find the changed node ...
+ String relPath = changedNode.getAbsolutePath().replaceAll("^/+", "");
+ node = session.getRootNode().getNode(relPath);
+
+ // Figure out which sequencers should run ...
+ sequencers = this.sequencerSelector.selectSequencers(sequencers, node, changedNode);
+ }
+ if (sequencers.isEmpty()) {
+ this.statistics.recordNodeSkipped();
+ if (this.logger.isDebugEnabled()) {
+ this.logger.trace("Skipping '{}': no sequencers matched this condition", changedNode);
+ }
+ } else {
+ // Run each of those sequencers ...
+ ProgressMonitor progressMonitor = new SimpleProgressMonitor(RepositoryI18n.sequencerTask.text(changedNode));
+ if (this.logger.isTraceEnabled()) {
+ progressMonitor = new LoggingProgressMonitor(progressMonitor, this.logger, Logger.Level.TRACE);
+ }
+ try {
+ progressMonitor.beginTask(sequencerCalls.size(), RepositoryI18n.sequencerTask, changedNode);
+ for (Map.Entry<SequencerCall, Set<RepositoryNodePath>> entry : sequencerCalls.entrySet()) {
+ final SequencerCall sequencerCall = entry.getKey();
+ final Set<RepositoryNodePath> outputPaths = entry.getValue();
+ final Sequencer sequencer = sequencerCall.getSequencer();
+ final String sequencerName = sequencer.getConfiguration().getName();
+ final String propertyName = sequencerCall.getSequencedPropertyName();
+
+ // Get the paths to the nodes where the sequencer should write it's output ...
+ assert outputPaths != null && outputPaths.size() != 0;
+
+ // Create a new execution context for each sequencer
+ final Context executionContext = new Context();
+ final ProgressMonitor sequenceMonitor = progressMonitor.createSubtask(1);
+ try {
+ sequenceMonitor.beginTask(100, RepositoryI18n.sequencerSubtask, sequencerName);
+ sequencer.execute(node, propertyName, changedNode, outputPaths, executionContext, sequenceMonitor.createSubtask(80)); // 80%
+ } catch (RepositoryException e) {
+ this.logger.error(e, RepositoryI18n.errorInRepositoryWhileSequencingNode, sequencerName, changedNode);
+ } catch (SequencerException e) {
+ this.logger.error(e, RepositoryI18n.errorWhileSequencingNode, sequencerName, changedNode);
+ } finally {
+ try {
+ // Save the changes made by each sequencer ...
+ if (session != null) session.save();
+ sequenceMonitor.worked(10); // 90% of sequenceMonitor
+ } finally {
+ try {
+ // And always close the context.
+ // This closes all sessions that may have been created by the sequencer.
+ executionContext.close();
+ } finally {
+ sequenceMonitor.done(); // 100% of sequenceMonitor
+ }
+ }
+ }
+ }
+ this.statistics.recordNodeSequenced();
+ } finally {
+ progressMonitor.done();
+ }
+ }
+ } finally {
+ if (session != null) session.logout();
+ }
+ } catch (RepositoryException e) {
+ this.logger.error(e, RepositoryI18n.errorInRepositoryWhileFindingSequencersToRunAgainstNode, changedNode);
+ } catch (Exception e) {
+ this.logger.error(e, RepositoryI18n.errorFindingSequencersToRunAgainstNode, changedNode);
+ }
+ }
+
+ protected class Context implements ExecutionContext {
+
+ protected final SessionFactory factory;
+ private final Set<Session> sessions = new HashSet<Session>();
+ protected final AtomicBoolean closed = new AtomicBoolean(false);
+
+ protected Context() {
+ final SessionFactory delegate = SequencingService.this.getExecutionContext().getSessionFactory();
+ this.factory = new SessionFactory() {
+
+ public Session createSession( String name ) throws RepositoryException {
+ if (closed.get()) throw new IllegalStateException(RepositoryI18n.executionContextHasBeenClosed.text());
+ Session session = delegate.createSession(name);
+ recordSession(session);
+ return session;
+ }
+ };
+ }
+
+ protected synchronized void recordSession( Session session ) {
+ if (session != null) sessions.add(session);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SessionFactory getSessionFactory() {
+ return this.factory;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public JcrTools getTools() {
+ return SequencingService.this.getExecutionContext().getTools();
+ }
+
+ public synchronized void close() {
+ if (this.closed.get()) return;
+ this.closed.set(true);
+ for (Session session : sessions) {
+ if (session != null) session.logout();
+ }
+ }
+ }
+
+ /**
+ * The statistics for the system. Each sequencing system has an instance of this class that is updated.
+ * @author Randall Hauch
+ */
+ @ThreadSafe
+ public class Statistics {
+
+ private final AtomicLong numberOfNodesSequenced = new AtomicLong(0);
+ private final AtomicLong numberOfNodesSkipped = new AtomicLong(0);
+ private final AtomicLong startTime;
+
+ protected Statistics() {
+ startTime = new AtomicLong(System.currentTimeMillis());
+ }
+
+ public Statistics reset() {
+ this.startTime.set(System.currentTimeMillis());
+ this.numberOfNodesSequenced.set(0);
+ this.numberOfNodesSkipped.set(0);
+ return this;
+ }
+
+ /**
+ * @return the system time when the statistics were started
+ */
+ public long getStartTime() {
+ return this.startTime.get();
+ }
+
+ /**
+ * @return the number of nodes that were sequenced
+ */
+ public long getNumberOfNodesSequenced() {
+ return this.numberOfNodesSequenced.get();
+ }
+
+ /**
+ * @return the number of nodes that were skipped because no sequencers applied
+ */
+ public long getNumberOfNodesSkipped() {
+ return this.numberOfNodesSkipped.get();
+ }
+
+ protected void recordNodeSequenced() {
+ this.numberOfNodesSequenced.incrementAndGet();
+ }
+
+ protected void recordNodeSkipped() {
+ this.numberOfNodesSkipped.incrementAndGet();
+ }
+ }
+
+ @Immutable
+ protected class SequencerCall {
+
+ private final Sequencer sequencer;
+ private final String sequencerName;
+ private final String sequencedPropertyName;
+ private final int hc;
+
+ protected SequencerCall( Sequencer sequencer, String sequencedPropertyName ) {
+ this.sequencer = sequencer;
+ this.sequencerName = sequencer.getConfiguration().getName();
+ this.sequencedPropertyName = sequencedPropertyName;
+ this.hc = HashCode.compute(this.sequencerName, this.sequencedPropertyName);
+ }
+
+ /**
+ * @return sequencer
+ */
+ public Sequencer getSequencer() {
+ return this.sequencer;
+ }
+
+ /**
+ * @return sequencedPropertyName
+ */
+ public String getSequencedPropertyName() {
+ return this.sequencedPropertyName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return this.hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof SequencerCall) {
+ SequencerCall that = (SequencerCall)obj;
+ if (!this.sequencerName.equals(that.sequencerName)) return false;
+ if (!this.sequencedPropertyName.equals(that.sequencedPropertyName)) return false;
+ return true;
+ }
+ return false;
+ }
+ }
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapter.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapter.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapter.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,253 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Set;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import org.jboss.dna.common.jcr.Path;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.repository.observation.NodeChange;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.RepositoryNodePath;
+import org.jboss.dna.spi.sequencers.StreamSequencer;
+
+/**
+ * An adapter class that wraps a {@link StreamSequencer} instance to be a {@link Sequencer}.
+ * @author Randall Hauch
+ */
+public class StreamSequencerAdapter implements Sequencer {
+
+ private SequencerConfig configuration;
+ private final StreamSequencer streamSequencer;
+
+ public StreamSequencerAdapter( StreamSequencer streamSequencer ) {
+ this.streamSequencer = streamSequencer;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SequencerConfig getConfiguration() {
+ return this.configuration;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setConfiguration( SequencerConfig configuration ) {
+ this.configuration = configuration;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, ExecutionContext context, ProgressMonitor progressMonitor )
+ throws RepositoryException, SequencerException {
+ // 'sequencedPropertyName' contains the name of the modified property on 'input' that resuled the call to this sequencer
+ // 'changes' contains all of the changes to this node that occurred in the transaction.
+ // 'outputPaths' contains the paths of the node(s) where this sequencer is to save it's data
+
+ try {
+ progressMonitor.beginTask(100, RepositoryI18n.sequencingPropertyOnNode, sequencedPropertyName, input.getPath());
+
+ // Get the property that contains the image data, given by 'propertyName' ...
+ Property imageDataProperty = null;
+ try {
+ imageDataProperty = input.getProperty(sequencedPropertyName);
+ } catch (PathNotFoundException e) {
+ String msg = RepositoryI18n.unableToFindPropertyForSequencing.text(sequencedPropertyName, input.getPath());
+ throw new SequencerException(msg, e);
+ }
+ progressMonitor.worked(10);
+
+ // Get the binary property with the image content, and build the image metadata from the image ...
+ SequencerOutputMap output = new SequencerOutputMap();
+ InputStream stream = null;
+ Throwable firstError = null;
+ ProgressMonitor sequencingMonitor = progressMonitor.createSubtask(50);
+ try {
+ stream = imageDataProperty.getStream();
+ this.streamSequencer.sequence(stream, output, sequencingMonitor);
+ } catch (Throwable t) {
+ // Record the error ...
+ firstError = t;
+ } finally {
+ sequencingMonitor.done();
+ if (stream != null) {
+ // Always close the stream, recording the error if we've not yet seen an error
+ try {
+ stream.close();
+ } catch (Throwable t) {
+ if (firstError == null) firstError = t;
+ } finally {
+ stream = null;
+ }
+ }
+ if (firstError != null) {
+ // Wrap and throw the first error that we saw ...
+ throw new SequencerException(firstError);
+ }
+ }
+
+ // Find each output node and save the image metadata there ...
+ ProgressMonitor writingProgress = progressMonitor.createSubtask(40);
+ writingProgress.beginTask(outputPaths.size(), RepositoryI18n.writingOutputSequencedFromPropertyOnNodes, sequencedPropertyName, input.getPath(), outputPaths.size());
+ for (RepositoryNodePath outputPath : outputPaths) {
+ Session session = null;
+ try {
+ // Get the name of the repository workspace and the path to the output node
+ final String repositoryWorkspaceName = outputPath.getRepositoryWorkspaceName();
+ final String nodePath = outputPath.getNodePath();
+
+ // Create a session to the repository where the data should be written ...
+ session = context.getSessionFactory().createSession(repositoryWorkspaceName);
+
+ // Find or create the output node in this session ...
+ Node outputNode = context.getTools().findOrCreateNode(session, nodePath);
+
+ // Now save the image metadata to the output node ...
+ if (saveOutput(outputNode, output, context)) {
+ session.save();
+ }
+ } finally {
+ writingProgress.worked(1);
+ // Always close the session ...
+ if (session != null) session.logout();
+ }
+ }
+ writingProgress.done();
+ } finally {
+ progressMonitor.done();
+ }
+ }
+
+ /**
+ * Save the sequencing output to the supplied node. This method does not need to save the output, as that is done by the
+ * caller of this method.
+ * @param outputNode the existing node onto (or below) which the output is to be written; never null
+ * @param outputProperties the (immutable) sequencing output; never null
+ * @param context the execution context for this sequencing operation; never null
+ * @return true if the output was written to the node, or false if no information was written
+ * @throws RepositoryException
+ */
+ protected boolean saveOutput( Node outputNode, SequencerOutputMap output, ExecutionContext context ) throws RepositoryException {
+ if (output.isEmpty()) return false;
+ final Path outputNodePath = new Path(outputNode.getPath());
+
+ // Iterate over the entries in the output, in Path's natural order (shorter paths first and in lexicographical order by
+ // prefix and name)
+ for (SequencerOutputMap.Entry entry : output) {
+ Path targetNodePath = entry.getPath();
+ String primaryType = entry.getPrimaryTypeValue();
+
+ // Resolve this path relative to the output node path, handling any parent or self references ...
+ Path absolutePath = targetNodePath.isAbsolute() ? targetNodePath : outputNodePath.resolve(targetNodePath);
+ Path relativePath = absolutePath.relativeTo(outputNodePath);
+
+ // Find or add the node (which may involve adding intermediate nodes) ...
+ Node targetNode = outputNode;
+ for (int i = 0, max = relativePath.size(); i != max; ++i) {
+ Path.Segment segment = relativePath.getSegment(i);
+ String qualifiedName = segment.getQualifiedName(true);
+ if (targetNode.hasNode(qualifiedName)) {
+ targetNode = targetNode.getNode(qualifiedName);
+ } else {
+ // It doesn't exist, so create it ...
+ if (segment.hasIndex()) {
+ // Use a name without an index ...
+ qualifiedName = segment.getQualifiedName(false);
+ }
+ // We only have the primary type for the final one ...
+ if (i == (max - 1) && primaryType != null) {
+ targetNode = targetNode.addNode(qualifiedName, primaryType);
+ } else {
+ targetNode = targetNode.addNode(qualifiedName);
+ }
+ }
+ assert targetNode != null;
+ }
+ assert targetNode != null;
+
+ // Set all of the properties on this
+ for (SequencerOutputMap.PropertyValue property : entry.getPropertyValues()) {
+ String propertyName = property.getName();
+ Object value = property.getValue();
+ Logger.getLogger(this.getClass()).trace("Writing property {0}/{1}={2}", targetNode.getPath(), propertyName, value);
+ if (value instanceof Boolean) {
+ targetNode.setProperty(propertyName, ((Boolean)value).booleanValue());
+ } else if (value instanceof String) {
+ targetNode.setProperty(propertyName, (String)value);
+ } else if (value instanceof Integer) {
+ targetNode.setProperty(propertyName, ((Integer)value).intValue());
+ } else if (value instanceof Short) {
+ targetNode.setProperty(propertyName, ((Short)value).shortValue());
+ } else if (value instanceof Long) {
+ targetNode.setProperty(propertyName, ((Long)value).longValue());
+ } else if (value instanceof Float) {
+ targetNode.setProperty(propertyName, ((Float)value).floatValue());
+ } else if (value instanceof Double) {
+ targetNode.setProperty(propertyName, ((Double)value).doubleValue());
+ } else if (value instanceof Calendar) {
+ targetNode.setProperty(propertyName, (Calendar)value);
+ } else if (value instanceof Path) {
+ // Find the path to reference node ...
+ Path pathToReferencedNode = (Path)value;
+ if (!pathToReferencedNode.isAbsolute()) {
+ // Resolve the path relative to the output node ...
+ pathToReferencedNode = outputNodePath.resolve(pathToReferencedNode);
+ }
+ // Find the referenced node ...
+ try {
+ Node referencedNode = outputNode.getNode(pathToReferencedNode.getString());
+ targetNode.setProperty(propertyName, referencedNode);
+ } catch (PathNotFoundException e) {
+ String msg = RepositoryI18n.errorGettingNodeRelativeToNode.text(value, outputNode.getPath());
+ throw new SequencerException(msg, e);
+ }
+ } else if (value == null) {
+ // Remove the property ...
+ targetNode.setProperty(propertyName, (String)null);
+ } else {
+ String msg = RepositoryI18n.unknownPropertyValueType.text(value, value.getClass().getName());
+ throw new SequencerException(msg);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ protected String[] extractMixinTypes( Object value ) {
+ if (value instanceof String[]) return (String[])value;
+ if (value instanceof String) return new String[] {(String)value};
+ return null;
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,216 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.services;
+
+import org.jboss.dna.repository.RepositoryI18n;
+import net.jcip.annotations.GuardedBy;
+import net.jcip.annotations.ThreadSafe;
+
+/**
+ * Simple abstract implementation of the service administrator interface that can be easily subclassed by services that require an
+ * administrative interface.
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public abstract class AbstractServiceAdministrator implements ServiceAdministrator {
+
+ private volatile State state;
+
+ protected AbstractServiceAdministrator( State initialState ) {
+ assert initialState != null;
+ this.state = initialState;
+ }
+
+ /**
+ * Return the current state of this service.
+ * @return the current state
+ */
+ public State getState() {
+ return this.state;
+ }
+
+ /**
+ * Set the state of the service. This method does nothing if the desired state matches the current state.
+ * @param state the desired state
+ * @return this object for method chaining purposes
+ * @see #setState(String)
+ * @see #start()
+ * @see #pause()
+ * @see #shutdown()
+ */
+ @GuardedBy( "this" )
+ public synchronized ServiceAdministrator setState( State state ) {
+ switch (state) {
+ case STARTED:
+ start();
+ break;
+ case PAUSED:
+ pause();
+ break;
+ case SHUTDOWN:
+ shutdown();
+ break;
+ }
+ return this;
+ }
+
+ /**
+ * Set the state of the service. This method does nothing if the desired state matches the current state.
+ * @param state the desired state in string form
+ * @return this object for method chaining purposes
+ * @throws IllegalArgumentException if the specified state string is null or does not match one of the predefined
+ * {@link ServiceAdministrator.State predefined enumerated values}
+ * @see #setState(State)
+ * @see #start()
+ * @see #pause()
+ * @see #shutdown()
+ */
+ public ServiceAdministrator setState( String state ) {
+ State newState = state == null ? null : State.valueOf(state.toUpperCase());
+ if (newState == null) {
+ throw new IllegalArgumentException(RepositoryI18n.invalidStateString.text(state));
+ }
+ return setState(newState);
+ }
+
+ /**
+ * Start monitoring and sequence the events. This method can be called multiple times, including after the service is
+ * {@link #pause() paused}. However, once the service is {@link #shutdown() shutdown}, it cannot be started or paused.
+ * @return this object for method chaining purposes
+ * @throws IllegalStateException if called when the service has been {@link #shutdown() shutdown}.
+ * @see #pause()
+ * @see #shutdown()
+ * @see #isStarted()
+ */
+ public synchronized ServiceAdministrator start() {
+ if (isShutdown()) throw new IllegalStateException(RepositoryI18n.serviceShutdowAndMayNotBeStarted.text(serviceName()));
+ if (this.state != State.STARTED) {
+ doStart(this.state);
+ this.state = State.STARTED;
+ }
+ return this;
+ }
+
+ /**
+ * Implementation of the functionality to switch to the started state. This method is only called if the state from which the
+ * service is transitioning is appropriate ({@link State#PAUSED}). This method does nothing by default, and should be
+ * overridden if needed.
+ * @param fromState the state from which this service is transitioning; never null
+ * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
+ */
+ @GuardedBy( "this" )
+ protected void doStart( State fromState ) {
+ }
+
+ /**
+ * Temporarily stop monitoring and sequencing events. This method can be called multiple times, including after the service is
+ * {@link #start() started}. However, once the service is {@link #shutdown() shutdown}, it cannot be started or paused.
+ * @return this object for method chaining purposes
+ * @throws IllegalStateException if called when the service has been {@link #shutdown() shutdown}.
+ * @see #start()
+ * @see #shutdown()
+ * @see #isPaused()
+ */
+ public synchronized ServiceAdministrator pause() {
+ if (isShutdown()) throw new IllegalStateException(RepositoryI18n.serviceShutdowAndMayNotBePaused.text(serviceName()));
+ if (this.state != State.PAUSED) {
+ doPause(this.state);
+ this.state = State.PAUSED;
+ }
+ return this;
+ }
+
+ /**
+ * Implementation of the functionality to switch to the paused state. This method is only called if the state from which the
+ * service is transitioning is appropriate ({@link State#STARTED}). This method does nothing by default, and should be
+ * overridden if needed.
+ * @param fromState the state from which this service is transitioning; never null
+ * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
+ */
+ @GuardedBy( "this" )
+ protected void doPause( State fromState ) {
+ }
+
+ /**
+ * Permanently stop monitoring and sequencing events. This method can be called multiple times, but only the first call has an
+ * effect. Once the service has been shutdown, it may not be {@link #start() restarted} or {@link #pause() paused}.
+ * @return this object for method chaining purposes
+ * @see #start()
+ * @see #pause()
+ * @see #isShutdown()
+ */
+ public synchronized ServiceAdministrator shutdown() {
+ if (this.state != State.SHUTDOWN) {
+ doShutdown(this.state);
+ this.state = State.SHUTDOWN;
+ }
+ return this;
+ }
+
+ /**
+ * Implementation of the functionality to switch to the shutdown state. This method is only called if the state from which the
+ * service is transitioning is appropriate ({@link State#STARTED} or {@link State#PAUSED}). This method does nothing by
+ * default, and should be overridden if needed.
+ * @param fromState the state from which this service is transitioning; never null
+ * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
+ */
+ @GuardedBy( "this" )
+ protected void doShutdown( State fromState ) {
+ }
+
+ /**
+ * Return whether this service has been started and is currently running.
+ * @return true if started and currently running, or false otherwise
+ * @see #start()
+ * @see #pause()
+ * @see #isPaused()
+ * @see #isShutdown()
+ */
+ public boolean isStarted() {
+ return this.state == State.STARTED;
+ }
+
+ /**
+ * Return whether this service is currently paused.
+ * @return true if currently paused, or false otherwise
+ * @see #pause()
+ * @see #start()
+ * @see #isStarted()
+ * @see #isShutdown()
+ */
+ public boolean isPaused() {
+ return this.state == State.PAUSED;
+ }
+
+ /**
+ * Return whether this service is stopped and unable to be restarted.
+ * @return true if currently shutdown, or false otherwise
+ * @see #shutdown()
+ * @see #isPaused()
+ * @see #isStarted()
+ */
+ public boolean isShutdown() {
+ return this.state == State.SHUTDOWN;
+ }
+
+ protected abstract String serviceName();
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AdministeredService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AdministeredService.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AdministeredService.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,30 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.services;
+
+/**
+ * @author Randall Hauch
+ */
+public interface AdministeredService {
+
+ ServiceAdministrator getAdministrator();
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AdministeredService.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,144 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.services;
+
+import java.util.concurrent.TimeUnit;
+import net.jcip.annotations.ThreadSafe;
+
+/**
+ * Contract defining an administrative interface for controlling the running state of a service.
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public interface ServiceAdministrator {
+
+ /**
+ * The available states.
+ * @author Randall Hauch
+ */
+ public static enum State {
+ STARTED,
+ PAUSED,
+ SHUTDOWN;
+ }
+
+ /**
+ * Return the current state of this system.
+ * @return the current state
+ */
+ public State getState();
+
+ /**
+ * Set the state of the system. This method does nothing if the desired state matches the current state.
+ * @param state the desired state
+ * @return this object for method chaining purposes
+ * @see #setState(String)
+ * @see #start()
+ * @see #pause()
+ * @see #shutdown()
+ */
+ public ServiceAdministrator setState( State state );
+
+ /**
+ * Set the state of the system. This method does nothing if the desired state matches the current state.
+ * @param state the desired state in string form
+ * @return this object for method chaining purposes
+ * @throws IllegalArgumentException if the specified state string is null or does not match one of the predefined
+ * {@link State predefined enumerated values}
+ * @see #setState(State)
+ * @see #start()
+ * @see #pause()
+ * @see #shutdown()
+ */
+ public ServiceAdministrator setState( String state );
+
+ /**
+ * Start monitoring and sequence the events. This method can be called multiple times, including after the system is
+ * {@link #pause() paused}. However, once the system is {@link #shutdown() shutdown}, it cannot be started or paused.
+ * @return this object for method chaining purposes
+ * @throws IllegalStateException if called when the system has been {@link #shutdown() shutdown}.
+ * @see #pause()
+ * @see #shutdown()
+ * @see #isStarted()
+ */
+ public ServiceAdministrator start();
+
+ /**
+ * Temporarily stop monitoring and sequencing events. This method can be called multiple times, including after the system is
+ * {@link #start() started}. However, once the system is {@link #shutdown() shutdown}, it cannot be started or paused.
+ * @return this object for method chaining purposes
+ * @throws IllegalStateException if called when the system has been {@link #shutdown() shutdown}.
+ * @see #start()
+ * @see #shutdown()
+ * @see #isPaused()
+ */
+ public ServiceAdministrator pause();
+
+ /**
+ * Permanently stop monitoring and sequencing events. This method can be called multiple times, but only the first call has an
+ * effect. Once the system has been shutdown, it may not be {@link #start() restarted} or {@link #pause() paused}.
+ * @return this object for method chaining purposes
+ * @see #start()
+ * @see #pause()
+ * @see #isShutdown()
+ */
+ public ServiceAdministrator shutdown();
+
+ /**
+ * Blocks until all work has completed execution after a shutdown request, or the timeout occurs, or the current thread is
+ * interrupted, whichever happens first.
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the timeout argument
+ * @return <tt>true</tt> if this service terminated and <tt>false</tt> if the timeout elapsed before termination
+ * @throws InterruptedException if interrupted while waiting
+ */
+ boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException;
+
+ /**
+ * Return whether this system has been started and is currently running.
+ * @return true if started and currently running, or false otherwise
+ * @see #start()
+ * @see #pause()
+ * @see #isPaused()
+ * @see #isShutdown()
+ */
+ public boolean isStarted();
+
+ /**
+ * Return whether this system is currently paused.
+ * @return true if currently paused, or false otherwise
+ * @see #pause()
+ * @see #start()
+ * @see #isStarted()
+ * @see #isShutdown()
+ */
+ public boolean isPaused();
+
+ /**
+ * Return whether this system is stopped and unable to be restarted.
+ * @return true if currently shutdown, or false otherwise
+ * @see #shutdown()
+ * @see #isPaused()
+ * @see #isStarted()
+ */
+ public boolean isShutdown();
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/ExecutionContext.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/ExecutionContext.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/ExecutionContext.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.util;
+
+import javax.jcr.Session;
+
+/**
+ * The context of an execution.
+ * @author Randall Hauch
+ */
+public interface ExecutionContext {
+
+ /**
+ * Get the session factory, which can be used to obtain sessions temporarily for this context. Any session obtained from this
+ * factory should be {@link Session#logout() closed} before the execution finishes.
+ * @return the session factory
+ */
+ SessionFactory getSessionFactory();
+
+ /**
+ * Get a set of utilities for working with JCR.
+ * @return the tools
+ */
+ JcrTools getTools();
+
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/ExecutionContext.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JcrTools.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JcrTools.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JcrTools.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,300 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import org.jboss.dna.common.collection.Problem;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.util.IoUtil;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.repository.RepositoryI18n;
+
+/**
+ * @author Randall Hauch
+ */
+public class JcrTools {
+
+ public Map<String, Object> loadProperties( Node propertyContainer, Problems problems ) {
+ return loadProperties(propertyContainer, null, problems);
+ }
+
+ public Map<String, Object> loadProperties( Node propertyContainer, Map<String, Object> properties, Problems problems ) {
+ if (properties == null) properties = new HashMap<String, Object>();
+ if (propertyContainer != null) {
+ try {
+ NodeIterator iter = propertyContainer.getNodes();
+ while (iter.hasNext()) {
+ Node propertyNode = iter.nextNode();
+ if (propertyNode != null && propertyNode.getPrimaryNodeType().isNodeType("dna:property")) {
+ String propertyName = propertyNode.getName();
+ Object propertyValue = getPropertyValue(propertyNode, "dna:propertyValue", true, problems);
+ properties.put(propertyName, propertyValue);
+ }
+ }
+ } catch (RepositoryException e) {
+ problems.addError(e, RepositoryI18n.errorReadingPropertiesFromContainerNode, getReadable(propertyContainer));
+ }
+ }
+
+ return properties;
+ }
+
+ public boolean removeProblems( Node parent ) throws RepositoryException {
+ Node problemsNode = null;
+ if (parent.hasNode("dna:problems")) {
+ problemsNode = parent.getNode("dna:problems");
+ problemsNode.remove();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean storeProblems( Node parent, Problems problems ) throws RepositoryException {
+ Node problemsNode = null;
+ if (parent.hasNode("dna:problems")) {
+ problemsNode = parent.getNode("dna:problems");
+ // Delete all problems ...
+ removeAllChildren(problemsNode);
+ }
+ if (problems.isEmpty()) {
+ return false;
+ }
+ if (problemsNode == null) {
+ problemsNode = parent.addNode("dna:problems"); // primary type dictated by child definition
+ }
+
+ // Add a child for each problem ...
+ for (Problem problem : problems) {
+ Node problemNode = problemsNode.addNode("problem", "dna:problem");
+ // - dna:status (string) mandatory copy
+ // < 'ERROR', 'WARNING', 'INFO'
+ // - dna:message (string) mandatory copy
+ // - dna:code (string) copy
+ // - dna:type (string) copy
+ // - dna:resource (string) copy
+ // - dna:location (string) copy
+ // - dna:trace (string) copy
+ problemNode.setProperty("dna:status", problem.getStatus().name());
+ problemNode.setProperty("dna:message", problem.getMessageString());
+ if (problem.getCode() != Problem.DEFAULT_CODE) {
+ problemNode.setProperty("dna:code", Integer.toString(problem.getCode()));
+ }
+ String resource = problem.getResource();
+ if (resource != null) {
+ problemNode.setProperty("dna:resource", resource);
+ }
+ String location = problem.getLocation();
+ if (location != null) {
+ problemNode.setProperty("dna:location", location);
+ }
+ Throwable t = problem.getThrowable();
+ if (t != null) {
+ String trace = StringUtil.getStackTrace(t);
+ problemNode.setProperty("dna:trace", trace);
+ }
+ }
+ return true;
+ }
+
+ public int removeAllChildren( Node node ) throws RepositoryException {
+ int childrenRemoved = 0;
+ NodeIterator iter = node.getNodes();
+ while (iter.hasNext()) {
+ Node child = iter.nextNode();
+ child.remove();
+ ++childrenRemoved;
+ }
+ return childrenRemoved;
+ }
+
+ public String getPropertyAsString( Node node, String propertyName, boolean required, Problems problems ) {
+ return getPropertyAsString(node, propertyName, required, null);
+ }
+
+ public String getPropertyAsString( Node node, String propertyName, boolean required, String defaultValue, Problems problems ) {
+ try {
+ Property property = node.getProperty(propertyName);
+ return property.getString();
+ } catch (ValueFormatException e) {
+ if (required) {
+ problems.addError(e, RepositoryI18n.requiredPropertyOnNodeWasExpectedToBeStringValue, propertyName, getReadable(node));
+ } else {
+ problems.addError(e, RepositoryI18n.optionalPropertyOnNodeWasExpectedToBeStringValue, propertyName, getReadable(node));
+ }
+ } catch (PathNotFoundException e) {
+ if (required) {
+ problems.addError(e, RepositoryI18n.requiredPropertyIsMissingFromNode, propertyName, getReadable(node));
+ }
+ if (!required) return defaultValue;
+ } catch (RepositoryException err) {
+ if (required) {
+ problems.addError(err, RepositoryI18n.errorGettingRequiredPropertyFromNode, propertyName, getReadable(node));
+ } else {
+ problems.addError(err, RepositoryI18n.errorGettingOptionalPropertyFromNode, propertyName, getReadable(node));
+ }
+ }
+ return null;
+ }
+
+ public Object getPropertyValue( Node node, String propertyName, boolean required, Problems problems ) {
+ try {
+ Property property = node.getProperty(propertyName);
+ switch (property.getType()) {
+ case PropertyType.BINARY: {
+ InputStream stream = property.getStream();
+ try {
+ stream = property.getStream();
+ return IoUtil.readBytes(stream);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // Log ...
+ Logger.getLogger(this.getClass()).error(e, RepositoryI18n.errorClosingBinaryStreamForPropertyFromNode, propertyName, node.getPath());
+ }
+ }
+ }
+ }
+ default: {
+ return property.getString();
+ }
+ }
+ } catch (IOException e) {
+ if (required) {
+ problems.addError(e, RepositoryI18n.requiredPropertyOnNodeCouldNotBeRead, propertyName, getReadable(node));
+ } else {
+ problems.addError(e, RepositoryI18n.optionalPropertyOnNodeCouldNotBeRead, propertyName, getReadable(node));
+ }
+ } catch (PathNotFoundException e) {
+ if (required) {
+ problems.addError(e, RepositoryI18n.requiredPropertyIsMissingFromNode, propertyName, getReadable(node));
+ }
+ } catch (RepositoryException err) {
+ if (required) {
+ problems.addError(err, RepositoryI18n.errorGettingRequiredPropertyFromNode, propertyName, getReadable(node));
+ } else {
+ problems.addError(err, RepositoryI18n.errorGettingOptionalPropertyFromNode, propertyName, getReadable(node));
+ }
+ }
+ return null;
+ }
+
+ public String[] getPropertyAsStringArray( Node node, String propertyName, boolean required, Problems problems, String... defaultValues ) {
+ String[] result = defaultValues;
+ try {
+ Property property = node.getProperty(propertyName);
+ if (property.getDefinition().isMultiple()) {
+ Value[] values = property.getValues();
+ result = new String[values.length];
+ int i = 0;
+ for (Value value : values) {
+ result[i++] = value.getString();
+ }
+ } else {
+ result = new String[] {property.getString()};
+ }
+ } catch (ValueFormatException e) {
+ if (required) {
+ problems.addError(e, RepositoryI18n.requiredPropertyOnNodeWasExpectedToBeStringArrayValue, propertyName, getReadable(node));
+ } else {
+ problems.addError(e, RepositoryI18n.optionalPropertyOnNodeWasExpectedToBeStringArrayValue, propertyName, getReadable(node));
+ }
+ } catch (PathNotFoundException e) {
+ if (required) {
+ problems.addError(e, RepositoryI18n.requiredPropertyIsMissingFromNode, propertyName, getReadable(node));
+ }
+ } catch (RepositoryException err) {
+ if (required) {
+ problems.addError(err, RepositoryI18n.errorGettingRequiredPropertyFromNode, propertyName, getReadable(node));
+ } else {
+ problems.addError(err, RepositoryI18n.errorGettingOptionalPropertyFromNode, propertyName, getReadable(node));
+ }
+ }
+ return result;
+ }
+
+ public Node getNode( Node node, String relativePath, boolean required, Problems problems ) {
+ Node result = null;
+ try {
+ result = node.getNode(relativePath);
+ } catch (PathNotFoundException e) {
+ if (required) problems.addError(e, RepositoryI18n.requiredNodeDoesNotExistRelativeToNode, relativePath, getReadable(node));
+ } catch (RepositoryException err) {
+ problems.addError(err, RepositoryI18n.errorGettingNodeRelativeToNode, relativePath, getReadable(node));
+ }
+ return result;
+ }
+
+ public String getReadable( Node node ) {
+ if (node == null) return "";
+ try {
+ return node.getPath();
+ } catch (RepositoryException err) {
+ return node.toString();
+ }
+ }
+
+ public Node findOrCreateNode( Session session, String path ) throws RepositoryException {
+ Node root = session.getRootNode();
+ // Remove leading and trailing slashes ...
+ String relPath = path.replaceAll("^/+", "").replaceAll("/+$", "");
+
+ // Look for the node first ...
+ try {
+ return root.getNode(relPath);
+ } catch (PathNotFoundException e) {
+ // continue
+ }
+ // Create the node, which has to be done segment by segment ...
+ String[] pathSegments = relPath.split("/");
+ Node node = root;
+ for (String pathSegment : pathSegments) {
+ pathSegment = pathSegment.trim();
+ if (pathSegment.length() == 0) continue;
+ if (node.hasNode(pathSegment)) {
+ // Find the existing node ...
+ node = node.getNode(pathSegment);
+ } else {
+ // Make sure there is no index on the final segment ...
+ String pathSegmentWithNoIndex = pathSegment.replaceAll("(\\[\\d+\\])+$", "");
+ // Create the node ...
+ node = node.addNode(pathSegmentWithNoIndex);
+ }
+ }
+ return node;
+ }
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JndiSessionFactory.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JndiSessionFactory.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JndiSessionFactory.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,249 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.util;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.jcr.Credentials;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import org.jboss.dna.common.SystemFailureException;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.repository.RepositoryI18n;
+
+/**
+ * A SessionFactory implementation that creates {@link Session} instances using {@link Repository} instances registered in JNDI.
+ * <p>
+ * This factory using a naming convention where the name supplied to the {@link #createSession(String)} contains both the name of
+ * the repository and the name of the workspace. Typically, this is <i><code>repositoryName/workspaceName</code></i>, where
+ * <code>repositoryName</code> is the JNDI name under which the Repository instance was bound, and <code>workspaceName</code>
+ * is the name of the workspace. Note that this method looks for the last delimiter in the whole name to distinguish between the
+ * repository and workspace names.
+ * </p>
+ * <p>
+ * For example, if "<code>java:comp/env/repository/dataRepository/myWorkspace</code>" is passed to the
+ * {@link #createSession(String)} method, this factory will look for a {@link Repository} instance registered in JDNI with the
+ * name "<code>java:comp/env/repository/dataRepository</code>" and use it to {@link Repository#login(String) create a session}
+ * to the workspace named "<code>myWorkspace</code>".
+ * </p>
+ * <p>
+ * By default, this factory creates an anonymous JCR session. To use sessions with specific {@link Credentials}, simply
+ * {@link #registerCredentials(String, Credentials) register} credentials for the appropriate repository/workspace name. For
+ * security reasons, it is not possible to retrieve the Credentials once registered with this factory.
+ * </p>
+ * @author Randall Hauch
+ */
+public class JndiSessionFactory implements SessionFactory {
+
+ protected static char[] DEFAULT_DELIMITERS = new char[] {'/'};
+
+ private final char[] workspaceDelims;
+ private final String workspaceDelimsRegexCharacterSet;
+ private final Context context;
+ private final Map<String, Credentials> credentials = new ConcurrentHashMap<String, Credentials>();
+
+ /**
+ * Create an instance of the factory by creating a new {@link InitialContext}. This is equivalent to calling
+ * <code>new JndiSessionFactory(new InitialContext())</code>.
+ * @throws NamingException if there is a problem creating the InitialContext.
+ */
+ public JndiSessionFactory() throws NamingException {
+ this(new InitialContext());
+ }
+
+ /**
+ * Create an instance of the factory by supplying the characters that may be used to delimit the workspace name from the
+ * repository name. This constructor initializes the factory with a new {@link InitialContext}, and is equivalent to calling
+ * <code>new JndiSessionFactory(new InitialContext(),workspaceDelimiters)</code>.
+ * @param workspaceDelimiters the delimiters, or null/empty if the default delimiter of '/' should be used.
+ * @throws NamingException if there is a problem creating the InitialContext.
+ */
+ public JndiSessionFactory( char... workspaceDelimiters ) throws NamingException {
+ this(new InitialContext(), workspaceDelimiters);
+ }
+
+ /**
+ * Create an instance of the factory using the supplied JNDI context.
+ * @param context the naming context
+ * @throws IllegalArgumentException if the context parameter is null
+ */
+ public JndiSessionFactory( Context context ) {
+ this(context, DEFAULT_DELIMITERS);
+ }
+
+ /**
+ * Create an instance of the factory by supplying naming context and the characters that may be used to delimit the workspace
+ * name from the repository name.
+ * @param context the naming context
+ * @param workspaceDelimiters the delimiters, or null/empty if the default delimiter of '/' should be used.
+ * @throws IllegalArgumentException if the context parameter is null
+ */
+ public JndiSessionFactory( Context context, char... workspaceDelimiters ) {
+ ArgCheck.isNotNull(context, "initial context");
+ this.context = context;
+ this.workspaceDelims = (workspaceDelimiters == null || workspaceDelimiters.length == 0) ? DEFAULT_DELIMITERS : workspaceDelimiters;
+ StringBuilder sb = new StringBuilder();
+ for (char delim : this.workspaceDelims) {
+ switch (delim) {
+ case '\\':
+ sb.append("\\");
+ break;
+ // case '[' : sb.append("\\["); break;
+ case ']':
+ sb.append("\\]");
+ break;
+ case '-':
+ sb.append("\\-");
+ break;
+ case '^':
+ sb.append("\\^");
+ break;
+ default:
+ sb.append(delim);
+ }
+ }
+ this.workspaceDelimsRegexCharacterSet = sb.toString();
+ }
+
+ /**
+ * Convenience method to bind a repository in JNDI. Repository instances can be bound into JNDI using any technique, so this
+ * method need not be used. <i>Note that the name should not contain the workspace part.</i>
+ * @param name the name of the repository, without the workspace name component.
+ * @param repository the repository to be bound, or null if an existing repository should be unbound.
+ * @throws NamingException if there is a problem registering the supplied repository
+ */
+ public void registerRepository( String name, Repository repository ) throws NamingException {
+ assert name != null;
+ // Remove all trailing delimiters ...
+ name = name.replaceAll("[" + this.workspaceDelimsRegexCharacterSet + "]+$", "");
+ if (repository != null) {
+ this.context.bind(name, repository);
+ } else {
+ this.context.unbind(name);
+ }
+ }
+
+ /**
+ * Register the credentials for the repository and workspace given by the supplied name, username and password. This is
+ * equivalent to calling <code>registerCredentials(name, new SimpleCredentials(username,password))</code>, although if
+ * <code>username</code> is null then this is equivalent to <code>registerCredentials(name,null)</code>.
+ * @param name the name of the repository and workspace
+ * @param username the username to use, or null if the existing credentials for the named workspace should be removed
+ * @param password the password, may be null or empty
+ * @return true if this overwrote existing credentials
+ * @see #registerCredentials(String, Credentials)
+ * @see #removeCredentials(String)
+ */
+ public boolean registerCredentials( String name, String username, char[] password ) {
+ if (password == null && username != null) password = new char[] {};
+ Credentials creds = username == null ? null : new SimpleCredentials(username, password);
+ return registerCredentials(name, creds);
+ }
+
+ /**
+ * Register the credentials to be used for the named repository and workspace. Use the same name as used to
+ * {@link #createSession(String) create sessions}.
+ * @param name the name of the repository and workspace
+ * @param credentials the credentials to use, or null if the existing credentials for the named workspace should be removed
+ * @return true if this overwrote existing credentials
+ * @see #registerCredentials(String, String, char[])
+ * @see #removeCredentials(String)
+ */
+ public boolean registerCredentials( String name, Credentials credentials ) {
+ boolean foundExisting = false;
+ name = name != null ? name.trim() : null;
+ if (credentials == null) {
+ foundExisting = this.credentials.remove(name) != null;
+ } else {
+ foundExisting = this.credentials.put(name, credentials) != null;
+ }
+ return foundExisting;
+ }
+
+ /**
+ * Remove any credentials associated with the named repository and workspace. This is equivalent to calling
+ * <code>registerCredentials(name,null)</code>.
+ * @param name the name of the repository and workspace
+ * @return true if existing credentials were found and removed, or false if no such credentials existed
+ * @see #registerCredentials(String, Credentials)
+ */
+ public boolean removeCredentials( String name ) {
+ return registerCredentials(name, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Session createSession( String name ) throws RepositoryException {
+ ArgCheck.isNotNull(name, "session name");
+ name = name.trim();
+ // Look up the Repository object in JNDI ...
+ String repositoryName = getRepositoryName(name);
+ Repository repository = null;
+ try {
+ repository = (Repository)this.context.lookup(repositoryName);
+ } catch (NamingException err) {
+ throw new SystemFailureException(RepositoryI18n.unableToFindRepositoryInJndi.text(repositoryName));
+ }
+
+ // Determine the name of the workspace ...
+ String workspaceName = getWorkspaceName(name);
+
+ // Look up any credentials, which may be null ...
+ Credentials creds = this.credentials.get(name);
+
+ // Create a session to the specified workspace and using the credentials (either or both may be null) ...
+ return repository.login(creds, workspaceName);
+ }
+
+ protected String getWorkspaceName( String name ) {
+ assert name != null;
+ int index = getIndexOfLastWorkspaceDelimiter(name);
+ if (index == -1) return null;
+ if ((index + 1) == name.length()) return null; // delim is the last character
+ return name.substring(index + 1);
+ }
+
+ protected String getRepositoryName( String name ) {
+ assert name != null;
+ int index = getIndexOfLastWorkspaceDelimiter(name);
+ if (index == -1) return name; // no delim
+ if ((index + 1) == name.length()) return name.substring(0, index); // delim as last character
+ return name.substring(0, index);
+ }
+
+ protected int getIndexOfLastWorkspaceDelimiter( String name ) {
+ int index = -1;
+ for (char delim : this.workspaceDelims) {
+ int i = name.lastIndexOf(delim);
+ index = Math.max(index, i);
+ }
+ return index;
+ }
+
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/JndiSessionFactory.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/RepositoryNodePath.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/RepositoryNodePath.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/RepositoryNodePath.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,105 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.repository.RepositoryI18n;
+
+/**
+ * @author Randall Hauch
+ */
+@Immutable
+public class RepositoryNodePath {
+
+ protected static final Pattern PATTERN = Pattern.compile("([^:/]):(/.*)");
+
+ public static RepositoryNodePath parse( String path, String defaultRepositoryWorkspaceName ) {
+ Matcher matcher = PATTERN.matcher(path);
+ if (matcher.matches()) {
+ try {
+ return new RepositoryNodePath(matcher.group(1), matcher.group(2));
+ } catch (Throwable t) {
+ throw new IllegalArgumentException(RepositoryI18n.invalidRepositoryNodePath.text(path, t.getMessage()));
+ }
+ }
+ return new RepositoryNodePath(defaultRepositoryWorkspaceName, path);
+
+ }
+
+ private final String repositoryName;
+ private final String nodePath;
+ private final int hc;
+
+ public RepositoryNodePath( String repositoryName, String nodePath ) {
+ this.repositoryName = repositoryName;
+ this.nodePath = nodePath;
+ this.hc = HashCode.compute(this.repositoryName, this.nodePath);
+ }
+
+ /**
+ * @return nodePath
+ */
+ public String getNodePath() {
+ return this.nodePath;
+ }
+
+ /**
+ * @return repositoryName
+ */
+ public String getRepositoryWorkspaceName() {
+ return this.repositoryName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return this.hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof RepositoryNodePath) {
+ RepositoryNodePath that = (RepositoryNodePath)obj;
+ if (!this.repositoryName.equals(that.repositoryName)) return false;
+ if (!this.nodePath.equals(that.nodePath)) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return this.repositoryName + ":" + this.nodePath;
+ }
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/RepositoryNodePath.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SessionFactory.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SessionFactory.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SessionFactory.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,35 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.util;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+/**
+ * @author Randall Hauch
+ */
+public interface SessionFactory {
+
+ Session createSession( String name ) throws RepositoryException;
+
+}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/services/AbstractServiceAdministrator.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/AbstractServiceAdministrator.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/services/AbstractServiceAdministrator.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,215 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import net.jcip.annotations.GuardedBy;
-import net.jcip.annotations.ThreadSafe;
-
-/**
- * Simple abstract implementation of the service administrator interface that can be easily subclassed by services that require an
- * administrative interface.
- * @author Randall Hauch
- */
-@ThreadSafe
-public abstract class AbstractServiceAdministrator implements ServiceAdministrator {
-
- private volatile State state;
-
- protected AbstractServiceAdministrator( State initialState ) {
- assert initialState != null;
- this.state = initialState;
- }
-
- /**
- * Return the current state of this service.
- * @return the current state
- */
- public State getState() {
- return this.state;
- }
-
- /**
- * Set the state of the service. This method does nothing if the desired state matches the current state.
- * @param state the desired state
- * @return this object for method chaining purposes
- * @see #setState(String)
- * @see #start()
- * @see #pause()
- * @see #shutdown()
- */
- @GuardedBy( "this" )
- public synchronized ServiceAdministrator setState( State state ) {
- switch (state) {
- case STARTED:
- start();
- break;
- case PAUSED:
- pause();
- break;
- case SHUTDOWN:
- shutdown();
- break;
- }
- return this;
- }
-
- /**
- * Set the state of the service. This method does nothing if the desired state matches the current state.
- * @param state the desired state in string form
- * @return this object for method chaining purposes
- * @throws IllegalArgumentException if the specified state string is null or does not match one of the predefined
- * {@link ServiceAdministrator.State predefined enumerated values}
- * @see #setState(State)
- * @see #start()
- * @see #pause()
- * @see #shutdown()
- */
- public ServiceAdministrator setState( String state ) {
- State newState = state == null ? null : State.valueOf(state.toUpperCase());
- if (newState == null) {
- throw new IllegalArgumentException(ServicesI18n.invalidStateString.text(state));
- }
- return setState(newState);
- }
-
- /**
- * Start monitoring and sequence the events. This method can be called multiple times, including after the service is
- * {@link #pause() paused}. However, once the service is {@link #shutdown() shutdown}, it cannot be started or paused.
- * @return this object for method chaining purposes
- * @throws IllegalStateException if called when the service has been {@link #shutdown() shutdown}.
- * @see #pause()
- * @see #shutdown()
- * @see #isStarted()
- */
- public synchronized ServiceAdministrator start() {
- if (isShutdown()) throw new IllegalStateException(ServicesI18n.serviceShutdowAndMayNotBeStarted.text(serviceName()));
- if (this.state != State.STARTED) {
- doStart(this.state);
- this.state = State.STARTED;
- }
- return this;
- }
-
- /**
- * Implementation of the functionality to switch to the started state. This method is only called if the state from which the
- * service is transitioning is appropriate ({@link State#PAUSED}). This method does nothing by default, and should be
- * overridden if needed.
- * @param fromState the state from which this service is transitioning; never null
- * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
- */
- @GuardedBy( "this" )
- protected void doStart( State fromState ) {
- }
-
- /**
- * Temporarily stop monitoring and sequencing events. This method can be called multiple times, including after the service is
- * {@link #start() started}. However, once the service is {@link #shutdown() shutdown}, it cannot be started or paused.
- * @return this object for method chaining purposes
- * @throws IllegalStateException if called when the service has been {@link #shutdown() shutdown}.
- * @see #start()
- * @see #shutdown()
- * @see #isPaused()
- */
- public synchronized ServiceAdministrator pause() {
- if (isShutdown()) throw new IllegalStateException(ServicesI18n.serviceShutdowAndMayNotBePaused.text(serviceName()));
- if (this.state != State.PAUSED) {
- doPause(this.state);
- this.state = State.PAUSED;
- }
- return this;
- }
-
- /**
- * Implementation of the functionality to switch to the paused state. This method is only called if the state from which the
- * service is transitioning is appropriate ({@link State#STARTED}). This method does nothing by default, and should be
- * overridden if needed.
- * @param fromState the state from which this service is transitioning; never null
- * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
- */
- @GuardedBy( "this" )
- protected void doPause( State fromState ) {
- }
-
- /**
- * Permanently stop monitoring and sequencing events. This method can be called multiple times, but only the first call has an
- * effect. Once the service has been shutdown, it may not be {@link #start() restarted} or {@link #pause() paused}.
- * @return this object for method chaining purposes
- * @see #start()
- * @see #pause()
- * @see #isShutdown()
- */
- public synchronized ServiceAdministrator shutdown() {
- if (this.state != State.SHUTDOWN) {
- doShutdown(this.state);
- this.state = State.SHUTDOWN;
- }
- return this;
- }
-
- /**
- * Implementation of the functionality to switch to the shutdown state. This method is only called if the state from which the
- * service is transitioning is appropriate ({@link State#STARTED} or {@link State#PAUSED}). This method does nothing by
- * default, and should be overridden if needed.
- * @param fromState the state from which this service is transitioning; never null
- * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
- */
- @GuardedBy( "this" )
- protected void doShutdown( State fromState ) {
- }
-
- /**
- * Return whether this service has been started and is currently running.
- * @return true if started and currently running, or false otherwise
- * @see #start()
- * @see #pause()
- * @see #isPaused()
- * @see #isShutdown()
- */
- public boolean isStarted() {
- return this.state == State.STARTED;
- }
-
- /**
- * Return whether this service is currently paused.
- * @return true if currently paused, or false otherwise
- * @see #pause()
- * @see #start()
- * @see #isStarted()
- * @see #isShutdown()
- */
- public boolean isPaused() {
- return this.state == State.PAUSED;
- }
-
- /**
- * Return whether this service is stopped and unable to be restarted.
- * @return true if currently shutdown, or false otherwise
- * @see #shutdown()
- * @see #isPaused()
- * @see #isStarted()
- */
- public boolean isShutdown() {
- return this.state == State.SHUTDOWN;
- }
-
- protected abstract String serviceName();
-}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/services/AdministeredService.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/AdministeredService.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/services/AdministeredService.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,30 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-/**
- * @author Randall Hauch
- */
-public interface AdministeredService {
-
- ServiceAdministrator getAdministrator();
-}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/services/ExecutionContext.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/ExecutionContext.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/services/ExecutionContext.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,46 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import javax.jcr.Session;
-import org.jboss.dna.services.util.JcrTools;
-
-/**
- * The context of an execution.
- * @author Randall Hauch
- */
-public interface ExecutionContext {
-
- /**
- * Get the session factory, which can be used to obtain sessions temporarily for this context. Any session obtained from this
- * factory should be {@link Session#logout() closed} before the execution finishes.
- * @return the session factory
- */
- SessionFactory getSessionFactory();
-
- /**
- * Get a set of utilities for working with JCR.
- * @return the tools
- */
- JcrTools getTools();
-
-}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/services/JndiSessionFactory.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/JndiSessionFactory.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/services/JndiSessionFactory.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,248 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import javax.jcr.Credentials;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import org.jboss.dna.common.SystemFailureException;
-import org.jboss.dna.common.util.ArgCheck;
-
-/**
- * A SessionFactory implementation that creates {@link Session} instances using {@link Repository} instances registered in JNDI.
- * <p>
- * This factory using a naming convention where the name supplied to the {@link #createSession(String)} contains both the name of
- * the repository and the name of the workspace. Typically, this is <i><code>repositoryName/workspaceName</code></i>, where
- * <code>repositoryName</code> is the JNDI name under which the Repository instance was bound, and <code>workspaceName</code>
- * is the name of the workspace. Note that this method looks for the last delimiter in the whole name to distinguish between the
- * repository and workspace names.
- * </p>
- * <p>
- * For example, if "<code>java:comp/env/repository/dataRepository/myWorkspace</code>" is passed to the
- * {@link #createSession(String)} method, this factory will look for a {@link Repository} instance registered in JDNI with the
- * name "<code>java:comp/env/repository/dataRepository</code>" and use it to {@link Repository#login(String) create a session}
- * to the workspace named "<code>myWorkspace</code>".
- * </p>
- * <p>
- * By default, this factory creates an anonymous JCR session. To use sessions with specific {@link Credentials}, simply
- * {@link #registerCredentials(String, Credentials) register} credentials for the appropriate repository/workspace name. For
- * security reasons, it is not possible to retrieve the Credentials once registered with this factory.
- * </p>
- * @author Randall Hauch
- */
-public class JndiSessionFactory implements SessionFactory {
-
- protected static char[] DEFAULT_DELIMITERS = new char[] {'/'};
-
- private final char[] workspaceDelims;
- private final String workspaceDelimsRegexCharacterSet;
- private final Context context;
- private final Map<String, Credentials> credentials = new ConcurrentHashMap<String, Credentials>();
-
- /**
- * Create an instance of the factory by creating a new {@link InitialContext}. This is equivalent to calling
- * <code>new JndiSessionFactory(new InitialContext())</code>.
- * @throws NamingException if there is a problem creating the InitialContext.
- */
- public JndiSessionFactory() throws NamingException {
- this(new InitialContext());
- }
-
- /**
- * Create an instance of the factory by supplying the characters that may be used to delimit the workspace name from the
- * repository name. This constructor initializes the factory with a new {@link InitialContext}, and is equivalent to calling
- * <code>new JndiSessionFactory(new InitialContext(),workspaceDelimiters)</code>.
- * @param workspaceDelimiters the delimiters, or null/empty if the default delimiter of '/' should be used.
- * @throws NamingException if there is a problem creating the InitialContext.
- */
- public JndiSessionFactory( char... workspaceDelimiters ) throws NamingException {
- this(new InitialContext(), workspaceDelimiters);
- }
-
- /**
- * Create an instance of the factory using the supplied JNDI context.
- * @param context the naming context
- * @throws IllegalArgumentException if the context parameter is null
- */
- public JndiSessionFactory( Context context ) {
- this(context, DEFAULT_DELIMITERS);
- }
-
- /**
- * Create an instance of the factory by supplying naming context and the characters that may be used to delimit the workspace
- * name from the repository name.
- * @param context the naming context
- * @param workspaceDelimiters the delimiters, or null/empty if the default delimiter of '/' should be used.
- * @throws IllegalArgumentException if the context parameter is null
- */
- public JndiSessionFactory( Context context, char... workspaceDelimiters ) {
- ArgCheck.isNotNull(context, "initial context");
- this.context = context;
- this.workspaceDelims = (workspaceDelimiters == null || workspaceDelimiters.length == 0) ? DEFAULT_DELIMITERS : workspaceDelimiters;
- StringBuilder sb = new StringBuilder();
- for (char delim : this.workspaceDelims) {
- switch (delim) {
- case '\\':
- sb.append("\\");
- break;
- // case '[' : sb.append("\\["); break;
- case ']':
- sb.append("\\]");
- break;
- case '-':
- sb.append("\\-");
- break;
- case '^':
- sb.append("\\^");
- break;
- default:
- sb.append(delim);
- }
- }
- this.workspaceDelimsRegexCharacterSet = sb.toString();
- }
-
- /**
- * Convenience method to bind a repository in JNDI. Repository instances can be bound into JNDI using any technique, so this
- * method need not be used. <i>Note that the name should not contain the workspace part.</i>
- * @param name the name of the repository, without the workspace name component.
- * @param repository the repository to be bound, or null if an existing repository should be unbound.
- * @throws NamingException if there is a problem registering the supplied repository
- */
- public void registerRepository( String name, Repository repository ) throws NamingException {
- assert name != null;
- // Remove all trailing delimiters ...
- name = name.replaceAll("[" + this.workspaceDelimsRegexCharacterSet + "]+$", "");
- if (repository != null) {
- this.context.bind(name, repository);
- } else {
- this.context.unbind(name);
- }
- }
-
- /**
- * Register the credentials for the repository and workspace given by the supplied name, username and password. This is
- * equivalent to calling <code>registerCredentials(name, new SimpleCredentials(username,password))</code>, although if
- * <code>username</code> is null then this is equivalent to <code>registerCredentials(name,null)</code>.
- * @param name the name of the repository and workspace
- * @param username the username to use, or null if the existing credentials for the named workspace should be removed
- * @param password the password, may be null or empty
- * @return true if this overwrote existing credentials
- * @see #registerCredentials(String, Credentials)
- * @see #removeCredentials(String)
- */
- public boolean registerCredentials( String name, String username, char[] password ) {
- if (password == null && username != null) password = new char[] {};
- Credentials creds = username == null ? null : new SimpleCredentials(username, password);
- return registerCredentials(name, creds);
- }
-
- /**
- * Register the credentials to be used for the named repository and workspace. Use the same name as used to
- * {@link #createSession(String) create sessions}.
- * @param name the name of the repository and workspace
- * @param credentials the credentials to use, or null if the existing credentials for the named workspace should be removed
- * @return true if this overwrote existing credentials
- * @see #registerCredentials(String, String, char[])
- * @see #removeCredentials(String)
- */
- public boolean registerCredentials( String name, Credentials credentials ) {
- boolean foundExisting = false;
- name = name != null ? name.trim() : null;
- if (credentials == null) {
- foundExisting = this.credentials.remove(name) != null;
- } else {
- foundExisting = this.credentials.put(name, credentials) != null;
- }
- return foundExisting;
- }
-
- /**
- * Remove any credentials associated with the named repository and workspace. This is equivalent to calling
- * <code>registerCredentials(name,null)</code>.
- * @param name the name of the repository and workspace
- * @return true if existing credentials were found and removed, or false if no such credentials existed
- * @see #registerCredentials(String, Credentials)
- */
- public boolean removeCredentials( String name ) {
- return registerCredentials(name, null);
- }
-
- /**
- * {@inheritDoc}
- */
- public Session createSession( String name ) throws RepositoryException {
- ArgCheck.isNotNull(name, "session name");
- name = name.trim();
- // Look up the Repository object in JNDI ...
- String repositoryName = getRepositoryName(name);
- Repository repository = null;
- try {
- repository = (Repository)this.context.lookup(repositoryName);
- } catch (NamingException err) {
- throw new SystemFailureException(ServicesI18n.unableToFindRepositoryInJndi.text(repositoryName));
- }
-
- // Determine the name of the workspace ...
- String workspaceName = getWorkspaceName(name);
-
- // Look up any credentials, which may be null ...
- Credentials creds = this.credentials.get(name);
-
- // Create a session to the specified workspace and using the credentials (either or both may be null) ...
- return repository.login(creds, workspaceName);
- }
-
- protected String getWorkspaceName( String name ) {
- assert name != null;
- int index = getIndexOfLastWorkspaceDelimiter(name);
- if (index == -1) return null;
- if ((index + 1) == name.length()) return null; // delim is the last character
- return name.substring(index + 1);
- }
-
- protected String getRepositoryName( String name ) {
- assert name != null;
- int index = getIndexOfLastWorkspaceDelimiter(name);
- if (index == -1) return name; // no delim
- if ((index + 1) == name.length()) return name.substring(0, index); // delim as last character
- return name.substring(0, index);
- }
-
- protected int getIndexOfLastWorkspaceDelimiter( String name ) {
- int index = -1;
- for (char delim : this.workspaceDelims) {
- int i = name.lastIndexOf(delim);
- index = Math.max(index, i);
- }
- return index;
- }
-
-}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/services/RepositoryNodePath.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/RepositoryNodePath.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/services/RepositoryNodePath.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,104 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.util.HashCode;
-
-/**
- * @author Randall Hauch
- */
-@Immutable
-public class RepositoryNodePath {
-
- protected static final Pattern PATTERN = Pattern.compile("([^:/]):(/.*)");
-
- public static RepositoryNodePath parse( String path, String defaultRepositoryWorkspaceName ) {
- Matcher matcher = PATTERN.matcher(path);
- if (matcher.matches()) {
- try {
- return new RepositoryNodePath(matcher.group(1), matcher.group(2));
- } catch (Throwable t) {
- throw new IllegalArgumentException(ServicesI18n.invalidRepositoryNodePath.text(path, t.getMessage()));
- }
- }
- return new RepositoryNodePath(defaultRepositoryWorkspaceName, path);
-
- }
-
- private final String repositoryName;
- private final String nodePath;
- private final int hc;
-
- public RepositoryNodePath( String repositoryName, String nodePath ) {
- this.repositoryName = repositoryName;
- this.nodePath = nodePath;
- this.hc = HashCode.compute(this.repositoryName, this.nodePath);
- }
-
- /**
- * @return nodePath
- */
- public String getNodePath() {
- return this.nodePath;
- }
-
- /**
- * @return repositoryName
- */
- public String getRepositoryWorkspaceName() {
- return this.repositoryName;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return this.hc;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals( Object obj ) {
- if (obj == this) return true;
- if (obj instanceof RepositoryNodePath) {
- RepositoryNodePath that = (RepositoryNodePath)obj;
- if (!this.repositoryName.equals(that.repositoryName)) return false;
- if (!this.nodePath.equals(that.nodePath)) return false;
- return true;
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return this.repositoryName + ":" + this.nodePath;
- }
-}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/services/ServiceAdministrator.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/ServiceAdministrator.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/services/ServiceAdministrator.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,144 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import java.util.concurrent.TimeUnit;
-import net.jcip.annotations.ThreadSafe;
-
-/**
- * Contract defining an administrative interface for controlling the running state of a service.
- * @author Randall Hauch
- */
-@ThreadSafe
-public interface ServiceAdministrator {
-
- /**
- * The available states.
- * @author Randall Hauch
- */
- public static enum State {
- STARTED,
- PAUSED,
- SHUTDOWN;
- }
-
- /**
- * Return the current state of this system.
- * @return the current state
- */
- public State getState();
-
- /**
- * Set the state of the system. This method does nothing if the desired state matches the current state.
- * @param state the desired state
- * @return this object for method chaining purposes
- * @see #setState(String)
- * @see #start()
- * @see #pause()
- * @see #shutdown()
- */
- public ServiceAdministrator setState( State state );
-
- /**
- * Set the state of the system. This method does nothing if the desired state matches the current state.
- * @param state the desired state in string form
- * @return this object for method chaining purposes
- * @throws IllegalArgumentException if the specified state string is null or does not match one of the predefined
- * {@link State predefined enumerated values}
- * @see #setState(State)
- * @see #start()
- * @see #pause()
- * @see #shutdown()
- */
- public ServiceAdministrator setState( String state );
-
- /**
- * Start monitoring and sequence the events. This method can be called multiple times, including after the system is
- * {@link #pause() paused}. However, once the system is {@link #shutdown() shutdown}, it cannot be started or paused.
- * @return this object for method chaining purposes
- * @throws IllegalStateException if called when the system has been {@link #shutdown() shutdown}.
- * @see #pause()
- * @see #shutdown()
- * @see #isStarted()
- */
- public ServiceAdministrator start();
-
- /**
- * Temporarily stop monitoring and sequencing events. This method can be called multiple times, including after the system is
- * {@link #start() started}. However, once the system is {@link #shutdown() shutdown}, it cannot be started or paused.
- * @return this object for method chaining purposes
- * @throws IllegalStateException if called when the system has been {@link #shutdown() shutdown}.
- * @see #start()
- * @see #shutdown()
- * @see #isPaused()
- */
- public ServiceAdministrator pause();
-
- /**
- * Permanently stop monitoring and sequencing events. This method can be called multiple times, but only the first call has an
- * effect. Once the system has been shutdown, it may not be {@link #start() restarted} or {@link #pause() paused}.
- * @return this object for method chaining purposes
- * @see #start()
- * @see #pause()
- * @see #isShutdown()
- */
- public ServiceAdministrator shutdown();
-
- /**
- * Blocks until all work has completed execution after a shutdown request, or the timeout occurs, or the current thread is
- * interrupted, whichever happens first.
- * @param timeout the maximum time to wait
- * @param unit the time unit of the timeout argument
- * @return <tt>true</tt> if this service terminated and <tt>false</tt> if the timeout elapsed before termination
- * @throws InterruptedException if interrupted while waiting
- */
- boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException;
-
- /**
- * Return whether this system has been started and is currently running.
- * @return true if started and currently running, or false otherwise
- * @see #start()
- * @see #pause()
- * @see #isPaused()
- * @see #isShutdown()
- */
- public boolean isStarted();
-
- /**
- * Return whether this system is currently paused.
- * @return true if currently paused, or false otherwise
- * @see #pause()
- * @see #start()
- * @see #isStarted()
- * @see #isShutdown()
- */
- public boolean isPaused();
-
- /**
- * Return whether this system is stopped and unable to be restarted.
- * @return true if currently shutdown, or false otherwise
- * @see #shutdown()
- * @see #isPaused()
- * @see #isStarted()
- */
- public boolean isShutdown();
-}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/services/ServicesI18n.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/ServicesI18n.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/services/ServicesI18n.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,101 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import org.jboss.dna.common.i18n.I18n;
-
-/**
- * @author Randall Hauch
- */
-public final class ServicesI18n {
-
- static {
- try {
- I18n.initialize(ServicesI18n.class);
- } catch (final Exception err) {
- System.err.println(err);
- }
- }
-
- public static I18n invalidStateString;
- public static I18n serviceShutdowAndMayNotBeStarted;
- public static I18n serviceShutdowAndMayNotBePaused;
- public static I18n unableToFindRepositoryInJndi;
- public static I18n errorProcessingEvents;
- public static I18n errorFindingPropertyNameInPropertyAddedEvent;
- public static I18n errorFindingPropertyNameInPropertyChangedEvent;
- public static I18n errorFindingPropertyNameInPropertyRemovedEvent;
-
- public static I18n unableToObtainJsr94RuleAdministrator;
- public static I18n errorUsingJsr94RuleAdministrator;
- public static I18n unableToObtainJsr94ServiceProvider;
- public static I18n errorAddingOrUpdatingRuleSet;
- public static I18n errorRollingBackRuleSetAfterUpdateFailed;
- public static I18n errorReadingRulesAndProperties;
- public static I18n errorDeregisteringRuleSetBeforeUpdatingIt;
- public static I18n errorRecreatingRuleSet;
- public static I18n errorRemovingRuleSet;
- public static I18n errorRemovingRuleSetUponShutdown;
- public static I18n unableToFindRuleSet;
- public static I18n errorExecutingRuleSetWithGlobalsAndFacts;
- public static I18n unableToBuildRuleSetRegularExpressionPattern;
-
- public static I18n errorObtainingSessionToRepositoryWorkspace;
- public static I18n errorWritingProblemsOnRuleSet;
-
- public static I18n sequencingServiceName;
- public static I18n unableToChangeExecutionContextWhileRunning;
- public static I18n unableToStartSequencingServiceWithoutExecutionContext;
- public static I18n errorWhileSequencingNode;
- public static I18n errorInRepositoryWhileSequencingNode;
- public static I18n errorFindingSequencersToRunAgainstNode;
- public static I18n errorInRepositoryWhileFindingSequencersToRunAgainstNode;
- public static I18n executionContextHasBeenClosed;
- public static I18n sequencerTask;
- public static I18n sequencerSubtask;
- public static I18n unableToFindPropertyForSequencing;
- public static I18n sequencingPropertyOnNode;
- public static I18n writingOutputSequencedFromPropertyOnNodes;
-
- public static I18n errorReadingPropertiesFromContainerNode;
- public static I18n requiredPropertyOnNodeWasExpectedToBeStringValue;
- public static I18n optionalPropertyOnNodeWasExpectedToBeStringValue;
- public static I18n requiredPropertyOnNodeWasExpectedToBeStringArrayValue;
- public static I18n optionalPropertyOnNodeWasExpectedToBeStringArrayValue;
- public static I18n requiredPropertyOnNodeCouldNotBeRead;
- public static I18n optionalPropertyOnNodeCouldNotBeRead;
- public static I18n requiredPropertyIsMissingFromNode;
- public static I18n errorGettingRequiredPropertyFromNode;
- public static I18n errorGettingOptionalPropertyFromNode;
- public static I18n errorClosingBinaryStreamForPropertyFromNode;
- public static I18n requiredNodeDoesNotExistRelativeToNode;
- public static I18n errorGettingNodeRelativeToNode;
- public static I18n unknownPropertyValueType;
-
- public static I18n pathExpressionIsInvalid;
- public static I18n pathExpressionMayNotBeBlank;
- public static I18n pathExpressionHasInvalidSelect;
- public static I18n pathExpressionHasInvalidMatch;
-
- public static I18n invalidRepositoryNodePath;
-
-}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/services/SessionFactory.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/SessionFactory.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/services/SessionFactory.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,35 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-/**
- * @author Randall Hauch
- */
-public interface SessionFactory {
-
- Session createSession( String name ) throws RepositoryException;
-
-}
Added: trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
===================================================================
--- trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties (rev 0)
+++ trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,61 @@
+invalidStateString = Invalid state parameter "{0}"
+serviceShutdowAndMayNotBeStarted = The {0} has been shutdown and may not be (re)started
+serviceShutdowAndMayNotBePaused = The {0} has been shutdown and my not be paused
+unableToFindRepositoryInJndi = Unable to find a JCR repository in JNDI at '{0}'
+errorProcessingEvents = Error processing events from {0}
+errorFindingPropertyNameInPropertyAddedEvent = Error finding the name of the added property in the event path {0}
+errorFindingPropertyNameInPropertyChangedEvent = Error finding the name of the changed property in the event path {0}
+errorFindingPropertyNameInPropertyRemovedEvent = Error finding the name of the removed property in the event path {0}
+
+unableToObtainJsr94RuleAdministrator = Unable to obtain the rule administrator for JSR-94 service provider {0} ({1}) while adding/updating rule set {2}
+errorUsingJsr94RuleAdministrator = Error using rule administrator for JSR-94 service provider {0} ({1}) while adding/updating rule set {2}
+unableToObtainJsr94ServiceProvider = Error using rule administrator for JSR-94 service provider {0} ({1})
+errorAddingOrUpdatingRuleSet = Error adding/updating rule set '{0}'
+errorRollingBackRuleSetAfterUpdateFailed = Error rolling back rule set '{0}' after new rule set failed
+errorReadingRulesAndProperties = Error reading the rules and properties while adding/updating rule set '{0}'
+errorDeregisteringRuleSetBeforeUpdatingIt = Error deregistering rule set '{0}' before updating it
+errorRecreatingRuleSet = Error (re)creating the rule set '{0}'
+errorRemovingRuleSet = Error removing rule set '{0}'
+errorRemovingRuleSetUponShutdown = Error removing rule set '{0}' upon shutdown
+unableToFindRuleSet = Unable to find rule set with name '{0}'
+errorExecutingRuleSetWithGlobalsAndFacts = Error executing rule set '{0}' and with globals {1} and facts {2}
+unableToBuildRuleSetRegularExpressionPattern = Unable to build the rule set name pattern "{0}" using the supplied absolute path ("{1}"): {2}
+
+errorObtainingSessionToRepositoryWorkspace = Error obtaining JCR session to repository workspace {0}
+errorWritingProblemsOnRuleSet = Error while writing problems on rule set node {0}
+
+sequencingServiceName = Sequencing Service
+unableToChangeExecutionContextWhileRunning = Unable to change the execution context while running
+unableToStartSequencingServiceWithoutExecutionContext = Unable to start the Sequencing Service without an execution context
+errorWhileSequencingNode = Error while sequencer {0} is sequencing node {1}
+errorInRepositoryWhileSequencingNode = Error in repository while sequencer {0} is sequencing node {1}
+errorInRepositoryWhileFindingSequencersToRunAgainstNode = Error in repository while finding sequencers to run against node {0}
+errorFindingSequencersToRunAgainstNode = Error finding sequencers to run against node {0}
+executionContextHasBeenClosed = This execution context has been closed and may not be used to create another session
+sequencerTask = Sequencing {0}
+sequencerSubtask = running {0}
+unableToFindPropertyForSequencing = Unable to find the {0} property while sequencing node {1}
+sequencingPropertyOnNode = Sequencing the {0} property on node {1}
+writingOutputSequencedFromPropertyOnNodes = Writing the output of the sequencing of the {0} property on node {1} to {2} nodes
+
+errorReadingPropertiesFromContainerNode = Error reading properties from property container node {0}
+requiredPropertyOnNodeWasExpectedToBeStringValue = The required {0} property on node {1} was expected to be a string value
+optionalPropertyOnNodeWasExpectedToBeStringValue = The optional {0} property on node {1} was expected to be a string value
+requiredPropertyOnNodeWasExpectedToBeStringArrayValue = The required {0} property on node {1} was expected to be a string array
+optionalPropertyOnNodeWasExpectedToBeStringArrayValue = The optional {0} property on node {1} was expected to be a string array
+requiredPropertyOnNodeCouldNotBeRead = The required {0} property on node {1} could not be read
+optionalPropertyOnNodeCouldNotBeRead = The optional {0} property on node {1} could not be read
+requiredPropertyIsMissingFromNode = The required {0} property is missing from node {1}
+errorGettingRequiredPropertyFromNode = Error while getting the required property {0} from node {1}
+errorGettingOptionalPropertyFromNode = Error while getting the optional property {0} from node {1}
+errorClosingBinaryStreamForPropertyFromNode = Error while closing the binary stream for property {0} on node {1}
+requiredNodeDoesNotExistRelativeToNode = The required node {0} does not exist relative to {1}
+errorGettingNodeRelativeToNode = Error while getting the node {0} (relative to {1})
+unknownPropertyValueType = Property value {0} is of a type ({1}) that is unknown
+
+pathExpressionMayNotBeBlank = The path expression may not be blank
+pathExpressionIsInvalid = The path expression {0} is not valid
+pathExpressionHasInvalidSelect = Invalid select expression '{0}' in the path expression '{1}=>{2}'
+pathExpressionHasInvalidMatch = Invalid match expression '{0}' in the path expression '{1}=>{2}'
+
+invalidRepositoryNodePath = The repository node path '{0}' is not valid: {1}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/observation/NodeChangeTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/observation/NodeChangeTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/observation/NodeChangeTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,65 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.observation;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.jcr.observation.Event;
+import org.jboss.dna.repository.observation.NodeChange;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class NodeChangeTest {
+
+ private String validRepositoryWorkspaceName;
+ private String validAbsolutePath;
+ private int validEventTypes;
+ private Set<String> validModifiedProperties;
+ private Set<String> validRemovedProperties;
+ private NodeChange nodeChange;
+
+ @Before
+ public void beforeEach() throws Exception {
+ validRepositoryWorkspaceName = "repositoryX";
+ validAbsolutePath = "/a/b/c/d";
+ validEventTypes = Event.NODE_ADDED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
+ validModifiedProperties = new HashSet<String>();
+ validRemovedProperties = new HashSet<String>();
+ validModifiedProperties.add("jcr:name");
+ validModifiedProperties.add("jcr:title");
+ validRemovedProperties.add("jcr:mime");
+ nodeChange = new NodeChange(validRepositoryWorkspaceName, validAbsolutePath, validEventTypes, validModifiedProperties, validRemovedProperties);
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldHaveUnmodifiableSetOfModifiedPropertyNames() {
+ nodeChange.getModifiedProperties().clear();
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldHaveUnmodifiableSetOfRemovedPropertyNames() {
+ nodeChange.getRemovedProperties().clear();
+ }
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleInput.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleInput.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleInput.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,79 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.rules;
+
+public final class RuleInput {
+
+ String mimeType = "";
+ String header = "";
+ String fileName = "";
+
+ /**
+ * @return fileName
+ */
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * @return header
+ */
+ public String getHeader() {
+ return header;
+ }
+
+ /**
+ * @return mimeType
+ */
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ /**
+ * @param fileName Sets fileName to the specified value.
+ */
+ public void setFileName( String fileName ) {
+ this.fileName = fileName;
+ }
+
+ /**
+ * @param header Sets header to the specified value.
+ */
+ public void setHeader( String header ) {
+ this.header = header;
+ }
+
+ /**
+ * @param mimeType Sets mimeType to the specified value.
+ */
+ public void setMimeType( String mimeType ) {
+ this.mimeType = mimeType;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return this.fileName + " (" + this.mimeType + ") => " + this.header;
+ }
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleResult.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleResult.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleResult.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.rules;
+
+/**
+ * @author John Verhaeg
+ */
+public final class RuleResult {
+
+ String name;
+
+ public RuleResult( String name ) {
+ this.name = name != null ? name : "";
+ }
+
+ /**
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleServiceTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleServiceTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleServiceTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,248 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.rules;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.component.StandardClassLoaderFactory;
+import org.jboss.dna.common.util.IoUtil;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.repository.rules.InvalidRuleSetException;
+import org.jboss.dna.repository.rules.RuleService;
+import org.jboss.dna.repository.rules.RuleSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class RuleServiceTest {
+
+ protected static final String DROOLS_PROVIDER_CLASSNAME = "org.drools.jsr94.rules.RuleServiceProviderImpl";
+ protected static final String DROOLS_PROVIDER_URI = "http://drools.org/";
+
+ private RuleService ruleService;
+ private ClassLoaderFactory classLoaderFactory;
+
+ protected RuleSet createDroolsRuleSet( String desc ) throws IOException {
+ String name = "SampleRuleSet";
+ String description = desc != null ? desc : "This is a sample rule set that uses Drools";
+ String providerClassname = DROOLS_PROVIDER_CLASSNAME;
+ String providerUri = DROOLS_PROVIDER_URI;
+ String[] providerClasspath = new String[] {};
+ String ruleSetUri = null;
+ URL ruleFile = this.getClass().getResource("/rule_test.dslr");
+ URL dslFile = this.getClass().getResource("/rule_test.dsl");
+ String rules = IoUtil.read(ruleFile.openStream());
+ byte[] dslBytes = IoUtil.readBytes(dslFile.openStream());
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put("javax.rules.admin.RuleExecutionSet.source", "drl"); // as opposed to "xml"
+ properties.put("javax.rules.admin.RuleExecutionSet.dsl", dslBytes);
+ return new RuleSet(name, description, providerClassname, providerClasspath, providerUri, ruleSetUri, rules, properties);
+ }
+
+ protected RuleSet createRuleSetWithInvalidProvider() throws IOException {
+ String name = "SampleRuleSet"; // same name as Drools rule set
+ String description = "This is a sample rule set that uses Drools";
+ String providerClassname = DROOLS_PROVIDER_CLASSNAME;
+ String providerUri = DROOLS_PROVIDER_URI + "this/is/incorrect";
+ String[] providerClasspath = new String[] {};
+ String ruleSetUri = null;
+ URL ruleFile = this.getClass().getResource("/rule_test.dslr");
+ URL dslFile = this.getClass().getResource("/rule_test.dsl");
+ String rules = IoUtil.read(ruleFile.openStream());
+ byte[] dslBytes = IoUtil.readBytes(dslFile.openStream());
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put("javax.rules.admin.RuleExecutionSet.source", "drl"); // as opposed to "xml"
+ properties.put("javax.rules.admin.RuleExecutionSet.dsl", dslBytes);
+ return new RuleSet(name, description, providerClassname, providerClasspath, providerUri, ruleSetUri, rules, properties);
+ }
+
+ @Before
+ public void beforeEach() throws Exception {
+ this.ruleService = new RuleService();
+ this.classLoaderFactory = new StandardClassLoaderFactory();
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ this.ruleService.getAdministrator().shutdown();
+ }
+
+ @Test
+ public void shouldHaveDefaultClasspathFactoryUponConstruction() {
+ assertThat(ruleService.getClassLoaderFactory(), is(notNullValue()));
+ assertThat(ruleService.getClassLoaderFactory(), is(sameInstance(RuleService.DEFAULT_CLASSLOADER_FACTORY)));
+ }
+
+ @Test
+ public void shouldHaveLoggerUponConstruction() {
+ assertThat(ruleService.getLogger(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldHaveEmptyRuleSetCollectionUponConstruction() {
+ assertThat(ruleService.getRuleSets(), is(notNullValue()));
+ assertThat(ruleService.getRuleSets().isEmpty(), is(true));
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldReturnUnmodifiableCollectionOfRuleSets() {
+ ruleService.getRuleSets().add(null);
+ }
+
+ @Test
+ public void shouldSetClassLoaderFactoryToDefaultWhenPassedNull() {
+ assertThat(ruleService.getClassLoaderFactory(), is(sameInstance(RuleService.DEFAULT_CLASSLOADER_FACTORY)));
+ ruleService.setClassLoaderFactory(classLoaderFactory);
+ assertThat(ruleService.getClassLoaderFactory(), is(sameInstance(classLoaderFactory)));
+ ruleService.setClassLoaderFactory(null);
+ assertThat(ruleService.getClassLoaderFactory(), is(sameInstance(RuleService.DEFAULT_CLASSLOADER_FACTORY)));
+ }
+
+ @Test
+ public void shouldSetLoggerToDefaultWhenPassedNull() {
+ Logger defaultLogger = ruleService.getLogger();
+ assertThat(ruleService.getLogger(), is(notNullValue()));
+ Logger orgLogger = Logger.getLogger("org");
+ ruleService.setLogger(orgLogger);
+ assertThat(ruleService.getLogger().getName(), is(orgLogger.getName()));
+ assertThat(ruleService.getLogger(), is(sameInstance(orgLogger)));
+ ruleService.setLogger(null);
+ assertThat(ruleService.getLogger().getName(), is(defaultLogger.getName()));
+ assertThat(ruleService.getLogger(), is(not(orgLogger)));
+ }
+
+ @Test( expected = InvalidRuleSetException.class )
+ public void shouldNotAddInvalidRuleSet() throws Exception {
+ ruleService.addRuleSet(createRuleSetWithInvalidProvider());
+
+ }
+
+ @Test
+ public void shouldAddValidRuleSet() throws Exception {
+ int numRuleSetsBefore = ruleService.getRuleSets().size();
+ RuleSet validRuleSet = createDroolsRuleSet(null);
+ assertThat(ruleService.addRuleSet(validRuleSet), is(true));
+ assertThat(ruleService.getRuleSets().size(), is(numRuleSetsBefore + 1));
+ }
+
+ @Test
+ public void shouldNotUpdateValidRuleSetWithInvalidRuleSet() throws Exception {
+ RuleSet validRuleSet = createDroolsRuleSet(null);
+ final String ruleSetName = validRuleSet.getName();
+
+ assertThat(ruleService.addRuleSet(validRuleSet), is(true));
+ assertThat(ruleService.getRuleSets().size(), is(1));
+ assertThat(ruleService.getRuleSets().iterator().next(), is(validRuleSet));
+ // Verify this rule set works ...
+ executeRuleSet(ruleSetName);
+
+ // Try to update the rule set with something that's invalid ...
+ RuleSet invalidRuleSet = createRuleSetWithInvalidProvider();
+ assertThat(invalidRuleSet.getName(), is(ruleSetName));
+ assertThat(invalidRuleSet.getName(), is(validRuleSet.getName()));
+ try {
+ ruleService.addRuleSet(invalidRuleSet);
+ fail("Should not get here");
+ } catch (InvalidRuleSetException e) {
+ // This is expected since it was a bad rule set ...
+ }
+
+ // Verify the original rule set is still there and still works ...
+ assertThat(ruleService.getRuleSets().size(), is(1));
+ assertThat(ruleService.getRuleSets().iterator().next(), is(validRuleSet));
+ executeRuleSet(ruleSetName);
+ }
+
+ @Test
+ public void shouldModifyExistingRuleSetWhenAddedOnlyWhenChanged() throws Exception {
+ int numRuleSetsBefore = ruleService.getRuleSets().size();
+ RuleSet validRuleSet = createDroolsRuleSet(null);
+ assertThat(ruleService.addRuleSet(validRuleSet), is(true));
+ assertThat(ruleService.getRuleSets().size(), is(numRuleSetsBefore + 1));
+
+ // Try to add an unchanged rule set ...
+ RuleSet validRuleSet2 = createDroolsRuleSet(null);
+ assertThat(validRuleSet2.hasChanged(validRuleSet), is(false));
+ assertThat(ruleService.addRuleSet(validRuleSet2), is(false));
+ assertThat(ruleService.getRuleSets().size(), is(numRuleSetsBefore + 1));
+
+ // Try to add a changed rule set ...
+ RuleSet validRuleSet3 = createDroolsRuleSet("This is an alternative description that causes it to be changed");
+ assertThat(validRuleSet3.hasChanged(validRuleSet), is(true));
+ assertThat(ruleService.addRuleSet(validRuleSet3), is(true));
+ assertThat(ruleService.getRuleSets().size(), is(numRuleSetsBefore + 1));
+ }
+
+ @Test
+ public void shouldExecuteRuleSet() throws Exception {
+ RuleSet validRuleSet = createDroolsRuleSet(null);
+ assertThat(ruleService.addRuleSet(validRuleSet), is(true));
+
+ executeRuleSet(validRuleSet.getName());
+ }
+
+ /**
+ * @param validRuleSet
+ */
+ protected void executeRuleSet( String ruleSetName ) {
+ // Create some simple fact objects ...
+ RuleInput info = new RuleInput();
+ info.setFileName("someOtherInput.dsl");
+ info.setHeader("This is the sequencer header");
+ info.setMimeType("text");
+
+ // Run the rules ...
+ Set<String> output = new LinkedHashSet<String>();
+ Map<String, Object> globals = new HashMap<String, Object>();
+ globals.put("output", output);
+
+ List<?> results = ruleService.executeRules(ruleSetName, globals, info);
+ assertThat(results, is(notNullValue()));
+ assertThat(results.isEmpty(), is(false));
+ assertThat(results.size(), is(2));
+ assertTrue(results.get(0) instanceof RuleResult || results.get(1) instanceof RuleResult);
+ // Object result = results.get(0);
+ // assertThat(result, is(instanceOf(RuleResult.class)));
+ assertThat(output.isEmpty(), is(false));
+ Object sequencer = output.iterator().next();
+ assertThat(sequencer, is(instanceOf(String.class)));
+ assertThat(((String)sequencer), is("A"));
+ }
+
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleSetTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleSetTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/rules/RuleSetTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,299 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.rules;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertThat;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import org.jboss.dna.common.util.IoUtil;
+import org.jboss.dna.repository.rules.RuleSet;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class RuleSetTest {
+
+ private RuleSet ruleSet;
+ private String validName;
+ private String validDescription;
+ private String validClassname;
+ private String[] validClasspath;
+ private String validProviderUri;
+ private String validRuleSetUri;
+ private String validRules;
+ private Map<String, Object> validProperties;
+
+ @Before
+ public void beforeEach() throws Exception {
+ this.validName = "This is a valid name";
+ this.validDescription = "This is a valid description";
+ this.validClassname = "com.acme.SuperDuper";
+ this.validClasspath = new String[] {"classpath1", "classpath2"};
+ this.validProviderUri = "http://www.acme.com/super/duper/rules_engine";
+ this.validRuleSetUri = "com.something.whatever doesn't really need to be a URI";
+ this.validRules = "when something is true then cheer";
+ this.validProperties = new HashMap<String, Object>();
+ this.validProperties.put("key1", "value1");
+ this.validProperties.put("key2", null);
+ this.validProperties.put("key3", "value3".getBytes());
+ this.ruleSet = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullName() {
+ new RuleSet(null, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowEmptyName() {
+ new RuleSet("", validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankName() {
+ new RuleSet(" \t ", validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test
+ public void shouldTrimName() {
+ validName = " this is a valid name with leading and trailing whitespace ";
+ ruleSet = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(ruleSet.getName(), is(validName.trim()));
+ }
+
+ @Test
+ public void shouldAllowNullOrEmptyOrBlankDescriptionAndShouldReplaceWithEmptyString() {
+ ruleSet = new RuleSet(validName, null, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(ruleSet.getDescription(), is(""));
+ ruleSet = new RuleSet(validName, "", validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(ruleSet.getDescription(), is(""));
+ ruleSet = new RuleSet(validName, " \t ", validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(ruleSet.getDescription(), is(""));
+ }
+
+ @Test
+ public void shouldTrimDescription() {
+ ruleSet = new RuleSet(validName, " valid ", validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(ruleSet.getDescription(), is("valid"));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullClassname() {
+ new RuleSet(validName, validDescription, null, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowEmptyClassname() {
+ new RuleSet(validName, validDescription, "", validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankClassname() {
+ new RuleSet(validName, validDescription, " ", validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowClassnameThatDoesNotFollowJavaNamingRules() {
+ new RuleSet(validName, validDescription, "not a valid classname", validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test
+ public void shouldAllowNullOrEmptyClasspath() {
+ new RuleSet(validName, validDescription, validClassname, null, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test
+ public void shouldRemoveNullOrBlankClasspathItems() {
+ new RuleSet(validName, validDescription, validClassname, new String[] {}, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test
+ public void shouldRemoveDuplicateClasspathItemsInCaseSensitiveManner() {
+ validClasspath = new String[] {"path1", "path2", "path1", "path3", "path2"};
+ ruleSet = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(ruleSet.getComponentClasspathArray(), is(new String[] {"path1", "path2", "path3"}));
+
+ validClasspath = new String[] {"path1", "path2", "path1", "path3", "Path2"};
+ ruleSet = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(ruleSet.getComponentClasspathArray(), is(new String[] {"path1", "path2", "path3", "Path2"}));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullProviderUri() {
+ new RuleSet(validName, validDescription, validClassname, validClasspath, null, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowEmptyProviderUri() {
+ new RuleSet(validName, validDescription, validClassname, validClasspath, "", validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankProviderUri() {
+ new RuleSet(validName, validDescription, validClassname, validClasspath, " \t ", validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test
+ public void shouldUseNameInPlaceOfNullRuleSetUri() {
+ ruleSet = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, null, validRules, validProperties);
+ assertThat(ruleSet.getRuleSetUri(), is(ruleSet.getName()));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowEmptyRuleSetUri() {
+ new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, "", validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankRuleSetUri() {
+ new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, " \t ", validRules, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullRules() {
+ new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, null, validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowEmptyRules() {
+ new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, "", validProperties);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankRules() {
+ new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, " \t ", validProperties);
+ }
+
+ @Test
+ public void shouldAllowNullOrEmptyProperties() {
+ validProperties = null;
+ ruleSet = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(ruleSet.getProperties(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldWrapByteArrayPropertyValuesWithInputStreamInExecutionSetProperties() throws Exception {
+ Map<Object, Object> executionSetProps = ruleSet.getExecutionSetProperties();
+ assertThat(executionSetProps.size(), is(ruleSet.getProperties().size()));
+ assertThat(executionSetProps.keySet(), is((Set<Object>)new HashSet<Object>(ruleSet.getProperties().keySet())));
+ Iterator<Map.Entry<Object, Object>> executionSetPropIter = executionSetProps.entrySet().iterator();
+ Iterator<Map.Entry<String, Object>> propIter = ruleSet.getProperties().entrySet().iterator();
+ while (executionSetPropIter.hasNext() && propIter.hasNext()) {
+ Map.Entry<Object, Object> execSetEntry = executionSetPropIter.next();
+ Object execSetKey = execSetEntry.getKey();
+ Object execSetValue = execSetEntry.getValue();
+ Map.Entry<String, Object> propertyEntry = propIter.next();
+ String propertyKey = propertyEntry.getKey();
+ Object propertyValue = propertyEntry.getValue();
+ // Check the entries ...
+ assertThat(execSetKey, is((Object)propertyKey));
+ if (propertyValue instanceof byte[]) {
+ assertThat(execSetValue, is(instanceOf(Reader.class)));
+ String streamValueAsString = IoUtil.read((Reader)execSetValue);
+ String propertyValueAsString = new String((byte[])propertyValue);
+ assertThat(streamValueAsString, is(propertyValueAsString));
+ } else {
+ assertThat(execSetValue, is(propertyValue));
+ }
+ }
+ assertThat(executionSetPropIter.hasNext(), is(false));
+ assertThat(propIter.hasNext(), is(false));
+
+ new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ }
+
+ @Test
+ public void shouldConsiderAnyAttributeDifferencesAsChange() {
+ RuleSet copy = ruleSet.clone();
+ assertThat(copy.hasChanged(ruleSet), is(false));
+ assertThat(copy.hasChanged(copy), is(false));
+
+ copy = new RuleSet(validName + "x", validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(copy.hasChanged(ruleSet), is(true));
+ assertThat(copy.hasChanged(copy), is(false));
+
+ copy = new RuleSet(validName, validDescription + "x", validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(copy.hasChanged(ruleSet), is(true));
+ assertThat(copy.hasChanged(copy), is(false));
+
+ copy = new RuleSet(validName, validDescription, validClassname + "x", validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(copy.hasChanged(ruleSet), is(true));
+ assertThat(copy.hasChanged(copy), is(false));
+
+ copy = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri + "x", validRuleSetUri, validRules, validProperties);
+ assertThat(copy.hasChanged(ruleSet), is(true));
+ assertThat(copy.hasChanged(copy), is(false));
+
+ validClasspath = new String[] {"classpath1", "classpath2x"};
+ copy = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri + "x", validRules, validProperties);
+ assertThat(copy.hasChanged(ruleSet), is(true));
+ assertThat(copy.hasChanged(copy), is(false));
+
+ copy = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules + "x", validProperties);
+ assertThat(copy.hasChanged(ruleSet), is(true));
+ assertThat(copy.hasChanged(copy), is(false));
+
+ validProperties.remove("key1");
+ copy = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(copy.hasChanged(ruleSet), is(true));
+ assertThat(copy.hasChanged(copy), is(false));
+ }
+
+ @Test
+ public void shouldConsiderOnlyNameWhenDeterminingIfSame() {
+ RuleSet copy = ruleSet.clone();
+ assertThat(copy.equals(ruleSet), is(true));
+
+ copy = new RuleSet(validName + "x", validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(copy.equals(ruleSet), is(false));
+
+ copy = new RuleSet(validName, validDescription + "x", validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(copy.equals(ruleSet), is(true));
+
+ copy = new RuleSet(validName, validDescription, validClassname + "x", validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(copy.equals(ruleSet), is(true));
+
+ copy = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri + "x", validRuleSetUri, validRules, validProperties);
+ assertThat(copy.equals(ruleSet), is(true));
+
+ validClasspath = new String[] {"classpath1", "classpath2x"};
+ copy = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri + "x", validRules, validProperties);
+ assertThat(copy.equals(ruleSet), is(true));
+
+ copy = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules + "x", validProperties);
+ assertThat(copy.equals(ruleSet), is(true));
+
+ validProperties.remove("key1");
+ copy = new RuleSet(validName, validDescription, validClassname, validClasspath, validProviderUri, validRuleSetUri, validRules, validProperties);
+ assertThat(copy.equals(ruleSet), is(true));
+ }
+
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,102 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.jcr.Node;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.repository.observation.NodeChange;
+import org.jboss.dna.repository.sequencers.Sequencer;
+import org.jboss.dna.repository.sequencers.SequencerConfig;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.RepositoryNodePath;
+
+/**
+ * A sequencer that can be used for basic unit testing.
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class MockSequencerA implements Sequencer {
+
+ private SequencerConfig config;
+ private AtomicInteger counter = new AtomicInteger();
+ private CountDownLatch latch = new CountDownLatch(0);
+
+ public void setExpectedCount( int numExpected ) {
+ this.latch = new CountDownLatch(numExpected);
+ }
+
+ public boolean awaitExecution( long timeout, TimeUnit unit ) throws InterruptedException {
+ return this.latch.await(timeout, unit);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setConfiguration( SequencerConfig sequencerConfiguration ) {
+ this.config = sequencerConfiguration;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, ExecutionContext context, ProgressMonitor progress ) {
+ try {
+ progress.beginTask(1, CoreI18n.passthrough, "Incrementing counter");
+ // increment the counter and record the progress ...
+ this.counter.incrementAndGet();
+ this.latch.countDown();
+ progress.worked(1);
+ } finally {
+ progress.done();
+ }
+ }
+
+ public int getCounter() {
+ return this.counter.get();
+ }
+
+ public boolean isConfigured() {
+ return this.config != null;
+ }
+
+ /**
+ * @return config
+ */
+ public SequencerConfig getConfiguration() {
+ return this.config;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return (this.config != null ? this.config.getName() : "SampleSequencer") + " [" + this.getCounter() + "]";
+ }
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,102 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.jcr.Node;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.CoreI18n;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.repository.observation.NodeChange;
+import org.jboss.dna.repository.sequencers.Sequencer;
+import org.jboss.dna.repository.sequencers.SequencerConfig;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.RepositoryNodePath;
+
+/**
+ * A sequencer that can be used for basic unit testing.
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class MockSequencerB implements Sequencer {
+
+ private SequencerConfig config;
+ private AtomicInteger counter = new AtomicInteger();
+ private CountDownLatch latch = new CountDownLatch(0);
+
+ public void setExpectedCount( int numExpected ) {
+ this.latch = new CountDownLatch(numExpected);
+ }
+
+ public boolean awaitExecution( long timeout, TimeUnit unit ) throws InterruptedException {
+ return this.latch.await(timeout, unit);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setConfiguration( SequencerConfig sequencerConfiguration ) {
+ this.config = sequencerConfiguration;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, ExecutionContext context, ProgressMonitor progress ) {
+ try {
+ progress.beginTask(1, CoreI18n.passthrough, "Incrementing counter");
+ // increment the counter and record the progress ...
+ this.counter.incrementAndGet();
+ this.latch.countDown();
+ progress.worked(1);
+ } finally {
+ progress.done();
+ }
+ }
+
+ public int getCounter() {
+ return this.counter.get();
+ }
+
+ public boolean isConfigured() {
+ return this.config != null;
+ }
+
+ /**
+ * @return config
+ */
+ public SequencerConfig getConfiguration() {
+ return this.config;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return (this.config != null ? this.config.getName() : "SampleSequencer") + " [" + this.getCounter() + "]";
+ }
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerConfigTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerConfigTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerConfigTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,131 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import org.jboss.dna.repository.sequencers.SequencerConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class SequencerConfigTest {
+
+ private SequencerConfig configA;
+ private SequencerConfig configB;
+ private SequencerConfig configA2;
+ private String validName;
+ private String validDescription;
+ private String validClassname;
+ private String[] validPathExpressions;
+ private String[] validMavenIds;
+
+ @Before
+ public void beforeEach() throws Exception {
+ this.validName = "valid configuration name";
+ this.validDescription = "a sequencer";
+ this.validClassname = MockSequencerA.class.getName();
+ this.validPathExpressions = new String[] {"/a/b/c/d[e/@attribute] => ."};
+ this.validMavenIds = new String[] {"com.acme:configA:1.0,com.acme:configB:1.0"};
+ this.configA = new SequencerConfig("configA", validDescription, MockSequencerA.class.getName(), validMavenIds, validPathExpressions);
+ this.configB = new SequencerConfig("configB", validDescription, MockSequencerB.class.getName(), validMavenIds, validPathExpressions);
+ this.configA2 = new SequencerConfig("conFigA", validDescription, MockSequencerA.class.getName(), validMavenIds, validPathExpressions);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullNameInConstructor() {
+ new SequencerConfig(null, validDescription, validClassname, validMavenIds, validPathExpressions);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowEmptyNameInConstructor() {
+ new SequencerConfig("", validDescription, validClassname, validMavenIds, validPathExpressions);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankNameInConstructor() {
+ new SequencerConfig(" \t", validDescription, validClassname, validMavenIds, validPathExpressions);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullClassNameInConstructor() {
+ new SequencerConfig(validName, validDescription, null, validMavenIds, validPathExpressions);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowEmptyClassNameInConstructor() {
+ new SequencerConfig(validName, validDescription, "", validMavenIds, validPathExpressions);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankClassNameInConstructor() {
+ new SequencerConfig(validName, validDescription, " \t", validMavenIds, validPathExpressions);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowInvalidClassNameInConstructor() {
+ new SequencerConfig(validName, validDescription, "12.this is not a valid classname", validMavenIds, validPathExpressions);
+ }
+
+ @Test
+ public void shouldConsiderSameIfNamesAreEqualIgnoringCase() {
+ assertThat(configA.equals(configA2), is(true));
+ }
+
+ @Test
+ public void shouldConsiderNotSameIfNamesAreNotEqualIgnoringCase() {
+ assertThat(configA.equals(configB), is(false));
+ }
+
+ @Test
+ public void shouldNotAddNullOrBlankPathExpressions() {
+ assertThat(SequencerConfig.buildPathExpressionSet(null, "", " ", validPathExpressions[0]).size(), is(1));
+ }
+
+ @Test
+ public void shouldNotAddSamePathExpressionMoreThanOnce() {
+ assertThat(SequencerConfig.buildPathExpressionSet(validPathExpressions[0], validPathExpressions[0], validPathExpressions[0]).size(), is(1));
+ }
+
+ @Test
+ public void shouldHaveNonNullPathExpressionCollectionWhenThereAreNoPathExpressions() {
+ configA = new SequencerConfig("configA", validDescription, validClassname, validMavenIds);
+ assertThat(configA.getPathExpressions().size(), is(0));
+ }
+
+ @Test
+ public void shouldSetClasspathWithValidMavenIds() {
+ assertThat(configA.getComponentClasspath().size(), is(validMavenIds.length));
+ assertThat(configA.getComponentClasspathArray(), is(validMavenIds));
+ }
+
+ @Test
+ public void shouldGetNonNullSequencerClasspathWhenEmpty() {
+ configA = new SequencerConfig("configA", validDescription, validClassname, null, validPathExpressions);
+ assertThat(configA.getComponentClasspath().size(), is(0));
+ assertThat(configA.getComponentClasspathArray().length, is(0));
+ }
+
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerPathExpressionTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerPathExpressionTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerPathExpressionTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,356 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import org.jboss.dna.repository.sequencers.InvalidSequencerPathExpression;
+import org.jboss.dna.repository.sequencers.SequencerPathExpression;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class SequencerPathExpressionTest {
+
+ private SequencerPathExpression expr;
+
+ @Before
+ public void beforeEach() throws Exception {
+ expr = new SequencerPathExpression(".*", "/output");
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotCompileNullExpression() {
+ SequencerPathExpression.compile(null);
+ }
+
+ @Test( expected = InvalidSequencerPathExpression.class )
+ public void shouldNotCompileZeroLengthExpression() {
+ SequencerPathExpression.compile("");
+ }
+
+ @Test( expected = InvalidSequencerPathExpression.class )
+ public void shouldNotCompileBlankExpression() {
+ SequencerPathExpression.compile(" ");
+ }
+
+ @Test
+ public void shouldCompileExpressionWithOnlySelectionExpression() {
+ expr = SequencerPathExpression.compile("/a/b/c");
+ assertThat(expr, is(notNullValue()));
+ assertThat(expr.getSelectExpression(), is("/a/b/c"));
+ assertThat(expr.getOutputExpression(), is(SequencerPathExpression.DEFAULT_OUTPUT_EXPRESSION));
+ }
+
+ @Test( expected = InvalidSequencerPathExpression.class )
+ public void shouldNotCompileExpressionWithSelectionExpressionAndDelimiterAndNoOutputExpression() {
+ SequencerPathExpression.compile("/a/b/c=>");
+ }
+
+ @Test
+ public void shouldCompileExpressionWithSelectionExpressionAndDelimiterAndOutputExpression() {
+ expr = SequencerPathExpression.compile("/a/b/c=>.");
+ assertThat(expr, is(notNullValue()));
+ assertThat(expr.getSelectExpression(), is("/a/b/c"));
+ assertThat(expr.getOutputExpression(), is("."));
+
+ expr = SequencerPathExpression.compile("/a/b/c=>/x/y");
+ assertThat(expr, is(notNullValue()));
+ assertThat(expr.getSelectExpression(), is("/a/b/c"));
+ assertThat(expr.getOutputExpression(), is("/x/y"));
+ }
+
+ @Test
+ public void shouldCompileExpressionWithExtraWhitespace() {
+ expr = SequencerPathExpression.compile(" /a/b/c => . ");
+ assertThat(expr, is(notNullValue()));
+ assertThat(expr.getSelectExpression(), is("/a/b/c"));
+ assertThat(expr.getOutputExpression(), is("."));
+
+ expr = SequencerPathExpression.compile(" /a/b/c => /x/y ");
+ assertThat(expr, is(notNullValue()));
+ assertThat(expr.getSelectExpression(), is("/a/b/c"));
+ assertThat(expr.getOutputExpression(), is("/x/y"));
+ }
+
+ @Test
+ public void shouldCompileExpressionWithIndexes() {
+ assertThat(SequencerPathExpression.compile("/a/b[0]/c[1]/d/e"), is(notNullValue()));
+ assertThat(SequencerPathExpression.compile("/a/b[0]/c[1]/d/e[2]"), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldNotRemoveUsedPredicates() {
+ assertThat(expr.removeUnusedPredicates("/a/b/c"), is("/a/b/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[0]/c"), is("/a/b[0]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[1]/c"), is("/a/b[1]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[10]/c"), is("/a/b[10]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[100]/c"), is("/a/b[100]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[1000]/c"), is("/a/b[1000]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[]/c"), is("/a/b[]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[*]/c"), is("/a/b[*]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[1,2]/c"), is("/a/b[1,2]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[1,2,3,4,5]/c"), is("/a/b[1,2,3,4,5]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b/c[@title]"), is("/a/b/c[@title]"));
+ assertThat(expr.removeUnusedPredicates("/a/b/c[d/e/@title]"), is("/a/b/c[d/e/@title]"));
+ assertThat(expr.removeUnusedPredicates("/a/(b/c)[(d|e)/(f|g)/@something]"), is("/a/(b/c)[(d|e)/(f|g)/@something]"));
+ // These are legal, but aren't really useful ...
+ assertThat(expr.removeUnusedPredicates("/a/b[1][2][3]/c"), is("/a/b[1][2][3]/c"));
+ }
+
+ @Test
+ public void shouldRemoveUnusedPredicates() {
+ assertThat(expr.removeUnusedPredicates("/a/b[-1]/c"), is("/a/b/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[@name='wacky']/c"), is("/a/b/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[3][@name='wacky']/c"), is("/a/b[3]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[3][@name]/c"), is("/a/b[3]/c"));
+ assertThat(expr.removeUnusedPredicates("/a/b[length(@name)=3]/c"), is("/a/b/c"));
+ }
+
+ @Test
+ public void shouldRemoveAllPredicates() {
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b/c"), is("/a/b/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[0]/c"), is("/a/b[0]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[1]/c"), is("/a/b[1]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[10]/c"), is("/a/b[10]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[100]/c"), is("/a/b[100]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[1000]/c"), is("/a/b[1000]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[]/c"), is("/a/b[]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[*]/c"), is("/a/b[*]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b/c[@title]"), is("/a/b/c"));
+ // These are legal, but aren't really useful ...
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[1][2][3]/c"), is("/a/b[1][2][3]/c"));
+
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[-1]/c"), is("/a/b/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[@name='wacky']/c"), is("/a/b/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[3][@name='wacky']/c"), is("/a/b[3]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[3][@name]/c"), is("/a/b[3]/c"));
+ assertThat(expr.removeAllPredicatesExceptIndexes("/a/b[length(@name)=3]/c"), is("/a/b/c"));
+ }
+
+ @Test
+ public void shouldReplaceAllXPathPatterns() {
+ assertThat(expr.replaceXPathPatterns("/a/b[3]/c"), is("/a/b\\[3\\]/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[*]/c"), is("/a/b(?:\\[\\d+\\])?/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[]/c"), is("/a/b(?:\\[\\d+\\])?/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[0]/c"), is("/a/b(?:\\[0\\])?/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[0,1,2,4]/c"), is("/a/b(?:\\[(?:1|2|4)\\])?/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[1,2,4,0]/c"), is("/a/b(?:\\[(?:1|2|4)\\])?/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[1,2,0,4]/c"), is("/a/b(?:\\[(?:1|2|4)\\])?/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[0,1,2,0,4,0]/c"), is("/a/b(?:\\[(?:1|2|4)\\])?/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[1,2,4]/c"), is("/a/b\\[(?:1|2|4)\\]/c"));
+ assertThat(expr.replaceXPathPatterns("/a/b[@param]"), is("/a/b/@param"));
+ assertThat(expr.replaceXPathPatterns("/a/b[3][@param]"), is("/a/b\\[3\\]/@param"));
+ assertThat(expr.replaceXPathPatterns("/a/b[c/d/@param]"), is("/a/b/c/d/@param"));
+
+ assertThat(expr.replaceXPathPatterns("/a/(b|c|d)/e"), is("/a/(b|c|d)/e"));
+ assertThat(expr.replaceXPathPatterns("/a/(b||c|d)/e"), is("/a/(b|c|d)/e"));
+ assertThat(expr.replaceXPathPatterns("/a/(b|||c|d)/e"), is("/a/(b|c|d)/e"));
+ assertThat(expr.replaceXPathPatterns("/a/(|b|c|d)/e"), is("/a(/(b|c|d))?/e"));
+ assertThat(expr.replaceXPathPatterns("/a/(b|c|d|)/e"), is("/a(/(b|c|d))?/e"));
+ assertThat(expr.replaceXPathPatterns("/a/(b|c|d)[]/e"), is("/a/(b|c|d)(?:\\[\\d+\\])?/e"));
+ assertThat(expr.replaceXPathPatterns("/a/(b|c[2]|d[])/e"), is("/a/(b|c\\[2\\]|d(?:\\[\\d+\\])?)/e"));
+ assertThat(expr.replaceXPathPatterns("/a/(b|c/d|e)/f"), is("/a/(b|c/d|e)/f"));
+ assertThat(expr.replaceXPathPatterns("/a/(b/c)[(d|e)/(f|g)/@something]"), is("/a/(b/c)/(d|e)/(f|g)/@something"));
+
+ assertThat(expr.replaceXPathPatterns("/a/*/f"), is("/a/[^/]*/f"));
+ assertThat(expr.replaceXPathPatterns("/a//f"), is("/a(/[^/]*)*/f"));
+ assertThat(expr.replaceXPathPatterns("/a///f"), is("/a(/[^/]*)*/f"));
+ assertThat(expr.replaceXPathPatterns("/a/////f"), is("/a(/[^/]*)*/f"));
+ }
+
+ protected void assertNotMatches( SequencerPathExpression.Matcher matcher ) {
+ assertThat(matcher, is(notNullValue()));
+ assertThat(matcher.getSelectedPath(), is(nullValue()));
+ assertThat(matcher.getOutputPath(), is(nullValue()));
+ assertThat(matcher.matches(), is(false));
+ }
+
+ protected void assertMatches( SequencerPathExpression.Matcher matcher, String selectedPath, String outputPath ) {
+ assertThat(matcher, is(notNullValue()));
+ assertThat(matcher.getSelectedPath(), is(selectedPath));
+ assertThat(matcher.getOutputPath(), is(outputPath));
+ if (selectedPath == null) {
+ assertThat(matcher.matches(), is(false));
+ } else {
+ assertThat(matcher.matches(), is(true));
+ }
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithoutRegardToCase() {
+ expr = SequencerPathExpression.compile("/a/b/c/d/e[@something] => .");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c/d/e", "/a/b/c/d/e");
+ assertMatches(expr.matcher("/a/b/c/d/E/@something"), "/a/b/c/d/E", "/a/b/c/d/E");
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithExactFullPath() {
+ expr = SequencerPathExpression.compile("/a/b/c/d/e[@something] => .");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c/d/e", "/a/b/c/d/e");
+ assertNotMatches(expr.matcher("/a/b/c/d/E/@something2"));
+ assertNotMatches(expr.matcher("/a/b/c/d/ex/@something"));
+ assertNotMatches(expr.matcher("/a/b[1]/c/d/e/@something"));
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithExactFullPathAndExtraPathInsideMatch() {
+ expr = SequencerPathExpression.compile("/a/b/c[d/e/@something] => .");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/a/b/c");
+ assertNotMatches(expr.matcher("/a/b/c/d/E/@something2"));
+ assertNotMatches(expr.matcher("/a/b/c/d/ex/@something"));
+ assertNotMatches(expr.matcher("/a/b[1]/c/d/e/@something"));
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithWildcardSelection() {
+ expr = SequencerPathExpression.compile("/a/*/c[d/e/@something] => .");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/a/b/c");
+ assertMatches(expr.matcher("/a/b[2]/c/d/e/@something"), "/a/b[2]/c", "/a/b[2]/c");
+ assertMatches(expr.matcher("/a/rt/c/d/e/@something"), "/a/rt/c", "/a/rt/c");
+ assertNotMatches(expr.matcher("/ac/d/e/@something"));
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithSegmentWildcardSelection() {
+ expr = SequencerPathExpression.compile("/a//c[d/e/@something] => .");
+ assertMatches(expr.matcher("/a/c/d/e/@something"), "/a/c", "/a/c");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/a/b/c");
+ assertMatches(expr.matcher("/a/b[2]/c/d/e/@something"), "/a/b[2]/c", "/a/b[2]/c");
+ assertMatches(expr.matcher("/a/rt/c/d/e/@something"), "/a/rt/c", "/a/rt/c");
+ assertMatches(expr.matcher("/a/r/s/t/c/d/e/@something"), "/a/r/s/t/c", "/a/r/s/t/c");
+ assertMatches(expr.matcher("/a/r[1]/s[2]/t[33]/c/d/e/@something"), "/a/r[1]/s[2]/t[33]/c", "/a/r[1]/s[2]/t[33]/c");
+ assertNotMatches(expr.matcher("/a[3]/c/d/e/@something"));
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithIndexesInSelectionPaths() {
+ expr = SequencerPathExpression.compile("/a/b[2,3,4,5]/c/d/e[@something] => /x/y");
+ assertMatches(expr.matcher("/a/b[2]/c/d/e/@something"), "/a/b[2]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[3]/c/d/e/@something"), "/a/b[3]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[4]/c/d/e/@something"), "/a/b[4]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[5]/c/d/e/@something"), "/a/b[5]/c/d/e", "/x/y");
+ assertNotMatches(expr.matcher("/a/b[1]/c/d/e/@something"));
+ assertNotMatches(expr.matcher("/a/b/c/d/e/@something"));
+ assertNotMatches(expr.matcher("/a[1]/b/c/d/e/@something"));
+
+ expr = SequencerPathExpression.compile("/a/b[0,2,3,4,5]/c/d/e[@something] => /x/y");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[2]/c/d/e/@something"), "/a/b[2]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[3]/c/d/e/@something"), "/a/b[3]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[4]/c/d/e/@something"), "/a/b[4]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[5]/c/d/e/@something"), "/a/b[5]/c/d/e", "/x/y");
+ assertNotMatches(expr.matcher("/a/b[1]/c/d/e/@something"));
+ assertNotMatches(expr.matcher("/a[1]/b/c/d/e/@something"));
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithAnyIndexesInSelectionPaths() {
+ expr = SequencerPathExpression.compile("/a/b[*]/c[]/d/e[@something] => /x/y");
+ assertMatches(expr.matcher("/a/b[2]/c/d/e/@something"), "/a/b[2]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[3]/c/d/e/@something"), "/a/b[3]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[4]/c/d/e/@something"), "/a/b[4]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[5]/c/d/e/@something"), "/a/b[5]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[1]/c/d/e/@something"), "/a/b[1]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[6]/c/d/e/@something"), "/a/b[6]/c/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b[6]/c[1]/d/e/@something"), "/a/b[6]/c[1]/d/e", "/x/y");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c/d/e", "/x/y");
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithFullOutputPath() {
+ expr = SequencerPathExpression.compile("/a/b/c[d/e/@something] => /x/y");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/x/y");
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithRepositoryInSelectionPath() {
+ expr = SequencerPathExpression.compile("reposA:/a/b/c[d/e/@something] => /x/y");
+ assertMatches(expr.matcher("reposA:/a/b/c/d/e/@something"), "reposA:/a/b/c", "/x/y");
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithRepositoryInFullOutputPath() {
+ expr = SequencerPathExpression.compile("/a/b/c[d/e/@something] => reposA:/x/y");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "reposA:/x/y");
+ }
+
+ @Test
+ public void shouldMatchExpressionsWithNamedGroupsInOutputPath() {
+ expr = SequencerPathExpression.compile("/a(//c)[d/e/@something] => $1/y/z");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/b/c/y/z");
+
+ expr = SequencerPathExpression.compile("/a(/(b|c|d|)/e)[f/g/@something] => $1/y/z");
+ assertMatches(expr.matcher("/a/b/e/f/g/@something"), "/a/b/e", "/b/e/y/z");
+ assertMatches(expr.matcher("/a/c/e/f/g/@something"), "/a/c/e", "/c/e/y/z");
+ assertMatches(expr.matcher("/a/d/e/f/g/@something"), "/a/d/e", "/d/e/y/z");
+ assertMatches(expr.matcher("/a/e/f/g/@something"), "/a/e", "/e/y/z");
+ assertNotMatches(expr.matcher("/a/t/e/f/g/@something"));
+
+ expr = SequencerPathExpression.compile("/a/(b/c)[(d|e)/(f|g)/@something] => /u/$1/y/z/$2/$3");
+ assertMatches(expr.matcher("/a/b/c/d/f/@something"), "/a/b/c", "/u/b/c/y/z/d/f");
+ assertMatches(expr.matcher("/a/b/c/e/f/@something"), "/a/b/c", "/u/b/c/y/z/e/f");
+ assertMatches(expr.matcher("/a/b/c/d/g/@something"), "/a/b/c", "/u/b/c/y/z/d/g");
+ assertMatches(expr.matcher("/a/b/c/e/g/@something"), "/a/b/c", "/u/b/c/y/z/e/g");
+
+ expr = SequencerPathExpression.compile("/a/(b/c)/(d|e)/(f|g)/@something => /u/$1/y/z/$2/$3");
+ assertMatches(expr.matcher("/a/b/c/d/f/@something"), "/a/b/c/d/f", "/u/b/c/y/z/d/f");
+ assertMatches(expr.matcher("/a/b/c/e/f/@something"), "/a/b/c/e/f", "/u/b/c/y/z/e/f");
+ assertMatches(expr.matcher("/a/b/c/d/g/@something"), "/a/b/c/d/g", "/u/b/c/y/z/d/g");
+ assertMatches(expr.matcher("/a/b/c/e/g/@something"), "/a/b/c/e/g", "/u/b/c/y/z/e/g");
+ }
+
+ @Test
+ public void shouldMatchExpressionWithReoccurringNamedGroupsDollarsInOutputPath() {
+ expr = SequencerPathExpression.compile("/a/(b/c)[(d|e)/(f|g)/@something] => /u/$1/y/z/$2/$3/$1/$1");
+ assertMatches(expr.matcher("/a/b/c/d/f/@something"), "/a/b/c", "/u/b/c/y/z/d/f/b/c/b/c");
+ }
+
+ @Test
+ public void shouldMatchExpressionWithNamedGroupsAndEscapedDollarsInOutputPath() {
+ expr = SequencerPathExpression.compile("/a/(b/c)[(d|e)/(f|g)/@something] => /\\$2u/$1/y/z/$2/$3");
+ assertMatches(expr.matcher("/a/b/c/d/f/@something"), "/a/b/c", "/\\$2u/b/c/y/z/d/f");
+ }
+
+ @Test
+ public void shouldMatchExpressionWithParentReferencesInOutputPath() {
+ expr = SequencerPathExpression.compile("/a/b/c[d/e/@something] => /x/y/z/../..");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/x");
+
+ expr = SequencerPathExpression.compile("/a/(b/c)[d/e/@something] => /x/$1/z/../../v");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/x/b/v");
+ }
+
+ @Test
+ public void shouldMatchExpressionWithSelfReferencesInOutputPath() {
+ expr = SequencerPathExpression.compile("/a/b/c[d/e/@something] => /x/y/./z/.");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/x/y/z");
+
+ expr = SequencerPathExpression.compile("/a/(b/c)[d/e/@something] => /x/$1/./z");
+ assertMatches(expr.matcher("/a/b/c/d/e/@something"), "/a/b/c", "/x/b/c/z");
+ }
+
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencingServiceTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencingServiceTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencingServiceTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,331 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import java.util.concurrent.TimeUnit;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItem;
+import javax.jcr.Node;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import org.jboss.dna.common.jcr.AbstractJcrRepositoryTest;
+import org.jboss.dna.repository.observation.ObservationService;
+import org.jboss.dna.repository.sequencers.Sequencer;
+import org.jboss.dna.repository.sequencers.SequencerConfig;
+import org.jboss.dna.repository.sequencers.SequencingService;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.SimpleExecutionContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class SequencingServiceTest extends AbstractJcrRepositoryTest {
+
+ public static final int ALL_EVENT_TYPES = Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
+ public static final String REPOSITORY_WORKSPACE_NAME = "testRepository-Workspace";
+
+ private ObservationService observationService;
+ private SequencingService sequencingService;
+ private ExecutionContext executionContext;
+
+ @Before
+ public void beforeEach() throws Exception {
+ this.executionContext = new SimpleExecutionContext(this, REPOSITORY_WORKSPACE_NAME);
+ this.sequencingService = new SequencingService();
+ this.sequencingService.setExecutionContext(this.executionContext);
+ this.observationService = new ObservationService(this.executionContext.getSessionFactory());
+ this.observationService.addListener(this.sequencingService);
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ super.shutdownRepository();
+ this.sequencingService.getAdministrator().shutdown();
+ }
+
+ @Test
+ public void shouldHaveTheDefaultSelectorUponConstruction() {
+ assertThat(sequencingService.getSequencerSelector(), is(sameInstance(SequencingService.DEFAULT_SEQUENCER_SELECTOR)));
+ }
+
+ @Test
+ public void shouldHaveNoExecutorServiceUponConstruction() {
+ assertThat(sequencingService.getExecutorService(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCreateDefaultExecutorServiceWhenStartedIfNoExecutorServiceHasBeenSet() {
+ assertThat(sequencingService.getExecutorService(), is(nullValue()));
+ sequencingService.getAdministrator().start();
+ assertThat(sequencingService.getExecutorService(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldCreateExecutorServiceWhenStarted() {
+ assertThat(sequencingService.getExecutorService(), is(nullValue()));
+ sequencingService.getAdministrator().start();
+ assertThat(sequencingService.getExecutorService(), is(notNullValue()));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToSetStateToUnknownString() {
+ sequencingService.getAdministrator().setState("asdf");
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToSetStateToNullString() {
+ sequencingService.getAdministrator().setState((String)null);
+ }
+
+ @Test
+ public void shouldSetStateUsingLowercaseString() {
+ assertThat(sequencingService.getAdministrator().setState("started").isStarted(), is(true));
+ assertThat(sequencingService.getAdministrator().setState("paused").isPaused(), is(true));
+ assertThat(sequencingService.getAdministrator().setState("shutdown").isShutdown(), is(true));
+ }
+
+ @Test
+ public void shouldSetStateUsingMixedCaseString() {
+ assertThat(sequencingService.getAdministrator().setState("StarTeD").isStarted(), is(true));
+ assertThat(sequencingService.getAdministrator().setState("PauSed").isPaused(), is(true));
+ assertThat(sequencingService.getAdministrator().setState("ShuTDowN").isShutdown(), is(true));
+ }
+
+ @Test
+ public void shouldSetStateUsingUppercasString() {
+ assertThat(sequencingService.getAdministrator().setState("STARTED").isStarted(), is(true));
+ assertThat(sequencingService.getAdministrator().setState("PAUSED").isPaused(), is(true));
+ assertThat(sequencingService.getAdministrator().setState("SHUTDOWN").isShutdown(), is(true));
+ }
+
+ @Test
+ public void shouldBePausedUponConstruction() {
+ assertThat(sequencingService.getAdministrator().isPaused(), is(true));
+ assertThat(sequencingService.getAdministrator().getState(), is(ServiceAdministrator.State.PAUSED));
+ assertThat(sequencingService.getAdministrator().isShutdown(), is(false));
+ assertThat(sequencingService.getAdministrator().isStarted(), is(false));
+ }
+
+ @Test
+ public void shouldBeAbleToShutdownWhenNotStarted() {
+ assertThat(sequencingService.getAdministrator().isShutdown(), is(false));
+ for (int i = 0; i != 3; ++i) {
+ assertThat(sequencingService.getAdministrator().shutdown().isShutdown(), is(true));
+ assertThat(sequencingService.getAdministrator().isPaused(), is(false));
+ assertThat(sequencingService.getAdministrator().isStarted(), is(false));
+ assertThat(sequencingService.getAdministrator().getState(), is(ServiceAdministrator.State.SHUTDOWN));
+ }
+ }
+
+ @Test
+ public void shouldBeAbleToBePauseAndRestarted() {
+ assertThat(sequencingService.getAdministrator().isShutdown(), is(false));
+ for (int i = 0; i != 3; ++i) {
+ // Now pause it ...
+ assertThat(sequencingService.getAdministrator().pause().isPaused(), is(true));
+ assertThat(sequencingService.getAdministrator().isStarted(), is(false));
+ assertThat(sequencingService.getAdministrator().isShutdown(), is(false));
+ assertThat(sequencingService.getAdministrator().getState(), is(ServiceAdministrator.State.PAUSED));
+
+ // Now start it back up ...
+ assertThat(sequencingService.getAdministrator().start().isStarted(), is(true));
+ assertThat(sequencingService.getAdministrator().isPaused(), is(false));
+ assertThat(sequencingService.getAdministrator().isShutdown(), is(false));
+ assertThat(sequencingService.getAdministrator().getState(), is(ServiceAdministrator.State.STARTED));
+ }
+ }
+
+ @Test( expected = IllegalStateException.class )
+ public void shouldNotBeAbleToBeRestartedAfterBeingShutdown() {
+ assertThat(sequencingService.getAdministrator().isShutdown(), is(false));
+ // Shut it down ...
+ assertThat(sequencingService.getAdministrator().shutdown().isShutdown(), is(true));
+ assertThat(sequencingService.getAdministrator().isPaused(), is(false));
+ assertThat(sequencingService.getAdministrator().isStarted(), is(false));
+ assertThat(sequencingService.getAdministrator().getState(), is(ServiceAdministrator.State.SHUTDOWN));
+
+ // Now start it back up ... this will fail
+ sequencingService.getAdministrator().start();
+ }
+
+ @Test
+ public void shouldBeAbleToMonitorWorkspaceWhenPausedOrStarted() throws Exception {
+ startRepository();
+ Session session = getRepository().login(getTestCredentials());
+
+ // Try when paused ...
+ assertThat(sequencingService.getAdministrator().isPaused(), is(true));
+ assertThat(observationService.getAdministrator().pause().isPaused(), is(true));
+ ObservationService.WorkspaceListener listener = observationService.monitor(REPOSITORY_WORKSPACE_NAME, Event.NODE_ADDED);
+ assertThat(listener, is(notNullValue()));
+ assertThat(listener.getAbsolutePath(), is("/"));
+ assertThat(listener.getEventTypes(), is(Event.NODE_ADDED));
+
+ // Cause an event ...
+ session.getRootNode().addNode("testnodeA", "nt:unstructured");
+ session.save();
+ Thread.sleep(100); // let the events be handled ...
+ assertThat(observationService.getStatistics().getNumberOfEventsIgnored(), is((long)1));
+
+ // Reset the statistics and remove the listener ...
+ sequencingService.getStatistics().reset();
+ observationService.getStatistics().reset();
+ assertThat(listener.isRegistered(), is(true));
+ listener.unregister();
+ assertThat(listener.isRegistered(), is(false));
+
+ // Start the sequencing sequencingService and try monitoring the workspace ...
+ assertThat(sequencingService.getAdministrator().start().isStarted(), is(true));
+ assertThat(observationService.getAdministrator().start().isStarted(), is(true));
+ ObservationService.WorkspaceListener listener2 = observationService.monitor(REPOSITORY_WORKSPACE_NAME, Event.NODE_ADDED);
+ assertThat(listener2.isRegistered(), is(true));
+ assertThat(listener2, is(notNullValue()));
+ assertThat(listener2.getAbsolutePath(), is("/"));
+ assertThat(listener2.getEventTypes(), is(Event.NODE_ADDED));
+
+ // Cause an event ...
+ session.getRootNode().addNode("testnodeB", "nt:unstructured");
+ session.save();
+ Thread.sleep(100); // let the events be handled ...
+
+ // Check the results: nothing ignored, and 1 node skipped (since no sequencers apply)
+ assertThat(observationService.getStatistics().getNumberOfEventsIgnored(), is((long)0));
+ assertThat(sequencingService.getStatistics().getNumberOfNodesSkipped(), is((long)1));
+
+ sequencingService.getAdministrator().shutdown();
+ sequencingService.getStatistics().reset();
+ observationService.getAdministrator().shutdown();
+ observationService.getStatistics().reset();
+
+ // Cause another event ...
+ session.getRootNode().addNode("testnodeC", "nt:unstructured");
+ session.save();
+ Thread.sleep(100); // let the events be handled ...
+ // The listener should no longer be registered ...
+ assertThat(listener2.isRegistered(), is(false));
+
+ // Check the results: nothing ignored, and nothing skipped
+ assertThat(observationService.getStatistics().getNumberOfEventsIgnored(), is((long)0));
+ assertThat(sequencingService.getStatistics().getNumberOfNodesSkipped(), is((long)0));
+ }
+
+ @Test
+ public void shouldUnregisterAllWorkspaceListenersWhenSystemIsShutdownAndNotWhenPaused() throws Exception {
+ startRepository();
+ Session session = getRepository().login(getTestCredentials());
+
+ // Start the sequencing sequencingService and try monitoring the workspace ...
+ assertThat(sequencingService.getAdministrator().start().isStarted(), is(true));
+ ObservationService.WorkspaceListener listener = observationService.monitor(REPOSITORY_WORKSPACE_NAME, Event.NODE_ADDED);
+ assertThat(listener.isRegistered(), is(true));
+ assertThat(listener, is(notNullValue()));
+ assertThat(listener.getAbsolutePath(), is("/"));
+ assertThat(listener.getEventTypes(), is(Event.NODE_ADDED));
+
+ // Cause an event ...
+ session.getRootNode().addNode("testnodeB", "nt:unstructured");
+ session.save();
+ assertThat(listener.isRegistered(), is(true));
+
+ // Pause the sequencingService, can cause an event ...
+ sequencingService.getAdministrator().pause();
+ session.getRootNode().addNode("testnodeB", "nt:unstructured");
+ session.save();
+ assertThat(listener.isRegistered(), is(true));
+
+ // Shut down the services and await termination ...
+ sequencingService.getAdministrator().shutdown();
+ observationService.getAdministrator().shutdown();
+ sequencingService.getAdministrator().awaitTermination(2, TimeUnit.SECONDS);
+ observationService.getAdministrator().awaitTermination(2, TimeUnit.SECONDS);
+
+ // Cause another event ...
+ session.getRootNode().addNode("testnodeC", "nt:unstructured");
+ session.save();
+
+ // The listener should no longer be registered ...
+ assertThat(listener.isRegistered(), is(false));
+ }
+
+ @Test
+ public void shouldExecuteSequencersUponChangesToRepositoryThatMatchSequencerPathExpressions() throws Exception {
+ // Add configurations for a sequencer ...
+ String name = "MockSequencerA";
+ String desc = "A mock sequencer that accumulates the number of times it's called";
+ String classname = MockSequencerA.class.getName();
+ String[] classpath = null;
+ String[] pathExpressions = {"/testnodeC/testnodeD/@description => ."};
+ SequencerConfig configA = new SequencerConfig(name, desc, classname, classpath, pathExpressions);
+ sequencingService.addSequencer(configA);
+
+ // Start the repository and get a session ...
+ startRepository();
+ Session session = getRepository().login(getTestCredentials());
+
+ // Start the sequencing sequencingService and try monitoring the workspace ...
+ assertThat(sequencingService.getAdministrator().start().isStarted(), is(true));
+ ObservationService.WorkspaceListener listener = observationService.monitor(REPOSITORY_WORKSPACE_NAME, ALL_EVENT_TYPES);
+ assertThat(listener.isRegistered(), is(true));
+ assertThat(listener, is(notNullValue()));
+ assertThat(listener.getAbsolutePath(), is("/"));
+ assertThat(listener.getEventTypes(), is(ALL_EVENT_TYPES));
+
+ // The sequencer should not yet have run ...
+ MockSequencerA sequencerA = (MockSequencerA)sequencingService.getSequencerLibrary().getInstances().get(0);
+ assertThat(sequencerA, is(notNullValue()));
+ assertThat(sequencerA.getCounter(), is(0));
+ assertThat(sequencingService.getSequencerLibrary().getInstances(), hasItem((Sequencer)sequencerA));
+
+ // Cause an event, but not one that the sequencer cares about ...
+ Node nodeC = session.getRootNode().addNode("testnodeC", "nt:unstructured");
+ assertThat(nodeC, is(notNullValue()));
+ session.save();
+ assertThat(sequencerA.getCounter(), is(0));
+ assertThat(sequencingService.getSequencerLibrary().getInstances(), hasItem((Sequencer)sequencerA));
+
+ // Cause another event, but again one that the sequencer does not care about ...
+ Node nodeD = nodeC.addNode("testnodeD", "nt:unstructured");
+ assertThat(nodeD, is(notNullValue()));
+ session.save();
+ assertThat(sequencerA.getCounter(), is(0));
+ assertThat(sequencingService.getSequencerLibrary().getInstances(), hasItem((Sequencer)sequencerA));
+
+ // Now set the property that the sequencer DOES care about ...
+ sequencerA.setExpectedCount(1);
+ nodeD.setProperty("description", "This is the value");
+ session.save();
+
+ // Wait for the event to be processed and the sequencer to be called ...
+ sequencerA.awaitExecution(4, TimeUnit.SECONDS); // wait for the sequencer to be called
+ assertThat(sequencerA.getCounter(), is(1));
+ assertThat(sequencingService.getSequencerLibrary().getInstances(), hasItem((Sequencer)sequencerA));
+ }
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapterTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapterTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapterTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,336 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.sequencers;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import javax.jcr.Node;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import org.jboss.dna.common.jcr.AbstractJcrRepositoryTest;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.RecordingProgressMonitor;
+import org.jboss.dna.repository.observation.NodeChange;
+import org.jboss.dna.repository.sequencers.SequencerConfig;
+import org.jboss.dna.repository.sequencers.SequencerException;
+import org.jboss.dna.repository.sequencers.SequencerOutputMap;
+import org.jboss.dna.repository.sequencers.StreamSequencerAdapter;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.JcrTools;
+import org.jboss.dna.repository.util.RepositoryNodePath;
+import org.jboss.dna.repository.util.SessionFactory;
+import org.jboss.dna.spi.sequencers.SequencerOutput;
+import org.jboss.dna.spi.sequencers.StreamSequencer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class StreamSequencerAdapterTest extends AbstractJcrRepositoryTest {
+
+ private StreamSequencer streamSequencer;
+ private StreamSequencerAdapter sequencer;
+ private String[] validExpressions = {"/a/* => /output"};
+ private SequencerConfig validConfig = new SequencerConfig("name", "desc", "something.class", null, validExpressions);
+ private JcrTools tools;
+ private Session session;
+ private SequencerOutputMap sequencerOutput;
+ private String sampleData = "The little brown fox didn't something bad.";
+ private ExecutionContext context;
+ private RecordingProgressMonitor progressMonitor;
+ private String repositoryWorkspaceName = "something";
+
+ @Before
+ public void beforeEach() throws Exception {
+ final JcrTools tools = new JcrTools();
+ this.tools = tools;
+ sequencerOutput = new SequencerOutputMap();
+ progressMonitor = new RecordingProgressMonitor(StreamSequencerAdapterTest.class.getName());
+ final SessionFactory sessionFactory = new SessionFactory() {
+
+ public Session createSession( String name ) {
+ return createTestSession();
+ }
+ };
+ context = new ExecutionContext() {
+
+ public SessionFactory getSessionFactory() {
+ return sessionFactory;
+ }
+
+ public JcrTools getTools() {
+ return tools;
+ }
+ };
+ final SequencerOutputMap finalOutput = sequencerOutput;
+ streamSequencer = new StreamSequencer() {
+
+ /**
+ * This method always copies the {@link StreamSequencerAdapterTest#sequencerOutput} data into the output {@inheritDoc},
+ * and does nothing else with any of the other parameters.
+ */
+ public void sequence( InputStream stream, SequencerOutput output, ProgressMonitor progressMonitor ) {
+ for (SequencerOutputMap.Entry entry : finalOutput) {
+ String nodePath = entry.getPath().getString();
+ for (SequencerOutputMap.PropertyValue property : entry.getPropertyValues()) {
+ output.setProperty(nodePath, property.getName(), property.getValue());
+ }
+ }
+ }
+ };
+ sequencer = new StreamSequencerAdapter(streamSequencer);
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ if (session != null) {
+ try {
+ session.logout();
+ } finally {
+ session = null;
+ }
+ }
+ }
+
+ protected Session createTestSession() {
+ try {
+ return getRepository().login(getTestCredentials());
+ } catch (Exception e) {
+ fail("Unable to create repository session: " + e.getMessage());
+ return null; // won't get here
+ }
+ }
+
+ @Test
+ public void shouldNotHaveSequencerUponInstantiation() {
+ assertThat(sequencer.getConfiguration(), is(nullValue()));
+ sequencer.setConfiguration(validConfig);
+ assertThat(sequencer.getConfiguration(), is(sameInstance(validConfig)));
+ }
+
+ @Test
+ public void shouldExtractNullMixinTypesFromNullValue() {
+ assertThat(sequencer.extractMixinTypes(null), is(nullValue()));
+ }
+
+ @Test
+ public void shouldExtractMixinTypesFromStringValue() {
+ assertThat(sequencer.extractMixinTypes("value"), is(new String[] {"value"}));
+ assertThat(sequencer.extractMixinTypes(""), is(new String[] {""}));
+ }
+
+ @Test
+ public void shouldExtractMixinTypesFromStringArrayValue() {
+ assertThat(sequencer.extractMixinTypes(new String[] {"value1"}), is(new String[] {"value1"}));
+ assertThat(sequencer.extractMixinTypes(new String[] {"value1", "value2"}), is(new String[] {"value1", "value2"}));
+ }
+
+ @Test
+ public void shouldExtractMixinTypesFromStringArrayWithNullValue() {
+ assertThat(sequencer.extractMixinTypes(new String[] {"value1", null, "value2"}), is(new String[] {"value1", null, "value2"}));
+ }
+
+ @Test
+ public void shouldExecuteSequencerOnExistingNodeAndOutputToExistingNode() throws Exception {
+ startRepository();
+ session = getRepository().login(getTestCredentials());
+
+ // Set up the repository for the test ...
+ Node nodeC = tools.findOrCreateNode(session, "/a/b/c");
+ Node nodeE = tools.findOrCreateNode(session, "/d/e");
+ assertThat(nodeC, is(notNullValue()));
+ assertThat(nodeE, is(notNullValue()));
+ assertThat(nodeE.getNodes().getSize(), is(0l));
+ assertThat(nodeE.getProperties().getSize(), is(1l)); // jcr:primaryType
+ assertThat(nodeE.getProperty("jcr:primaryType").getString(), is("nt:unstructured"));
+
+ // Set the property that will be sequenced ...
+ nodeC.setProperty("sequencedProperty", new ByteArrayInputStream(sampleData.getBytes()));
+
+ // Set up the node changes ...
+ NodeChange nodeChange = new NodeChange(repositoryWorkspaceName, nodeC.getPath(), Event.PROPERTY_CHANGED, Collections.singleton("sequencedProperty"), null);
+
+ // Set up the output directory ...
+ Set<RepositoryNodePath> outputPaths = new HashSet<RepositoryNodePath>();
+ outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, nodeE.getPath()));
+
+ // Generate the output data that the sequencer subclass will produce and that should be saved to the repository ...
+ sequencerOutput.setProperty("alpha/beta", "isSomething", true);
+
+ // Call the sequencer ...
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+ }
+
+ @Test( expected = SequencerException.class )
+ public void shouldExecuteSequencerOnExistingNodeWithMissingSequencedPropertyAndOutputToExistingNode() throws Exception {
+ startRepository();
+ session = getRepository().login(getTestCredentials());
+
+ // Set up the repository for the test ...
+ Node nodeC = tools.findOrCreateNode(session, "/a/b/c");
+ Node nodeE = tools.findOrCreateNode(session, "/d/e");
+ assertThat(nodeC, is(notNullValue()));
+ assertThat(nodeE, is(notNullValue()));
+ assertThat(nodeE.getNodes().getSize(), is(0l));
+ assertThat(nodeE.getProperties().getSize(), is(1l)); // jcr:primaryType
+ assertThat(nodeE.getProperty("jcr:primaryType").getString(), is("nt:unstructured"));
+
+ // Set the property that will be sequenced ...
+ // THIS TEST REQUIRES THIS PROPERTY TO BE NULL OR NON-EXISTANT
+ nodeC.setProperty("sequencedProperty", (InputStream)null);
+
+ // Set up the node changes ...
+ NodeChange nodeChange = new NodeChange(repositoryWorkspaceName, nodeC.getPath(), Event.PROPERTY_CHANGED, Collections.singleton("sequencedProperty"), null);
+
+ // Set up the output directory ...
+ Set<RepositoryNodePath> outputPaths = new HashSet<RepositoryNodePath>();
+ outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, nodeE.getPath()));
+
+ // Generate the output data that the sequencer subclass will produce and that should be saved to the repository ...
+ sequencerOutput.setProperty("alpha/beta", "isSomething", true);
+
+ // Call the sequencer, which should cause the exception ...
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+ }
+
+ @Test
+ public void shouldExecuteSequencerOnExistingNodeAndOutputToMultipleExistingNodes() throws Exception {
+ startRepository();
+ session = getRepository().login(getTestCredentials());
+
+ // Set up the repository for the test ...
+ Node nodeC = tools.findOrCreateNode(session, "/a/b/c");
+ Node nodeE = tools.findOrCreateNode(session, "/d/e");
+ assertThat(nodeC, is(notNullValue()));
+ assertThat(nodeE, is(notNullValue()));
+ assertThat(nodeE.getNodes().getSize(), is(0l));
+ assertThat(nodeE.getProperties().getSize(), is(1l)); // jcr:primaryType
+ assertThat(nodeE.getProperty("jcr:primaryType").getString(), is("nt:unstructured"));
+
+ // Set the property that will be sequenced ...
+ nodeC.setProperty("sequencedProperty", new ByteArrayInputStream(sampleData.getBytes()));
+
+ // Set up the node changes ...
+ NodeChange nodeChange = new NodeChange(repositoryWorkspaceName, nodeC.getPath(), Event.PROPERTY_CHANGED, Collections.singleton("sequencedProperty"), null);
+
+ // Set up the output directory ...
+ Set<RepositoryNodePath> outputPaths = new HashSet<RepositoryNodePath>();
+ outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, "/d/e"));
+ outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, "/x/y/z"));
+
+ // Generate the output data that the sequencer subclass will produce and that should be saved to the repository ...
+ sequencerOutput.setProperty("alpha/beta", "isSomething", true);
+
+ // Call the sequencer ...
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+
+ // Check to see that the output nodes have been created ...
+ assertThat(session.getRootNode().hasNode("d/e"), is(true));
+ assertThat(session.getRootNode().hasNode("x/y/z"), is(true));
+ }
+
+ @Test
+ public void shouldExecuteSequencerOnExistingNodeAndOutputToNonExistingNode() throws Exception {
+ startRepository();
+ session = getRepository().login(getTestCredentials());
+
+ // Set up the repository for the test ...
+ Node nodeC = tools.findOrCreateNode(session, "/a/b/c");
+ assertThat(session.getRootNode().hasNode("d"), is(false));
+ assertThat(nodeC, is(notNullValue()));
+
+ // Set the property that will be sequenced ...
+ nodeC.setProperty("sequencedProperty", new ByteArrayInputStream(sampleData.getBytes()));
+
+ // Set up the node changes ...
+ NodeChange nodeChange = new NodeChange(repositoryWorkspaceName, nodeC.getPath(), Event.PROPERTY_CHANGED, Collections.singleton("sequencedProperty"), null);
+
+ // Set up the output directory ...
+ Set<RepositoryNodePath> outputPaths = new HashSet<RepositoryNodePath>();
+ outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, "/d/e"));
+
+ // Generate the output data that the sequencer subclass will produce and that should be saved to the repository ...
+ sequencerOutput.setProperty("alpha/beta", "isSomething", true);
+
+ // Call the sequencer ...
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+
+ // Check to see that the "/d/e" node has been created ...
+ assertThat(session.getRootNode().hasNode("d/e"), is(true));
+ }
+
+ @Test
+ public void shouldExecuteSequencerOnExistingNodeAndOutputToMultipleNonExistingNodes() throws Exception {
+ startRepository();
+ session = getRepository().login(getTestCredentials());
+
+ // Set up the repository for the test ...
+ Node nodeC = tools.findOrCreateNode(session, "/a/b/c");
+ assertThat(session.getRootNode().hasNode("d"), is(false));
+ assertThat(session.getRootNode().hasNode("x"), is(false));
+ assertThat(nodeC, is(notNullValue()));
+
+ // Set the property that will be sequenced ...
+ nodeC.setProperty("sequencedProperty", new ByteArrayInputStream(sampleData.getBytes()));
+
+ // Set up the node changes ...
+ NodeChange nodeChange = new NodeChange(repositoryWorkspaceName, nodeC.getPath(), Event.PROPERTY_CHANGED, Collections.singleton("sequencedProperty"), null);
+
+ // Set up the output directory ...
+ Set<RepositoryNodePath> outputPaths = new HashSet<RepositoryNodePath>();
+ outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, "/d/e"));
+ outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, "/x/y/z"));
+ outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, "/x/z"));
+
+ // Generate the output data that the sequencer subclass will produce and that should be saved to the repository ...
+ sequencerOutput.setProperty("alpha/beta", "isSomething", true);
+
+ // Call the sequencer ...
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+
+ // Check to see that the output nodes have been created ...
+ assertThat(session.getRootNode().hasNode("d/e"), is(true));
+ assertThat(session.getRootNode().hasNode("x/y/z"), is(true));
+ assertThat(session.getRootNode().hasNode("x/z"), is(true));
+
+ // Check to see that the sequencer-generated nodes have been created ...
+ // Node beta = session.getRootNode().getNode("d/e/alpha/beta");
+ // for (PropertyIterator iter = beta.getProperties(); iter.hasNext();) {
+ // Property property = iter.nextProperty();
+ // System.out.println("Property on " + beta.getPath() + " ===> " + property.getName() + " = " + property.getValue());
+ // }
+ assertThat(session.getRootNode().getNode("d/e/alpha/beta").getProperty("isSomething").getBoolean(), is(true));
+ assertThat(session.getRootNode().getNode("x/y/z/alpha/beta").getProperty("isSomething").getBoolean(), is(true));
+ assertThat(session.getRootNode().getNode("x/z/alpha/beta").getProperty("isSomething").getBoolean(), is(true));
+ }
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,168 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.util;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import org.jboss.dna.common.SystemFailureException;
+import org.jboss.dna.common.jcr.AbstractJcrRepositoryTest;
+import org.jboss.dna.common.naming.MockInitialContext;
+import org.jboss.dna.repository.util.JndiSessionFactory;
+import org.jmock.Mockery;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class JndiSessionFactoryTest extends AbstractJcrRepositoryTest {
+
+ public static final String MOCK_REPOSITORY_NAME = "java:jcr/unit/test/repository/1";
+ public static final String MOCK_REPOSITORY_NAME_ALT = "java:jcr/unit/test/repository/2";
+
+ private JndiSessionFactory factory;
+ private Mockery context;
+ private Repository mockRepository;
+ private Session session;
+
+ @Before
+ public void beforeEach() throws Exception {
+ this.context = new Mockery();
+ this.mockRepository = this.context.mock(Repository.class);
+ MockInitialContext.register(MOCK_REPOSITORY_NAME, this.mockRepository);
+ this.factory = new JndiSessionFactory();
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ if (session != null) {
+ session.logout();
+ }
+ MockInitialContext.tearDown();
+ }
+
+ protected void assertNotRegistered( String name ) {
+ try {
+ new InitialContext().lookup(name);
+ fail("Unexpectedly found registered object");
+ } catch (NamingException e) {
+ // expected ...
+ }
+ }
+
+ protected void assertRegistered( String name, Object obj ) {
+ try {
+ assertThat(new InitialContext().lookup(name), is(sameInstance(obj)));
+ } catch (NamingException e) {
+ fail("Failed to find registered object \"" + name + "\"");
+ }
+ }
+
+ @Test
+ public void shouldCreateSessionForRegisteredRepository() {
+
+ }
+
+ @Test( expected = SystemFailureException.class )
+ public void shouldThrowSystemFailureWhenUnableToFindRegisteredRepository() throws Exception {
+ factory.createSession(MOCK_REPOSITORY_NAME + "something_extra_that_can't_be_found");
+ }
+
+ @Test
+ public void shouldFindWorkspaceInRegisteredName() {
+ assertThat(factory.getWorkspaceName("java:jcr/path/to/repository/workspaceName"), is("workspaceName"));
+ }
+
+ @Test
+ public void shouldReturnNullWorkspaceIfRegisteredNameEndsInDelimiter() {
+ assertThat(factory.getWorkspaceName("java:jcr/path/to/repository/"), is(nullValue()));
+ }
+
+ @Test
+ public void shouldReturnNullWorkspaceIfRegisteredNameHasNoDelimiter() {
+ assertThat(factory.getWorkspaceName("java:jcr"), is(nullValue()));
+ }
+
+ @Test
+ public void shouldFindRepositoryInRegisteredName() {
+ assertThat(factory.getRepositoryName("java:jcr/path/to/repository/workspaceName"), is("java:jcr/path/to/repository"));
+ }
+
+ @Test
+ public void shouldConsiderWholeRegisteredNameToBeRepositoryNameIfRegisteredNameEndsInDelimiter() {
+ assertThat(factory.getRepositoryName("java:jcr/path/to/repository/"), is("java:jcr/path/to/repository"));
+ }
+
+ @Test
+ public void shouldConsiderWholeRegisteredNameToBeRepositoryNameIfRegisteredNameHasNoDelimiter() {
+ assertThat(factory.getRepositoryName("java:jcr"), is("java:jcr"));
+ }
+
+ @Test
+ public void shouldRegisterSuppliedRepositoryInJndi() throws Exception {
+ assertNotRegistered(MOCK_REPOSITORY_NAME_ALT);
+ factory.registerRepository(MOCK_REPOSITORY_NAME_ALT, mockRepository);
+ assertRegistered(MOCK_REPOSITORY_NAME_ALT, mockRepository);
+ }
+
+ @Test
+ public void shouldUnregisterRepositoryInJndiIfNullRepositoryReference() throws Exception {
+ assertRegistered(MOCK_REPOSITORY_NAME, mockRepository);
+ factory.registerRepository(MOCK_REPOSITORY_NAME, null);
+ assertNotRegistered(MOCK_REPOSITORY_NAME);
+ }
+
+ @Test
+ public void shouldRemoveAllTrailingDelimitersWhenRegisteringRepository() throws Exception {
+ assertNotRegistered("java:jcr/unit/test/repository");
+ factory.registerRepository("java:jcr/unit/test/repository///", mockRepository);
+ assertRegistered("java:jcr/unit/test/repository", mockRepository);
+ }
+
+ @Test
+ public void shouldCreateAnonymousSessionInRepositoryIfNoCredentialsAreRegisterd() throws Exception {
+ Repository repository = getRepository();
+ factory.registerRepository("java:jcr/unit/test/repository/", repository);
+ session = factory.createSession("java:jcr/unit/test/repository/default");
+ assertThat(session, is(notNullValue()));
+ assertThat(session.getUserID(), is("anonymous")); // as defined in the Jackrabbit configuration file
+ }
+
+ @Test
+ public void shouldCreateNonAnonymousSessionInRepositoryIfCredentialsAreRegistered() throws Exception {
+ Repository repository = getRepository();
+ factory.registerRepository("java:jcr/unit/test/repository/", repository);
+ factory.registerCredentials("java:jcr/unit/test/repository/default", "jsmith", "secret".toCharArray());
+ session = factory.createSession("java:jcr/unit/test/repository/default");
+ assertThat(session, is(notNullValue()));
+ assertThat(session.getUserID(), is("jsmith")); // as defined in the Jackrabbit configuration file
+ }
+}
Property changes on: trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/SimpleExecutionContext.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/SimpleExecutionContext.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/SimpleExecutionContext.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.repository.util;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import java.io.IOException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import org.jboss.dna.common.SystemFailureException;
+import org.jboss.dna.common.jcr.AbstractJcrRepositoryTest;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.repository.util.JcrTools;
+import org.jboss.dna.repository.util.SessionFactory;
+
+/**
+ * @author Randall Hauch
+ */
+public class SimpleExecutionContext implements ExecutionContext {
+
+ private JcrTools tools = new JcrTools();
+ private SessionFactory sessionFactory;
+
+ public SimpleExecutionContext( final AbstractJcrRepositoryTest test, final String repositoryName ) {
+ this.sessionFactory = new SessionFactory() {
+
+ public Session createSession( String name ) throws RepositoryException {
+ assertThat(name, is(repositoryName));
+ try {
+ return test.getRepository().login(test.getTestCredentials());
+ } catch (IOException e) {
+ throw new SystemFailureException(e);
+ }
+ }
+ };
+ }
+
+ public SessionFactory getSessionFactory() {
+ return sessionFactory;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public JcrTools getTools() {
+ return tools;
+ }
+}
Property changes on: trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/SimpleExecutionContext.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Deleted: trunk/dna-repository/src/test/java/org/jboss/dna/services/JndiSessionFactoryTest.java
===================================================================
--- trunk/dna-services/src/test/java/org/jboss/dna/services/JndiSessionFactoryTest.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/services/JndiSessionFactoryTest.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,167 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import org.jboss.dna.common.SystemFailureException;
-import org.jboss.dna.common.jcr.AbstractJcrRepositoryTest;
-import org.jboss.dna.common.naming.MockInitialContext;
-import org.jmock.Mockery;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- */
-public class JndiSessionFactoryTest extends AbstractJcrRepositoryTest {
-
- public static final String MOCK_REPOSITORY_NAME = "java:jcr/unit/test/repository/1";
- public static final String MOCK_REPOSITORY_NAME_ALT = "java:jcr/unit/test/repository/2";
-
- private JndiSessionFactory factory;
- private Mockery context;
- private Repository mockRepository;
- private Session session;
-
- @Before
- public void beforeEach() throws Exception {
- this.context = new Mockery();
- this.mockRepository = this.context.mock(Repository.class);
- MockInitialContext.register(MOCK_REPOSITORY_NAME, this.mockRepository);
- this.factory = new JndiSessionFactory();
- }
-
- @After
- public void afterEach() throws Exception {
- if (session != null) {
- session.logout();
- }
- MockInitialContext.tearDown();
- }
-
- protected void assertNotRegistered( String name ) {
- try {
- new InitialContext().lookup(name);
- fail("Unexpectedly found registered object");
- } catch (NamingException e) {
- // expected ...
- }
- }
-
- protected void assertRegistered( String name, Object obj ) {
- try {
- assertThat(new InitialContext().lookup(name), is(sameInstance(obj)));
- } catch (NamingException e) {
- fail("Failed to find registered object \"" + name + "\"");
- }
- }
-
- @Test
- public void shouldCreateSessionForRegisteredRepository() {
-
- }
-
- @Test( expected = SystemFailureException.class )
- public void shouldThrowSystemFailureWhenUnableToFindRegisteredRepository() throws Exception {
- factory.createSession(MOCK_REPOSITORY_NAME + "something_extra_that_can't_be_found");
- }
-
- @Test
- public void shouldFindWorkspaceInRegisteredName() {
- assertThat(factory.getWorkspaceName("java:jcr/path/to/repository/workspaceName"), is("workspaceName"));
- }
-
- @Test
- public void shouldReturnNullWorkspaceIfRegisteredNameEndsInDelimiter() {
- assertThat(factory.getWorkspaceName("java:jcr/path/to/repository/"), is(nullValue()));
- }
-
- @Test
- public void shouldReturnNullWorkspaceIfRegisteredNameHasNoDelimiter() {
- assertThat(factory.getWorkspaceName("java:jcr"), is(nullValue()));
- }
-
- @Test
- public void shouldFindRepositoryInRegisteredName() {
- assertThat(factory.getRepositoryName("java:jcr/path/to/repository/workspaceName"), is("java:jcr/path/to/repository"));
- }
-
- @Test
- public void shouldConsiderWholeRegisteredNameToBeRepositoryNameIfRegisteredNameEndsInDelimiter() {
- assertThat(factory.getRepositoryName("java:jcr/path/to/repository/"), is("java:jcr/path/to/repository"));
- }
-
- @Test
- public void shouldConsiderWholeRegisteredNameToBeRepositoryNameIfRegisteredNameHasNoDelimiter() {
- assertThat(factory.getRepositoryName("java:jcr"), is("java:jcr"));
- }
-
- @Test
- public void shouldRegisterSuppliedRepositoryInJndi() throws Exception {
- assertNotRegistered(MOCK_REPOSITORY_NAME_ALT);
- factory.registerRepository(MOCK_REPOSITORY_NAME_ALT, mockRepository);
- assertRegistered(MOCK_REPOSITORY_NAME_ALT, mockRepository);
- }
-
- @Test
- public void shouldUnregisterRepositoryInJndiIfNullRepositoryReference() throws Exception {
- assertRegistered(MOCK_REPOSITORY_NAME, mockRepository);
- factory.registerRepository(MOCK_REPOSITORY_NAME, null);
- assertNotRegistered(MOCK_REPOSITORY_NAME);
- }
-
- @Test
- public void shouldRemoveAllTrailingDelimitersWhenRegisteringRepository() throws Exception {
- assertNotRegistered("java:jcr/unit/test/repository");
- factory.registerRepository("java:jcr/unit/test/repository///", mockRepository);
- assertRegistered("java:jcr/unit/test/repository", mockRepository);
- }
-
- @Test
- public void shouldCreateAnonymousSessionInRepositoryIfNoCredentialsAreRegisterd() throws Exception {
- Repository repository = getRepository();
- factory.registerRepository("java:jcr/unit/test/repository/", repository);
- session = factory.createSession("java:jcr/unit/test/repository/default");
- assertThat(session, is(notNullValue()));
- assertThat(session.getUserID(), is("anonymous")); // as defined in the Jackrabbit configuration file
- }
-
- @Test
- public void shouldCreateNonAnonymousSessionInRepositoryIfCredentialsAreRegistered() throws Exception {
- Repository repository = getRepository();
- factory.registerRepository("java:jcr/unit/test/repository/", repository);
- factory.registerCredentials("java:jcr/unit/test/repository/default", "jsmith", "secret".toCharArray());
- session = factory.createSession("java:jcr/unit/test/repository/default");
- assertThat(session, is(notNullValue()));
- assertThat(session.getUserID(), is("jsmith")); // as defined in the Jackrabbit configuration file
- }
-}
Deleted: trunk/dna-repository/src/test/java/org/jboss/dna/services/SimpleExecutionContext.java
===================================================================
--- trunk/dna-services/src/test/java/org/jboss/dna/services/SimpleExecutionContext.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/services/SimpleExecutionContext.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,65 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * 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.jboss.dna.services;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-import java.io.IOException;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import org.jboss.dna.common.SystemFailureException;
-import org.jboss.dna.common.jcr.AbstractJcrRepositoryTest;
-import org.jboss.dna.services.util.JcrTools;
-
-/**
- * @author Randall Hauch
- */
-public class SimpleExecutionContext implements ExecutionContext {
-
- private JcrTools tools = new JcrTools();
- private SessionFactory sessionFactory;
-
- public SimpleExecutionContext( final AbstractJcrRepositoryTest test, final String repositoryName ) {
- this.sessionFactory = new SessionFactory() {
-
- public Session createSession( String name ) throws RepositoryException {
- assertThat(name, is(repositoryName));
- try {
- return test.getRepository().login(test.getTestCredentials());
- } catch (IOException e) {
- throw new SystemFailureException(e);
- }
- }
- };
- }
-
- public SessionFactory getSessionFactory() {
- return sessionFactory;
- }
-
- /**
- * {@inheritDoc}
- */
- public JcrTools getTools() {
- return tools;
- }
-}
Modified: trunk/dna-repository/src/test/resources/log4j.properties
===================================================================
--- trunk/dna-services/src/test/resources/log4j.properties 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/test/resources/log4j.properties 2008-04-22 02:47:53 UTC (rev 96)
@@ -9,7 +9,7 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-log4j.logger.org.jboss.dna.services.sequencers=TRACE
+log4j.logger.org.jboss.dna.repository.sequencers=TRACE
# Jackrabbit logging
log4j.logger.org.apache.jackrabbit=WARN, stdout
Modified: trunk/dna-repository/src/test/resources/rule_test.dslr
===================================================================
--- trunk/dna-services/src/test/resources/rule_test.dslr 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/dna-repository/src/test/resources/rule_test.dslr 2008-04-22 02:47:53 UTC (rev 96)
@@ -1,5 +1,5 @@
#created on: Jan 4, 2008
-package org.jboss.dna.services.rules
+package org.jboss.dna.repository.rules
#list any import classes here.
Property changes on: trunk/dna-spi
___________________________________________________________________
Name: svn:ignore
+ target
Added: trunk/dna-spi/.classpath
===================================================================
--- trunk/dna-spi/.classpath (rev 0)
+++ trunk/dna-spi/.classpath 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
Added: trunk/dna-spi/.project
===================================================================
--- trunk/dna-spi/.project (rev 0)
+++ trunk/dna-spi/.project 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>dna-spi</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ </natures>
+</projectDescription>
Added: trunk/dna-spi/pom.xml
===================================================================
--- trunk/dna-spi/pom.xml (rev 0)
+++ trunk/dna-spi/pom.xml 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </parent>
+ <!-- The groupId and version values are inherited from parent -->
+ <artifactId>dna-spi</artifactId>
+ <description>The JBoss DNA Service Provider Interface (SPI) used to create extensions</description>
+ <packaging>jar</packaging>
+ <name>JBoss DNA Service Provider Interface (SPI)</name>
+ <url>http://labs.jboss.org/dna</url>
+ <!--
+ Define the dependencies. Note that all version and scopes default to those
+ defined in the dependencyManagement section of the parent pom.
+ -->
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ Testing (note the scope)
+ -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jmock</groupId>
+ <artifactId>jmock</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jmock</groupId>
+ <artifactId>jmock-junit4</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for testing)
+ -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ Java Concurrency in Practice annotations
+ -->
+ <dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ </dependency>
+ </dependencies>
+</project>
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/SequencerOutput.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/SequencerOutput.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/SequencerOutput.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,68 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.spi.sequencers;
+
+import java.io.InputStream;
+import java.util.Calendar;
+
+/**
+ * Interface for sequencers to use to generate their output.
+ *
+ * @author Randall Hauch
+ */
+public interface SequencerOutput {
+
+ /**
+ * Set the supplied property on the supplied node.
+ * <p>
+ * The allowable values are any of the following:
+ * <ul>
+ * <li>primitives (which will be autoboxed)</li>
+ * <li>{@link String} instances</li>
+ * <li>{@link String} arrays</li>
+ * <li>byte arrays</li>
+ * <li>{@link InputStream} instances</li>
+ * <li>{@link Calendar} instances</li>
+ * <li></li>
+ * </ul>
+ * </p>
+ *
+ * @param nodePath the path to the node containing the property; may not be null
+ * @param property the name of the property to be set
+ * @param values the value(s) for the property; may be empty if any existing property is to be removed
+ */
+ void setProperty( String nodePath,
+ String property,
+ Object... values );
+
+ /**
+ * Set the supplied reference on the supplied node.
+ *
+ * @param nodePath the path to the node containing the property; may not be null
+ * @param property the name of the property to be set
+ * @param paths the paths to the referenced property, which may be absolute paths or relative to the sequencer output node;
+ * may be empty if any existing property is to be removed
+ */
+ void setReference( String nodePath,
+ String property,
+ String... paths );
+}
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/StreamSequencer.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/StreamSequencer.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/sequencers/StreamSequencer.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,68 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.dna.spi.sequencers;
+
+import java.io.InputStream;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+
+/**
+ * The interface for a DNA sequencer that processes a property as a stream to extract information from the content and store in
+ * the repository.
+ * <p>
+ * Implementations must provide a no-argument constructor.
+ * </p>
+ * @author Randall Hauch
+ */
+public interface StreamSequencer {
+
+ /**
+ * Sequence the data found in the supplied stream, placing the output information into the supplied map.
+ * <p>
+ * JBoss DNA's SequencingService determines the sequencers that should be executed by monitoring the changes to one or more
+ * workspaces that it is monitoring. Changes in those workspaces are aggregated and used to determine which sequencers should
+ * be called. If the sequencer implements this interface, then this method is called with the property that is to be sequenced
+ * along with the interface used to register the output. The framework takes care of all the rest.
+ * </p>
+ * <p>
+ * This operation should report progress to the supplied {@link ProgressMonitor}. At the beginning of the operation, call
+ * {@link ProgressMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, Object...)} with a meaningful message describing
+ * the operation and a total for the amount of work that will be done by this sequencer. Then perform the sequencing work,
+ * periodically reporting work by specifying the {@link ProgressMonitor#worked(double) amount of work} that has was just
+ * completed or by {@link ProgressMonitor#createSubtask(double) creating a subtask} and reporting work against that subtask
+ * monitor.
+ * </p>
+ * <p>
+ * The implementation should also periodically check whether the operation has been
+ * {@link ProgressMonitor#isCancelled() cancelled}. If this method returns true, the implementation should abort all work as
+ * soon as possible and close any resources that were acquired or opened.
+ * </p>
+ * <p>
+ * Finally, the implementation should call {@link ProgressMonitor#done()} when the operation has finished.
+ * </p>
+ * @param stream the stream with the data to be sequenced; never null
+ * @param output the output from the sequencing operation; never null
+ * @param progressMonitor the progress monitor that should be kept updated with the sequencer's progress and that should be
+ * frequently consulted as to whether this operation has been {@link ProgressMonitor#isCancelled() cancelled}.
+ */
+ void sequence( InputStream stream, SequencerOutput output, ProgressMonitor progressMonitor );
+
+}
Added: trunk/dna-spi/src/test/resources/log4j.properties
===================================================================
--- trunk/dna-spi/src/test/resources/log4j.properties (rev 0)
+++ trunk/dna-spi/src/test/resources/log4j.properties 2008-04-22 02:47:53 UTC (rev 96)
@@ -0,0 +1,16 @@
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %m%n
+
+# Root logger option
+log4j.rootLogger=INFO, stdout
+
+# Set up the default logging to be INFO level, then override specific units
+log4j.logger.org.jboss.dna=INFO
+
+# Jackrabbit logging
+log4j.logger.org.apache.jackrabbit=WARN, stdout
+log4j.logger.org.apache.derby=INFO, stdout
+
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/pom.xml 2008-04-22 02:47:53 UTC (rev 96)
@@ -11,7 +11,7 @@
<modules>
<module>dna-common</module>
<module>dna-maven-classloader</module>
- <module>dna-services</module>
+ <module>dna-repository</module>
<module>sequencers/dna-sequencer-images</module>
<module>dna-integration-tests</module>
</modules>
@@ -98,9 +98,14 @@
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
- <artifactId>dna-services</artifactId>
+ <artifactId>dna-spi</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-repository</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </dependency>
<!--
Rules
-->
Modified: trunk/sequencers/dna-sequencer-images/pom.xml
===================================================================
--- trunk/sequencers/dna-sequencer-images/pom.xml 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/sequencers/dna-sequencer-images/pom.xml 2008-04-22 02:47:53 UTC (rev 96)
@@ -33,7 +33,7 @@
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
- <artifactId>dna-services</artifactId>
+ <artifactId>dna-spi</artifactId>
</dependency>
<!--
Testing (note the scope)
Modified: trunk/sequencers/dna-sequencer-images/src/main/java/org/jboss/dna/sequencer/images/ImageMetadataSequencer.java
===================================================================
--- trunk/sequencers/dna-sequencer-images/src/main/java/org/jboss/dna/sequencer/images/ImageMetadataSequencer.java 2008-04-22 01:42:33 UTC (rev 95)
+++ trunk/sequencers/dna-sequencer-images/src/main/java/org/jboss/dna/sequencer/images/ImageMetadataSequencer.java 2008-04-22 02:47:53 UTC (rev 96)
@@ -23,9 +23,8 @@
import java.io.InputStream;
import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.services.ExecutionContext;
-import org.jboss.dna.services.sequencers.SequencerOutput;
-import org.jboss.dna.services.sequencers.StreamSequencer;
+import org.jboss.dna.spi.sequencers.SequencerOutput;
+import org.jboss.dna.spi.sequencers.StreamSequencer;
/**
* A sequencer that processes the binary content of an image file, extracts the metadata for the image, and then writes that image
@@ -62,7 +61,7 @@
* </p>
* @author Randall Hauch
*/
-public class ImageMetadataSequencer extends StreamSequencer {
+public class ImageMetadataSequencer implements StreamSequencer {
public static final String METADATA_NODE = "image:metadata";
public static final String IMAGE_PRIMARY_TYPE = "jcr:primaryType";
@@ -83,8 +82,7 @@
/**
* {@inheritDoc}
*/
- @Override
- protected void sequence( InputStream stream, SequencerOutput output, ExecutionContext context, ProgressMonitor progressMonitor ) {
+ public void sequence( InputStream stream, SequencerOutput output, ProgressMonitor progressMonitor ) {
ImageMetadata metadata = new ImageMetadata();
metadata.setInput(stream);
metadata.setDetermineImageNumber(true);
16 years
DNA SVN: r95 - trunk/dna-common.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-04-21 21:42:33 -0400 (Mon, 21 Apr 2008)
New Revision: 95
Modified:
trunk/dna-common/pom.xml
Log:
Changed the dependencies to include JCR API only in test scope.
Modified: trunk/dna-common/pom.xml
===================================================================
--- trunk/dna-common/pom.xml 2008-04-21 15:02:24 UTC (rev 94)
+++ trunk/dna-common/pom.xml 2008-04-22 01:42:33 UTC (rev 95)
@@ -63,6 +63,7 @@
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
16 years
DNA SVN: r94 - in trunk: dna-common/src/test/java/org/jboss/dna/common/naming and 6 other directories.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-04-21 11:02:24 -0400 (Mon, 21 Apr 2008)
New Revision: 94
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/util/Logger.java
trunk/dna-common/src/test/java/org/jboss/dna/common/naming/MockInitialContext.java
trunk/dna-maven-classloader/src/main/java/org/jboss/dna/maven/MavenRepository.java
trunk/dna-maven-classloader/src/main/java/org/jboss/dna/maven/spi/MavenUrlProvider.java
trunk/dna-services/src/main/java/org/jboss/dna/services/ExecutionContext.java
trunk/dna-services/src/main/java/org/jboss/dna/services/observation/ObservationService.java
trunk/dna-services/src/main/java/org/jboss/dna/services/rules/RuleSet.java
trunk/dna-services/src/main/java/org/jboss/dna/services/rules/RuleSetRepositoryMonitor.java
trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/Sequencer.java
trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/SequencerOutput.java
trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/SequencingService.java
Log:
Un-reformatted (had some bad compiler settings)
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/Logger.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/Logger.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/Logger.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -25,6 +25,7 @@
import java.util.concurrent.atomic.AtomicReference;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.i18n.I18n;
+import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
/**
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/naming/MockInitialContext.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/naming/MockInitialContext.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/naming/MockInitialContext.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -34,6 +34,7 @@
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
import org.jboss.dna.common.SystemFailureException;
/**
Modified: trunk/dna-maven-classloader/src/main/java/org/jboss/dna/maven/MavenRepository.java
===================================================================
--- trunk/dna-maven-classloader/src/main/java/org/jboss/dna/maven/MavenRepository.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-maven-classloader/src/main/java/org/jboss/dna/maven/MavenRepository.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -25,6 +25,7 @@
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
@@ -32,6 +33,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import javax.jcr.Repository;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -44,6 +46,7 @@
import org.jboss.dna.common.util.ArgCheck;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.common.xml.SimpleNamespaceContext;
+import org.jboss.dna.maven.spi.JcrMavenUrlProvider;
import org.jboss.dna.maven.spi.MavenUrlProvider;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
Modified: trunk/dna-maven-classloader/src/main/java/org/jboss/dna/maven/spi/MavenUrlProvider.java
===================================================================
--- trunk/dna-maven-classloader/src/main/java/org/jboss/dna/maven/spi/MavenUrlProvider.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-maven-classloader/src/main/java/org/jboss/dna/maven/spi/MavenUrlProvider.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -23,9 +23,11 @@
import java.net.MalformedURLException;
import java.net.URL;
+import java.net.URLConnection;
import java.util.Properties;
import org.jboss.dna.maven.ArtifactType;
import org.jboss.dna.maven.MavenId;
+import org.jboss.dna.maven.MavenRepository;
import org.jboss.dna.maven.MavenRepositoryException;
import org.jboss.dna.maven.SignatureType;
Modified: trunk/dna-services/src/main/java/org/jboss/dna/services/ExecutionContext.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/ExecutionContext.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-services/src/main/java/org/jboss/dna/services/ExecutionContext.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -21,6 +21,7 @@
*/
package org.jboss.dna.services;
+import javax.jcr.Session;
import org.jboss.dna.services.util.JcrTools;
/**
Modified: trunk/dna-services/src/main/java/org/jboss/dna/services/observation/ObservationService.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/observation/ObservationService.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-services/src/main/java/org/jboss/dna/services/observation/ObservationService.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -38,6 +38,7 @@
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.util.ArgCheck;
Modified: trunk/dna-services/src/main/java/org/jboss/dna/services/rules/RuleSet.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/rules/RuleSet.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-services/src/main/java/org/jboss/dna/services/rules/RuleSet.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -2,7 +2,7 @@
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
+ * distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
@@ -23,10 +23,15 @@
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
+import java.io.Reader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import javax.rules.RuleServiceProvider;
+import javax.rules.admin.RuleExecutionSet;
+import javax.rules.admin.RuleExecutionSetProvider;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.component.ClassLoaderFactory;
import org.jboss.dna.common.component.ComponentConfig;
import org.jboss.dna.common.util.ArgCheck;
Modified: trunk/dna-services/src/main/java/org/jboss/dna/services/rules/RuleSetRepositoryMonitor.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/rules/RuleSetRepositoryMonitor.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-services/src/main/java/org/jboss/dna/services/rules/RuleSetRepositoryMonitor.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -41,6 +41,7 @@
import org.jboss.dna.services.observation.NodeChange;
import org.jboss.dna.services.observation.NodeChangeListener;
import org.jboss.dna.services.observation.NodeChanges;
+import org.jboss.dna.services.observation.ObservationService;
import org.jboss.dna.services.util.JcrTools;
import org.jboss.dna.services.util.Problems;
Modified: trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/Sequencer.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/Sequencer.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/Sequencer.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -2,7 +2,7 @@
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
+ * distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
@@ -24,12 +24,16 @@
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
+import javax.jcr.Session;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.component.Component;
import org.jboss.dna.common.monitor.ProgressMonitor;
import org.jboss.dna.services.ExecutionContext;
import org.jboss.dna.services.RepositoryNodePath;
import org.jboss.dna.services.observation.NodeChange;
+import org.jboss.dna.services.observation.NodeChangeListener;
+import org.jboss.dna.services.observation.NodeChanges;
+import org.jboss.dna.services.observation.ObservationService;
/**
* The interface for a DNA sequencer, which sequences nodes and their content to extract additional information from the
Modified: trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/SequencerOutput.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/SequencerOutput.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/SequencerOutput.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -21,6 +21,9 @@
*/
package org.jboss.dna.services.sequencers;
+import java.io.InputStream;
+import java.util.Calendar;
+
/**
* Interface for sequencers to use to generate their output.
*
Modified: trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/SequencingService.java
===================================================================
--- trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/SequencingService.java 2008-04-19 00:21:53 UTC (rev 93)
+++ trunk/dna-services/src/main/java/org/jboss/dna/services/sequencers/SequencingService.java 2008-04-21 15:02:24 UTC (rev 94)
@@ -33,6 +33,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import javax.jcr.Node;
+import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.Event;
16 years