DNA SVN: r601 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connectors and 5 other directories.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-10-29 16:50:28 -0400 (Wed, 29 Oct 2008)
New Revision: 601
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContexts.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/BasicExecutionContext.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencers/MockSequencerContext.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerNodeContext.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/BasicJcrExecutionContext.java
trunk/extensions/dna-sequencer-images/src/test/java/org/jboss/dna/sequencer/images/ImageMetadataSequencerTest.java
trunk/extensions/dna-sequencer-java/src/test/java/org/jboss/dna/sequencer/java/JavaMetadataSequencerTest.java
Log:
Changed ExcecutionContext to provide ability to create a new activity monitor and updated related classes
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -25,6 +25,7 @@
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.properties.NamespaceRegistry;
@@ -45,16 +46,21 @@
public interface ExecutionContext extends ClassLoaderFactory {
/**
- * @return the access control context; may be <code>null</code>
+ * Creates a thread-safe activity monitor with the specified activity name. This method should be used when the caller is
+ * either not participating in an activity itself, or when a new activity needs to be performed that is not considered a
+ * subtask of the caller's activity.
+ *
+ * @param activityName The internationalization object representing the activity's name.
+ * @param activityNameParameters Any parameters needed to localize the activity's name.
+ * @return A new activity monitor
*/
- AccessControlContext getAccessControlContext();
+ ActivityMonitor createActivityMonitor( I18n activityName,
+ Object... activityNameParameters );
/**
- * Returns the thread-safe activity monitor associated with this execution context.
- *
- * @return the activity monitor; never <code>null</code>;
+ * @return the access control context; may be <code>null</code>
*/
- ActivityMonitor getActivityMonitor();
+ AccessControlContext getAccessControlContext();
/**
* Return a logger associated with this context. This logger records only those activities within the context and provide a
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContexts.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContexts.java 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContexts.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -24,6 +24,7 @@
import java.security.AccessControlContext;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
+import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.Logger;
@@ -151,6 +152,16 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.ExecutionContext#createActivityMonitor(org.jboss.dna.common.i18n.I18n, java.lang.Object[])
+ */
+ public ActivityMonitor createActivityMonitor( I18n activityName,
+ Object... activityNameParameters ) {
+ return delegate.createActivityMonitor(activityName, activityNameParameters);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.common.component.ClassLoaderFactory#getClassLoader(java.lang.String[])
*/
public ClassLoader getClassLoader( String... classpath ) {
@@ -188,15 +199,6 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
- */
- public ActivityMonitor getActivityMonitor() {
- return delegate.getActivityMonitor();
- }
-
- /**
- * {@inheritDoc}
- *
* @see org.jboss.dna.graph.ExecutionContext#getPropertyFactory()
*/
public PropertyFactory getPropertyFactory() {
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/BasicExecutionContext.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/BasicExecutionContext.java 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/BasicExecutionContext.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -25,9 +25,9 @@
import java.security.AccessController;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
-import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.component.ClassLoaderFactory;
import org.jboss.dna.common.component.StandardClassLoaderFactory;
+import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.common.util.Logger;
@@ -52,41 +52,37 @@
private final PropertyFactory propertyFactory;
private final ValueFactories valueFactories;
private final NamespaceRegistry namespaceRegistry;
- private final ActivityMonitor activityMonitor;
public BasicExecutionContext() {
- this(null, null, null, null, null, null);
+ this(null, null, null, null, null);
}
public BasicExecutionContext( LoginContext loginContext ) {
- this(loginContext, null, null, null, null, null);
+ this(loginContext, null, null, null, null);
}
public BasicExecutionContext( AccessControlContext accessControlContext ) {
- this(null, accessControlContext, null, null, null, null);
+ this(null, accessControlContext, null, null, null);
}
public BasicExecutionContext( NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
- PropertyFactory propertyFactory,
- ActivityMonitor activityMonitor ) {
- this(null, null, namespaceRegistry, valueFactories, propertyFactory, activityMonitor);
+ PropertyFactory propertyFactory ) {
+ this(null, null, namespaceRegistry, valueFactories, propertyFactory);
}
public BasicExecutionContext( LoginContext loginContext,
NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
- PropertyFactory propertyFactory,
- ActivityMonitor activityMonitor ) {
- this(loginContext, null, namespaceRegistry, valueFactories, propertyFactory, activityMonitor);
+ PropertyFactory propertyFactory ) {
+ this(loginContext, null, namespaceRegistry, valueFactories, propertyFactory);
}
public BasicExecutionContext( AccessControlContext accessControlContext,
NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
- PropertyFactory propertyFactory,
- ActivityMonitor activityMonitor ) {
- this(null, accessControlContext, namespaceRegistry, valueFactories, propertyFactory, activityMonitor);
+ PropertyFactory propertyFactory ) {
+ this(null, accessControlContext, namespaceRegistry, valueFactories, propertyFactory);
}
/*
@@ -96,8 +92,7 @@
AccessControlContext accessControlContext,
NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
- PropertyFactory propertyFactory,
- ActivityMonitor activityMonitor ) {
+ PropertyFactory propertyFactory ) {
this.loginContext = loginContext;
this.accessControlContext = accessControlContext;
if (loginContext == null) {
@@ -108,13 +103,22 @@
this.namespaceRegistry = namespaceRegistry == null ? new BasicNamespaceRegistry() : namespaceRegistry;
this.valueFactories = valueFactories == null ? new StandardValueFactories(this.namespaceRegistry) : valueFactories;
this.propertyFactory = propertyFactory == null ? new BasicPropertyFactory(this.valueFactories) : propertyFactory;
- this.activityMonitor = activityMonitor == null ? new SimpleActivityMonitor(CommonI18n.nullActivityMonitorTaskName) : activityMonitor;
this.classLoaderFactory = new StandardClassLoaderFactory();
}
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.ExecutionContext#createActivityMonitor(org.jboss.dna.common.i18n.I18n, java.lang.Object[])
+ */
+ public ActivityMonitor createActivityMonitor( I18n activityName,
+ Object... activityNameParameters ) {
+ return new SimpleActivityMonitor(activityName, activityNameParameters);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.common.component.ClassLoaderFactory#getClassLoader(java.lang.String[])
*/
public ClassLoader getClassLoader( String... classpath ) {
@@ -148,16 +152,7 @@
/**
* {@inheritDoc}
- *
- * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
*/
- public ActivityMonitor getActivityMonitor() {
- return activityMonitor;
- }
-
- /**
- * {@inheritDoc}
- */
public PropertyFactory getPropertyFactory() {
return propertyFactory;
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencers/MockSequencerContext.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencers/MockSequencerContext.java 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencers/MockSequencerContext.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -26,7 +26,9 @@
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.monitor.ActivityMonitor;
+import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.properties.Name;
@@ -60,6 +62,16 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.ExecutionContext#createActivityMonitor(org.jboss.dna.common.i18n.I18n, java.lang.Object[])
+ */
+ public ActivityMonitor createActivityMonitor( I18n activityName,
+ Object... activityNameParameters ) {
+ return new SimpleActivityMonitor(activityName, activityNameParameters);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.common.component.ClassLoaderFactory#getClassLoader(java.lang.String[])
*/
public ClassLoader getClassLoader( String... classpath ) {
@@ -150,15 +162,6 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
- */
- public ActivityMonitor getActivityMonitor() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
* @see org.jboss.dna.graph.ExecutionContext#getPropertyFactory()
*/
public PropertyFactory getPropertyFactory() {
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerNodeContext.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerNodeContext.java 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerNodeContext.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -35,6 +35,7 @@
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.Logger;
@@ -141,6 +142,16 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.ExecutionContext#createActivityMonitor(org.jboss.dna.common.i18n.I18n, java.lang.Object[])
+ */
+ public ActivityMonitor createActivityMonitor( I18n activityName,
+ Object... activityNameParameters ) {
+ return context.createActivityMonitor(activityName, activityNameParameters);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.graph.ExecutionContext#getAccessControlContext()
*/
public AccessControlContext getAccessControlContext() {
@@ -264,15 +275,6 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
- */
- public ActivityMonitor getActivityMonitor() {
- return context.getActivityMonitor();
- }
-
- /**
- * {@inheritDoc}
- *
* @see org.jboss.dna.graph.ExecutionContext#getPropertyFactory()
*/
public PropertyFactory getPropertyFactory() {
Modified: 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 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -46,9 +46,9 @@
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.i18n.I18n;
import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.monitor.LoggingActivityMonitor;
-import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.common.util.Logger;
@@ -514,7 +514,7 @@
}
} else {
// Run each of those sequencers ...
- ActivityMonitor activityMonitor = new SimpleActivityMonitor(RepositoryI18n.sequencerTask, changedNode);
+ ActivityMonitor activityMonitor = context.createActivityMonitor(RepositoryI18n.sequencerTask, changedNode);
if (logger.isTraceEnabled()) {
activityMonitor = new LoggingActivityMonitor(activityMonitor, logger, Logger.Level.TRACE);
}
@@ -608,6 +608,16 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.ExecutionContext#createActivityMonitor(org.jboss.dna.common.i18n.I18n, java.lang.Object[])
+ */
+ public ActivityMonitor createActivityMonitor( I18n activityName,
+ Object... activityNameParameters ) {
+ return delegate.createActivityMonitor(activityName, activityNameParameters);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.common.component.ClassLoaderFactory#getClassLoader(java.lang.String[])
*/
public ClassLoader getClassLoader( String... classpath ) {
@@ -641,16 +651,7 @@
/**
* {@inheritDoc}
- *
- * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
*/
- public ActivityMonitor getActivityMonitor() {
- return delegate.getActivityMonitor();
- }
-
- /**
- * {@inheritDoc}
- */
public PropertyFactory getPropertyFactory() {
return this.delegate.getPropertyFactory();
}
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/BasicJcrExecutionContext.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/BasicJcrExecutionContext.java 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/BasicJcrExecutionContext.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -50,7 +50,7 @@
NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
PropertyFactory propertyFactory ) {
- super(namespaceRegistry, valueFactories, propertyFactory, null);
+ super(namespaceRegistry, valueFactories, propertyFactory);
CheckArg.isNotNull(sessionFactory, "session factory");
this.sessionFactory = sessionFactory;
}
Modified: trunk/extensions/dna-sequencer-images/src/test/java/org/jboss/dna/sequencer/images/ImageMetadataSequencerTest.java
===================================================================
--- trunk/extensions/dna-sequencer-images/src/test/java/org/jboss/dna/sequencer/images/ImageMetadataSequencerTest.java 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/extensions/dna-sequencer-images/src/test/java/org/jboss/dna/sequencer/images/ImageMetadataSequencerTest.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -30,7 +30,6 @@
import java.net.URL;
import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.monitor.ActivityMonitor;
-import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.graph.sequencers.MockSequencerContext;
import org.jboss.dna.graph.sequencers.MockSequencerOutput;
import org.jboss.dna.graph.sequencers.SequencerContext;
@@ -60,7 +59,7 @@
context = new MockSequencerContext();
context.getNamespaceRegistry().register("image", "http://jboss.org/dna/images/1.0");
output = new MockSequencerOutput(context);
- activityMonitor = new SimpleActivityMonitor(MockI18n.passthrough, "Test Activity");
+ activityMonitor = context.createActivityMonitor(MockI18n.passthrough, "Test Activity");
cautionGif = this.getClass().getClassLoader().getResource("caution.gif");
cautionJpg = this.getClass().getClassLoader().getResource("caution.jpg");
cautionPict = this.getClass().getClassLoader().getResource("caution.pict");
Modified: trunk/extensions/dna-sequencer-java/src/test/java/org/jboss/dna/sequencer/java/JavaMetadataSequencerTest.java
===================================================================
--- trunk/extensions/dna-sequencer-java/src/test/java/org/jboss/dna/sequencer/java/JavaMetadataSequencerTest.java 2008-10-29 20:37:59 UTC (rev 600)
+++ trunk/extensions/dna-sequencer-java/src/test/java/org/jboss/dna/sequencer/java/JavaMetadataSequencerTest.java 2008-10-29 20:50:28 UTC (rev 601)
@@ -31,7 +31,6 @@
import java.io.InputStream;
import org.jboss.dna.common.i18n.MockI18n;
import org.jboss.dna.common.monitor.ActivityMonitor;
-import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.graph.sequencers.MockSequencerContext;
import org.jboss.dna.graph.sequencers.MockSequencerOutput;
import org.jboss.dna.graph.sequencers.SequencerContext;
@@ -57,7 +56,7 @@
context.getNamespaceRegistry().register("java", "http://jboss.org/dna/java/1.0");
sequencer = new JavaMetadataSequencer();
output = new MockSequencerOutput(context);
- this.activityMonitor = new SimpleActivityMonitor(MockI18n.passthrough, "Test java monitor activity");
+ this.activityMonitor = context.createActivityMonitor(MockI18n.passthrough, "Test java monitor activity");
source = new File("src/test/workspace/projectX/src/org/acme/MySource.java");
}
15 years, 6 months
DNA SVN: r600 - in trunk/extensions/dna-sequencer-xml/src: test/java/org/jboss/dna/sequencer/xml and 1 other directory.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-10-29 16:37:59 -0400 (Wed, 29 Oct 2008)
New Revision: 600
Modified:
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencer.java
trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java
Log:
Undid DNA-186 in lieu of better solution to come involving execution context progress monitor, and renamed ProgressMonitor and ProgressStatus to ActivityMonitor and ActivityStatus, respectively, since the monitor is about more than just progress (such as collecting problems that occur during an activity)
Modified: trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencer.java 2008-10-29 20:09:42 UTC (rev 599)
+++ trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencer.java 2008-10-29 20:37:59 UTC (rev 600)
@@ -27,7 +27,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.properties.Name;
@@ -63,12 +63,12 @@
* {@inheritDoc}
*
* @see org.jboss.dna.graph.sequencers.StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext,
- * ProgressMonitor)
+ * ActivityMonitor)
*/
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor monitor ) {
+ ActivityMonitor monitor ) {
monitor.beginTask(100.0, XmlSequencerI18n.sequencingXmlDocument);
XMLReader reader;
try {
@@ -120,7 +120,7 @@
private final SequencerOutput output;
private final SequencerContext context;
- private final ProgressMonitor monitor;
+ private final ActivityMonitor monitor;
private double progress;
@@ -151,7 +151,7 @@
Handler( SequencerOutput output,
SequencerContext context,
- ProgressMonitor monitor ) {
+ ActivityMonitor monitor ) {
assert output != null;
assert monitor != null;
assert context != null;
Modified: trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java 2008-10-29 20:09:42 UTC (rev 599)
+++ trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java 2008-10-29 20:37:59 UTC (rev 600)
@@ -28,13 +28,12 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
-import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.common.monitor.SimpleProgressMonitor;
+import org.jboss.dna.common.i18n.MockI18n;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.graph.properties.Name;
import org.jboss.dna.graph.sequencers.MockSequencerContext;
import org.jboss.dna.graph.sequencers.MockSequencerOutput;
import org.jboss.dna.graph.sequencers.SequencerContext;
-import org.jboss.dna.sequencer.xml.XmlSequencer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -62,7 +61,7 @@
private XmlSequencer sequencer;
private InputStream stream;
private MockSequencerOutput output;
- private ProgressMonitor monitor;
+ private ActivityMonitor monitor;
private URL xml1;
private URL xml2;
private URL xml3;
@@ -75,7 +74,7 @@
sequencer = new XmlSequencer();
context = new MockSequencerContext();
output = new MockSequencerOutput(context);
- monitor = new SimpleProgressMonitor("Test activity");
+ monitor = context.createActivityMonitor(MockI18n.passthrough, "Test activity");
xml1 = this.getClass().getClassLoader().getResource("jackrabbitInMemoryTestRepositoryConfig.xml");
assertThat(xml1, is(notNullValue()));
xml2 = this.getClass().getClassLoader().getResource("master.xml");
15 years, 6 months
DNA SVN: r599 - in trunk: dna-common/src/main/java/org/jboss/dna/common/monitor and 18 other directories.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-10-29 16:09:42 -0400 (Wed, 29 Oct 2008)
New Revision: 599
Added:
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityMonitorWrapper.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityStatus.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingActivityMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleActivityMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubActivityMonitor.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ActivityStatusTest.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingActivityMonitor.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleActivityMonitorTest.java
trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_en.properties
trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_fr.properties
Removed:
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingProgressMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressStatus.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ProgressStatusTest.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java
trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_en.properties
trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_fr.properties
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java
trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties
trunk/dna-common/src/test/java/org/jboss/dna/common/component/ComponentLibraryTest.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/component/SampleComponent.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContexts.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/BasicExecutionContext.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/sequencers/StreamSequencer.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencers/MockSequencerContext.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/SequencerNodeContext.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/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/StreamSequencerAdapterTest.java
trunk/extensions/dna-sequencer-images/src/main/java/org/jboss/dna/sequencer/images/ImageMetadataSequencer.java
trunk/extensions/dna-sequencer-images/src/test/java/org/jboss/dna/sequencer/images/ImageMetadataSequencerTest.java
trunk/extensions/dna-sequencer-java/src/main/java/org/jboss/dna/sequencer/java/JavaMetadataSequencer.java
trunk/extensions/dna-sequencer-java/src/main/java/org/jboss/dna/sequencer/java/metadata/JavaMetadata.java
trunk/extensions/dna-sequencer-java/src/test/java/org/jboss/dna/sequencer/java/JavaMetadataSequencerTest.java
trunk/extensions/dna-sequencer-mp3/src/main/java/org/jboss/dna/sequencer/mp3/Mp3MetadataSequencer.java
trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/MSOfficeMetadataSequencer.java
trunk/extensions/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/ZipSequencer.java
Log:
Undid DNA-186 in lieu of better solution to come involving execution context progress monitor, and renamed ProgressMonitor and ProgressStatus to ActivityMonitor and ActivityStatus, respectively, since the monitor is about more than just progress (such as collecting problems that occur during an activity)
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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -85,15 +85,15 @@
public static I18n componentClassnameNotValid;
public static I18n componentNotConfigured;
public static I18n dateParsingFailure;
- public static I18n initialProgressMonitorTaskName;
- public static I18n nullProgressMonitorTaskName;
+ public static I18n initialActivityMonitorTaskName;
+ public static I18n nullActivityMonitorTaskName;
public static I18n pathAncestorDegreeIsInvalid;
public static I18n pathIsAlreadyAbsolute;
public static I18n pathIsNotAbsolute;
public static I18n pathIsNotRelative;
public static I18n pathCannotBeNormalized;
- public static I18n progressMonitorBeginTask;
- public static I18n progressMonitorStatus;
+ public static I18n activityMonitorBeginTask;
+ public static I18n activityMonitorStatus;
public static I18n requiredToSuppliedParameterMismatch;
static {
Copied: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityMonitor.java (from rev 596, trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java)
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityMonitor.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,145 @@
+/*
+ * 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.monitor;
+
+import java.util.Locale;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * A basic activity monitor that facilitates the updating and monitoring of progress towards the completion of an activity.
+ * Documentation hereafter will refer to the code in an application that updates progress as the <strong>Updater</strong>, and
+ * code that monitors progress as an <strong>Observer</strong>.
+ * <p>
+ * The progress of each activity is started when the <strong>Updater</strong> calls {@link #beginTask(double, I18n, Object...)},
+ * continues with a mixture of work ({@link #worked(double)}) and subtasks ( {@link #createSubtask(double)}), and finishes when
+ * the activity is completed ({@link #done()}) or cancelled ( {@link #setCancelled(boolean)}).
+ * </p>
+ * <p>
+ * If an activity is interrupted before its normal completion due to a cancellation request by an <strong>Observer</strong>, it is
+ * still the responsibility of the <strong>Updater</strong> to mark the activity as completed. Similarly, if an activity cannot be
+ * cancelled before its normal completion, the <strong>Updater</strong> must deny any previous cancellation request by calling
+ * {@link #setCancelled(boolean) setCancelled(false)}.
+ * </p>
+ *
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public interface ActivityMonitor {
+
+ /**
+ * Called by the <strong>Updater</strong> to indicate work has started on the task, specifying the total amount of work that
+ * this task constitutes.
+ *
+ * @param totalWork the total number of work units for the task
+ * @param name the name of the task
+ * @param params the parameters for localization
+ */
+ void beginTask( double totalWork,
+ I18n name,
+ Object... params );
+
+ /**
+ * Called by the <strong>Updater</strong> to create a subtask with the given about of work. The resulting activity monitor
+ * must be started ({@link #beginTask(double, I18n, Object...)}) and finished ({@link #done()}).
+ *
+ * @param subtaskWork the number of work units for this subtask
+ * @return the activity monitor for the subtask
+ */
+ ActivityMonitor createSubtask( double subtaskWork );
+
+ /**
+ * Called by the <strong>Updater</strong> to mark this activity as complete. This method must be called, even if the activity
+ * has been cancelled.
+ */
+ void done();
+
+ /**
+ * Get the name of the activity using the default locale. This should never change for a activity monitor, and all
+ * {@link #createSubtask(double) subtasks} should have the same name.
+ *
+ * @return the activity's name; never <code>null</code>
+ * @see #getActivityName(Locale)
+ */
+ String getActivityName();
+
+ /**
+ * Returns the name of the activity using the supplied locale. This should never change for a activity monitor, and all
+ * {@link #createSubtask(double) subtasks} should have the same name.
+ *
+ * @param locale the locale in which the name is to be represented; if null, the {@link Locale#getDefault() default locale}
+ * will be used
+ * @return the activity's name; never <code>null</code>
+ * @see #getActivityName()
+ */
+ String getActivityName( Locale locale );
+
+ /**
+ * Return the problems encountered during the {@link #getStatus(Locale) progress} made towards completing the associated
+ * {@link #getActivityName() activity}.
+ *
+ * @return the list of problems
+ */
+ Problems getProblems();
+
+ /**
+ * Return the current status of this activity, localized to the specified locale. This method returns an immutable but
+ * consistent snapshot of the status for this activity. Note that if this instance is a {@link #createSubtask(double) subtask}
+ * , this method returns the status of the subtask.
+ *
+ * @param locale the locale in which the status is to be represented; if null, the {@link Locale#getDefault() default locale}
+ * will be used
+ * @return the status of this activity
+ */
+ ActivityStatus getStatus( Locale locale );
+
+ /**
+ * Return whether a request was made by an <strong>Observer</strong> to {@link #setCancelled(boolean) cancel} this activity.
+ *
+ * @return <code>true</code> if this activity has been requested to be cancelled.
+ */
+ boolean isCancelled();
+
+ /**
+ * Return whether this activity has completed.
+ *
+ * @return <code>true</code> if this activity has completed.
+ */
+ boolean isDone();
+
+ /**
+ * Called by an <strong>Observer</strong> to request the cancellation of this activity, or by the <strong>Updater</strong> to
+ * deny a prior cancellation request (i.e., when the activity {@link #done() completes} before the <strong>Updater</strong>
+ * recognizes a cancellation request by an <strong>Observer</strong>).
+ *
+ * @param value <code>true</code> if requesting the activity be cancelled.
+ */
+ void setCancelled( boolean value );
+
+ /**
+ * Called by the <strong>Updater</strong> to report work completed for this task.
+ *
+ * @param work the number of work units that have been worked
+ */
+ void worked( double work );
+}
Copied: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityMonitorWrapper.java (from rev 596, trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java)
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityMonitorWrapper.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityMonitorWrapper.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,147 @@
+/*
+ * 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.monitor;
+
+import java.util.Locale;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * The thread safety of this class is determined by the delegate.
+ *
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public class ActivityMonitorWrapper implements ActivityMonitor {
+
+ private final ActivityMonitor delegate;
+
+ public ActivityMonitorWrapper( ActivityMonitor delegate ) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, java.lang.Object[])
+ */
+ public void beginTask( double totalWork,
+ I18n name,
+ Object... params ) {
+ this.delegate.beginTask(totalWork, name, params);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#createSubtask(double)
+ */
+ public ActivityMonitor createSubtask( double subtaskWork ) {
+ return this.delegate.createSubtask(subtaskWork);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#done()
+ */
+ public void done() {
+ this.delegate.done();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getActivityName()
+ */
+ public String getActivityName() {
+ return delegate.getActivityName();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getActivityName(java.util.Locale)
+ */
+ public String getActivityName( Locale locale ) {
+ return delegate.getActivityName(locale);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getProblems()
+ */
+ public Problems getProblems() {
+ return delegate.getProblems();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getStatus(java.util.Locale)
+ */
+ public ActivityStatus getStatus( Locale locale ) {
+ return this.delegate.getStatus(locale);
+ }
+
+ public ActivityMonitor getWrappedMonitor() {
+ return this.delegate;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#isCancelled()
+ */
+ public boolean isCancelled() {
+ return this.delegate.isCancelled();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#isDone()
+ */
+ public boolean isDone() {
+ return delegate.isDone();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#setCancelled(boolean)
+ */
+ public void setCancelled( boolean value ) {
+ this.delegate.setCancelled(value);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#worked(double)
+ */
+ public void worked( double work ) {
+ this.delegate.worked(work);
+ }
+}
Copied: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityStatus.java (from rev 596, trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressStatus.java)
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityStatus.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ActivityStatus.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,208 @@
+/*
+ * 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.monitor;
+
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.StringUtil;
+
+/**
+ * A snapshot of the progress on an activity.
+ *
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+@Immutable
+public class ActivityStatus implements Serializable, Comparable<ActivityStatus> {
+
+ /**
+ */
+ private static final long serialVersionUID = -7771764546193063275L;
+ protected static final String PERCENTAGE_PATTERN = "##0.0"; // percentage should always fit
+ protected static final double PERCENT_PRECISION = 0.001d;
+
+ /**
+ * Compute the percentage worked, accounting for imprecision in
+ *
+ * @param workedSoFar the amount of work so far percentage worked
+ * @param totalWork the total amount of work for this activity
+ * @return the percentage worked
+ */
+ protected static double computePercentage( double workedSoFar,
+ double totalWork ) {
+ if (isSamePercentage(workedSoFar, 0.0d)) return 0.0d;
+ assert totalWork > 0.0d;
+ double percentage = workedSoFar / totalWork * 100.0d;
+ if (isSamePercentage(percentage, 100.0d)) percentage = 100.0d;
+ return percentage;
+ }
+
+ protected static boolean isSamePercentage( double percentage1,
+ double percentage2 ) {
+ return Math.abs(percentage1 - percentage2) <= PERCENT_PRECISION;
+ }
+
+ private final String activityName;
+ private final double percentWorked;
+ private final boolean done;
+ private final boolean cancelled;
+ private final String message;
+
+ /**
+ * Create the activity status.
+ *
+ * @param activityName the name of the activity, which may not be <code>null</code>
+ * @param message the message for the status, which may not be <code>null</code>
+ * @param percentWorked the percentage worked, ranging from 0.0 for not started to 100.0 for complete; a negative value are
+ * treated as 0.0, while a value greater than 100.0 is treated as 100.0
+ * @param cancelled <code>true</code> if the activity has been requested to be cancelled, or <code>false</code> otherwise
+ */
+ public ActivityStatus( String activityName,
+ String message,
+ double percentWorked,
+ boolean cancelled ) {
+ assert activityName != null;
+ assert message != null;
+ this.activityName = activityName;
+ this.done = percentWorked >= 100.0d;
+ this.percentWorked = this.done ? 100.0d : (percentWorked <= 0.0d ? 0.0d : percentWorked);
+ this.message = message;
+ this.cancelled = cancelled;
+ }
+
+ /**
+ * Create the activity status and compute the percentage worked.
+ *
+ * @param activityName the name of the activity, which may not be null
+ * @param message the message for the status, which may not be null
+ * @param workedSoFar the amount of work so far percentage worked
+ * @param totalWork the total amount of work for this activity
+ * @param cancelled true if the activity has been requested to be cancelled, or false otherwise
+ */
+ public ActivityStatus( String activityName,
+ String message,
+ double workedSoFar,
+ double totalWork,
+ boolean cancelled ) {
+ this(activityName, message, computePercentage(workedSoFar, totalWork), cancelled);
+ }
+
+ /**
+ * Get the name of the activity.
+ *
+ * @return the activity's name
+ */
+ public String getActivityName() {
+ return this.activityName;
+ }
+
+ /**
+ * Get the progress as a percentage of the total work that's been completed.
+ *
+ * @return the percentage worked, ranging from 0.0 to 100.0
+ */
+ public double getPercentWorked() {
+ return this.percentWorked;
+ }
+
+ /**
+ * Get the activity monitor's text message.
+ *
+ * @return the text message
+ */
+ public String getMessage() {
+ return this.message;
+ }
+
+ /**
+ * Return whether work on this activity has completed.
+ *
+ * @return true if work has completed, or false if work on the activity is still progressing
+ * @see #isCancelled()
+ */
+ public boolean isDone() {
+ return done;
+ }
+
+ /**
+ * Return whether the activity was requested to be cancelled.
+ *
+ * @return cancelled
+ * @see #isDone()
+ */
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ String percentage = new DecimalFormat(PERCENTAGE_PATTERN).format(getPercentWorked());
+ percentage = StringUtil.justifyRight(percentage, PERCENTAGE_PATTERN.length(), ' ');
+ String cancelled = this.isCancelled() ? " (cancelled)" : "";
+ return this.activityName + " (" + this.message + ") " + percentage + " %" + cancelled;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return this.getActivityName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (this == obj) return true;
+ if (obj instanceof ActivityStatus) {
+ final ActivityStatus that = (ActivityStatus)obj;
+ // First check that the name is the same ...
+ if (!this.getActivityName().equals(that.getActivityName())) return false;
+ // Then check doneness and percent complete ...
+ if (this.isDone() != that.isDone()) return false;
+ if (!isSamePercentage(this.getPercentWorked(), that.getPercentWorked())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo( ActivityStatus that ) {
+ if (this == that) return 0;
+
+ // First check the name ...
+ int diff = this.getActivityName().compareTo(that.getActivityName());
+ if (diff != 0) return diff;
+
+ // Then check the percentage ...
+ return Double.compare(this.getPercentWorked(), that.getPercentWorked());
+ }
+}
Copied: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingActivityMonitor.java (from rev 596, trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingProgressMonitor.java)
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingActivityMonitor.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingActivityMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,96 @@
+/*
+ * 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.monitor;
+
+import java.util.Locale;
+import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.Logger;
+
+/**
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public class LoggingActivityMonitor extends ActivityMonitorWrapper {
+
+ private final Logger logger;
+ private final Logger.Level level;
+ private final Locale locale;
+
+ public LoggingActivityMonitor( ActivityMonitor delegate,
+ Logger logger,
+ Logger.Level level ) {
+ this(delegate, logger, level, null);
+ }
+
+ public LoggingActivityMonitor( ActivityMonitor delegate,
+ Logger logger,
+ Logger.Level level,
+ Locale locale ) {
+ super(delegate);
+ assert level != null;
+ assert logger != null;
+ this.level = level;
+ this.logger = logger;
+ this.locale = locale;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void beginTask( double totalWork,
+ I18n name,
+ Object... params ) {
+ super.beginTask(totalWork, name, params);
+ this.logger.log(level, CommonI18n.activityMonitorBeginTask, getActivityName(), name.text(params));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void done() {
+ super.done();
+ this.logger.log(level, CommonI18n.activityMonitorStatus, super.getStatus(this.locale));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setCancelled( boolean value ) {
+ super.setCancelled(value);
+ this.logger.log(level, CommonI18n.activityMonitorStatus, super.getStatus(this.locale));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void worked( double work ) {
+ super.worked(work);
+ this.logger.log(level, CommonI18n.activityMonitorStatus, super.getStatus(this.locale));
+ }
+
+}
Deleted: 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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/LoggingProgressMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,88 +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.monitor;
-
-import java.util.Locale;
-import org.jboss.dna.common.CommonI18n;
-import org.jboss.dna.common.i18n.I18n;
-import org.jboss.dna.common.util.Logger;
-
-/**
- * @author Randall Hauch
- */
-public class LoggingProgressMonitor extends ProgressMonitorWrapper {
-
- private final Logger logger;
- private final Logger.Level level;
- private final Locale locale;
-
- public LoggingProgressMonitor( ProgressMonitor delegate, Logger logger, Logger.Level level ) {
- this(delegate, logger, level, null);
- }
-
- public LoggingProgressMonitor( ProgressMonitor delegate, Logger logger, Logger.Level level, Locale locale ) {
- super(delegate);
- assert level != null;
- assert logger != null;
- this.level = level;
- this.logger = logger;
- this.locale = locale;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void beginTask( double totalWork, I18n name, Object... params ) {
- super.beginTask(totalWork, name, params);
- this.logger.log(level, CommonI18n.progressMonitorBeginTask, getActivityName(), name.text(params));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void done() {
- super.done();
- this.logger.log(level, CommonI18n.progressMonitorStatus, super.getStatus(this.locale));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setCancelled( boolean value ) {
- super.setCancelled(value);
- this.logger.log(level, CommonI18n.progressMonitorStatus, super.getStatus(this.locale));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void worked( double work ) {
- super.worked(work);
- this.logger.log(level, CommonI18n.progressMonitorStatus, super.getStatus(this.locale));
- }
-
-}
Deleted: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,141 +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.monitor;
-
-import java.util.Locale;
-import org.jboss.dna.common.collection.Problems;
-import org.jboss.dna.common.i18n.I18n;
-
-/**
- * A basic progress monitor that facilitates the updating and monitoring of progress towards the completion of an activity.
- * Documentation hereafter will refer to the code in an application that updates progress as the <strong>Updater</strong>, and
- * code that monitors progress as an <strong>Observer</strong>.
- * <p>
- * The progress of each {@link #getActivityName() activity} is started when the <strong>Updater</strong> calls
- * {@link #beginTask(double, I18n, Object...)}, continues with a mixture of work ({@link #worked(double)}) and subtasks (
- * {@link #createSubtask(double)}), and finishes when the activity is completed ({@link #done()}) or cancelled (
- * {@link #setCancelled(boolean)}).
- * </p>
- * <p>
- * If an activity is interrupted before its normal completion due to a cancellation request by an <strong>Observer</strong>, it is
- * still the responsibility of the <strong>Updater</strong> to mark the activity as completed. Similarly, if an activity cannot be
- * cancelled before its normal completion, the <strong>Updater</strong> must deny any previous cancellation request by calling
- * {@link #setCancelled(boolean) setCancelled(false)}.
- * </p>
- *
- * @author Randall Hauch
- * @author John Verhaeg
- */
-public interface ProgressMonitor {
-
- /**
- * Called by the <strong>Updater</strong> to indicate work has started on the task, specifying the total amount of work that
- * this task constitutes.
- *
- * @param totalWork the total number of work units for the task
- * @param name the name of the task
- * @param params the parameters for localization
- */
- void beginTask( double totalWork,
- I18n name,
- Object... params );
-
- /**
- * Called by the <strong>Updater</strong> to create a subtask with the given about of work. The resulting progress monitor
- * must be started ({@link #beginTask(double, I18n, Object...)}) and finished ({@link #done()}).
- *
- * @param subtaskWork the number of work units for this subtask
- * @return the progress monitor for the subtask
- */
- ProgressMonitor createSubtask( double subtaskWork );
-
- /**
- * Called by the <strong>Updater</strong> to mark this activity as complete. This method must be called, even if the activity
- * has been cancelled.
- */
- void done();
-
- /**
- * Get the name of the activity. This should never change for a progress monitor, and all {@link #createSubtask(double)
- * subtasks} should have the same name.
- *
- * @return the activity's name; never <code>null</code>
- */
- String getActivityName();
-
- /**
- * Get the name of the activity that spawned this activity. This should never change for a progress monitor.
- *
- * @return the parent activity's name; never <code>null</code>
- */
- String getParentActivityName();
-
- /**
- * Return the problems encountered during the {@link #getStatus(Locale) progress} made towards completing the associated
- * {@link #getActivityName() activity}.
- *
- * @return the list of problems
- */
- Problems getProblems();
-
- /**
- * Return the current status of this activity, localized to the specified locale. This method returns an immutable but
- * consistent snapshot of the status for this activity. Note that if this instance is a {@link #createSubtask(double) subtask}
- * , this method returns the status of the subtask.
- *
- * @param locale the locale in which the status is to be represented; if null, the {@link Locale#getDefault() default locale}
- * will be used
- * @return the status of this activity
- */
- ProgressStatus getStatus( Locale locale );
-
- /**
- * Return whether a request was made by an <strong>Observer</strong> to {@link #setCancelled(boolean) cancel} this activity.
- *
- * @return <code>true</code> if this activity has been requested to be cancelled.
- */
- boolean isCancelled();
-
- /**
- * Return whether this activity has completed.
- *
- * @return <code>true</code> if this activity has completed.
- */
- boolean isDone();
-
- /**
- * Called by an <strong>Observer</strong> to request the cancellation of this activity, or by the <strong>Updater</strong> to
- * deny a prior cancellation request (i.e., when the activity {@link #done() completes} before the <strong>Updater</strong>
- * recognizes a cancellation request by an <strong>Observer</strong>).
- *
- * @param value <code>true</code> if requesting the activity be cancelled.
- */
- void setCancelled( boolean value );
-
- /**
- * Called by the <strong>Updater</strong> to report work completed for this task.
- *
- * @param work the number of work units that have been worked
- */
- void worked( double work );
-}
Deleted: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,107 +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.monitor;
-
-import java.util.Locale;
-import org.jboss.dna.common.collection.Problems;
-import org.jboss.dna.common.i18n.I18n;
-
-/**
- * The thread safety of this class is determined by the delegate.
- *
- * @author Randall Hauch
- * @author John Verhaeg
- */
-public class ProgressMonitorWrapper implements ProgressMonitor {
-
- private final ProgressMonitor delegate;
-
- public ProgressMonitorWrapper( ProgressMonitor delegate ) {
- this.delegate = delegate;
- }
-
- public void beginTask( double totalWork,
- I18n name,
- Object... params ) {
- this.delegate.beginTask(totalWork, name, params);
- }
-
- public ProgressMonitor createSubtask( double subtaskWork ) {
- return this.delegate.createSubtask(subtaskWork);
- }
-
- public void done() {
- this.delegate.done();
- }
-
- public String getActivityName() {
- return this.delegate.getActivityName();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getParentActivityName()
- */
- public String getParentActivityName() {
- return this.delegate.getParentActivityName();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems()
- */
- public Problems getProblems() {
- return delegate.getProblems();
- }
-
- public ProgressStatus getStatus( Locale locale ) {
- return this.delegate.getStatus(locale);
- }
-
- public ProgressMonitor getWrappedMonitor() {
- return this.delegate;
- }
-
- public boolean isCancelled() {
- return this.delegate.isCancelled();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#isDone()
- */
- public boolean isDone() {
- return delegate.isDone();
- }
-
- public void setCancelled( boolean value ) {
- this.delegate.setCancelled(value);
- }
-
- public void worked( double work ) {
- this.delegate.worked(work);
- }
-}
Deleted: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressStatus.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressStatus.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressStatus.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,207 +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.monitor;
-
-import java.io.Serializable;
-import java.text.DecimalFormat;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.util.StringUtil;
-
-/**
- * A snapshot of the progress on an activity.
- *
- * @author Randall Hauch
- */
-@Immutable
-public class ProgressStatus implements Serializable, Comparable<ProgressStatus> {
-
- /**
- */
- private static final long serialVersionUID = -7771764546193063275L;
- protected static final String PERCENTAGE_PATTERN = "##0.0"; // percentage should always fit
- protected static final double PERCENT_PRECISION = 0.001d;
-
- /**
- * Compute the percentage worked, accounting for imprecision in
- *
- * @param workedSoFar the amount of work so far percentage worked
- * @param totalWork the total amount of work for this activity
- * @return the percentage worked
- */
- protected static double computePercentage( double workedSoFar,
- double totalWork ) {
- if (isSamePercentage(workedSoFar, 0.0d)) return 0.0d;
- assert totalWork > 0.0d;
- double percentage = workedSoFar / totalWork * 100.0d;
- if (isSamePercentage(percentage, 100.0d)) percentage = 100.0d;
- return percentage;
- }
-
- protected static boolean isSamePercentage( double percentage1,
- double percentage2 ) {
- return Math.abs(percentage1 - percentage2) <= PERCENT_PRECISION;
- }
-
- private final String activityName;
- private final double percentWorked;
- private final boolean done;
- private final boolean cancelled;
- private final String message;
-
- /**
- * Create the progress status.
- *
- * @param activityName the name of the activity, which may not be null
- * @param message the message for the progress, which may not be null
- * @param percentWorked the percentage worked, ranging from 0.0 for not started to 100.0 for complete; a negative value are
- * treated as 0.0, while a value greater than 100.0 is treated as 100.0
- * @param cancelled true if the activity has been requested to be cancelled, or false otherwise
- */
- public ProgressStatus( String activityName,
- String message,
- double percentWorked,
- boolean cancelled ) {
- assert activityName != null;
- assert message != null;
- this.activityName = activityName;
- this.done = percentWorked >= 100.0d;
- this.percentWorked = this.done ? 100.0d : (percentWorked <= 0.0d ? 0.0d : percentWorked);
- this.message = message;
- this.cancelled = cancelled;
- }
-
- /**
- * Create the progress status and compute the percentage worked.
- *
- * @param activityName the name of the activity, which may not be null
- * @param message the message for the progress, which may not be null
- * @param workedSoFar the amount of work so far percentage worked
- * @param totalWork the total amount of work for this activity
- * @param cancelled true if the activity has been requested to be cancelled, or false otherwise
- */
- public ProgressStatus( String activityName,
- String message,
- double workedSoFar,
- double totalWork,
- boolean cancelled ) {
- this(activityName, message, computePercentage(workedSoFar, totalWork), cancelled);
- }
-
- /**
- * Get the name of the activity.
- *
- * @return the activity's name
- */
- public String getActivityName() {
- return this.activityName;
- }
-
- /**
- * Get the progress as a percentage of the total work that's been completed.
- *
- * @return the percentage worked, ranging from 0.0 to 100.0
- */
- public double getPercentWorked() {
- return this.percentWorked;
- }
-
- /**
- * Get the progress monitor's text message.
- *
- * @return the text message
- */
- public String getMessage() {
- return this.message;
- }
-
- /**
- * Return whether work on this activity has completed.
- *
- * @return true if work has completed, or false if work on the activity is still progressing
- * @see #isCancelled()
- */
- public boolean isDone() {
- return done;
- }
-
- /**
- * Return whether the activity was requested to be cancelled.
- *
- * @return cancelled
- * @see #isDone()
- */
- public boolean isCancelled() {
- return this.cancelled;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- String percentage = new DecimalFormat(PERCENTAGE_PATTERN).format(getPercentWorked());
- percentage = StringUtil.justifyRight(percentage, PERCENTAGE_PATTERN.length(), ' ');
- String cancelled = this.isCancelled() ? " (cancelled)" : "";
- return this.activityName + " (" + this.message + ") " + percentage + " %" + cancelled;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return this.getActivityName().hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals( Object obj ) {
- if (this == obj) return true;
- if (obj instanceof ProgressStatus) {
- final ProgressStatus that = (ProgressStatus)obj;
- // First check that the name is the same ...
- if (!this.getActivityName().equals(that.getActivityName())) return false;
- // Then check doneness and percent complete ...
- if (this.isDone() != that.isDone()) return false;
- if (!isSamePercentage(this.getPercentWorked(), that.getPercentWorked())) return false;
- return true;
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public int compareTo( ProgressStatus that ) {
- if (this == that) return 0;
-
- // First check the name ...
- int diff = this.getActivityName().compareTo(that.getActivityName());
- if (diff != 0) return diff;
-
- // Then check the percentage ...
- return Double.compare(this.getPercentWorked(), that.getPercentWorked());
- }
-}
Copied: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleActivityMonitor.java (from rev 596, trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java)
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleActivityMonitor.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleActivityMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,228 @@
+/*
+ * 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.monitor;
+
+import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.GuardedBy;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.collection.ThreadSafeProblems;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
+
+/**
+ * A basic activity monitor.
+ *
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+@ThreadSafe
+public class SimpleActivityMonitor implements ActivityMonitor {
+
+ @GuardedBy( "lock" )
+ private I18n taskName;
+ @GuardedBy( "lock" )
+ private Object[] taskNameParams;
+ @GuardedBy( "lock" )
+ private double totalWork;
+ @GuardedBy( "lock" )
+ private double worked;
+
+ private final I18n activityName;
+ private final Object[] activityNameParams;
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final AtomicBoolean cancelled = new AtomicBoolean(false);
+ private final Problems problems = new ThreadSafeProblems();
+
+ public SimpleActivityMonitor( I18n activityName,
+ Object... params ) {
+ CheckArg.isNotNull(activityName, "activityName");
+ this.activityName = activityName;
+ this.activityNameParams = params;
+ this.taskName = null;
+ this.taskNameParams = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, java.lang.Object[])
+ */
+ public void beginTask( double totalWork,
+ I18n name,
+ Object... params ) {
+ CheckArg.isGreaterThan(totalWork, 0.0, "totalWork");
+ try {
+ this.lock.writeLock().lock();
+ this.taskName = name;
+ this.taskNameParams = params;
+ this.totalWork = totalWork;
+ this.worked = 0.0d;
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#createSubtask(double)
+ */
+ public ActivityMonitor createSubtask( double subtaskWork ) {
+ return new SubActivityMonitor(this, subtaskWork);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#done()
+ */
+ public void done() {
+ boolean alreadyDone = false;
+ try {
+ this.lock.writeLock().lock();
+ if (this.worked < this.totalWork) {
+ this.worked = this.totalWork;
+ } else {
+ alreadyDone = true;
+ }
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ if (!alreadyDone) notifyProgress();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getActivityName()
+ */
+ public String getActivityName() {
+ return getActivityName(null);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getActivityName(java.util.Locale)
+ */
+ public String getActivityName( Locale locale ) {
+ return activityName.text(locale == null ? Locale.getDefault() : locale, activityNameParams);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Problems must only be added by the {@link ActivityMonitor <strong>Updater</strong>}, and accessed by
+ * {@link ActivityMonitor Observers} only after the activity has been {@link #done() completed}.
+ * </p>
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getProblems()
+ */
+ public Problems getProblems() {
+ return problems;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getStatus(java.util.Locale)
+ */
+ public ActivityStatus getStatus( Locale locale ) {
+ try {
+ this.lock.readLock().lock();
+ String localizedTaskName = this.taskName == null ? "" : this.taskName.text(locale, this.taskNameParams);
+ return new ActivityStatus(this.getActivityName(locale), localizedTaskName, this.worked, this.totalWork,
+ this.isCancelled());
+ } finally {
+ this.lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#isCancelled()
+ */
+ public boolean isCancelled() {
+ return this.cancelled.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#isDone()
+ */
+ public boolean isDone() {
+ lock.readLock().lock();
+ try {
+ return worked >= totalWork;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Method that is called in {@link #worked(double)} (which is called by {@link #createSubtask(double) subtasks}) when there
+ * has been some positive work, or when the monitor is first marked as {@link #done()}.
+ * <p>
+ * This method implementation does nothing, but subclasses can easily override this method if they want to be updated with the
+ * latest progress.
+ * </p>
+ */
+ protected void notifyProgress() {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#setCancelled(boolean)
+ */
+ public void setCancelled( boolean value ) {
+ this.cancelled.set(value);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#worked(double)
+ */
+ public void worked( double work ) {
+ if (work > 0) {
+ try {
+ this.lock.writeLock().lock();
+ if (this.worked < this.totalWork) {
+ this.worked += work;
+ if (this.worked > this.totalWork) this.worked = this.totalWork;
+ }
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ notifyProgress();
+ }
+ }
+}
Deleted: 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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,230 +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.monitor;
-
-import java.util.Locale;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import net.jcip.annotations.GuardedBy;
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.collection.Problems;
-import org.jboss.dna.common.collection.ThreadSafeProblems;
-import org.jboss.dna.common.i18n.I18n;
-import org.jboss.dna.common.util.CheckArg;
-
-/**
- * A basic progress monitor.
- *
- * @author Randall Hauch
- * @author John Verhaeg
- */
-@ThreadSafe
-public class SimpleProgressMonitor implements ProgressMonitor {
-
- @GuardedBy( "lock" )
- private I18n taskName;
- @GuardedBy( "lock" )
- private Object[] taskNameParams;
- @GuardedBy( "lock" )
- private double totalWork;
- @GuardedBy( "lock" )
- private double worked;
-
- private final String activityName;
- private final String parentActivityName;
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
- private final AtomicBoolean cancelled = new AtomicBoolean(false);
- private final Problems problems = new ThreadSafeProblems();
-
- public SimpleProgressMonitor( String activityName ) {
- this(activityName, null);
- }
-
- public SimpleProgressMonitor( String activityName,
- ProgressMonitor parentProgressMonitor ) {
- this.activityName = activityName == null ? "" : activityName.trim();
- this.parentActivityName = parentProgressMonitor == null ? "" : parentProgressMonitor.getActivityName();
- this.taskName = null;
- this.taskNameParams = null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, java.lang.Object[])
- */
- public void beginTask( double totalWork,
- I18n name,
- Object... params ) {
- CheckArg.isGreaterThan(totalWork, 0.0, "totalWork");
- try {
- this.lock.writeLock().lock();
- this.taskName = name;
- this.taskNameParams = params;
- this.totalWork = totalWork;
- this.worked = 0.0d;
- } finally {
- this.lock.writeLock().unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#createSubtask(double)
- */
- public ProgressMonitor createSubtask( double subtaskWork ) {
- return new SubProgressMonitor(this, subtaskWork);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#done()
- */
- public void done() {
- boolean alreadyDone = false;
- try {
- this.lock.writeLock().lock();
- if (this.worked < this.totalWork) {
- this.worked = this.totalWork;
- } else {
- alreadyDone = true;
- }
- } finally {
- this.lock.writeLock().unlock();
- }
- if (!alreadyDone) notifyProgress();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getActivityName()
- */
- public String getActivityName() {
- return this.activityName;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getParentActivityName()
- */
- public String getParentActivityName() {
- return this.parentActivityName;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Problems must only be added by the {@link ProgressMonitor <strong>Updater</strong>}, and accessed by
- * {@link ProgressMonitor Observers} only after the activity has been {@link #done() completed}.
- * </p>
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems()
- */
- public Problems getProblems() {
- return problems;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getStatus(java.util.Locale)
- */
- public ProgressStatus getStatus( Locale locale ) {
- try {
- this.lock.readLock().lock();
- String localizedTaskName = this.taskName == null ? "" : this.taskName.text(locale, this.taskNameParams);
- return new ProgressStatus(this.getActivityName(), localizedTaskName, this.worked, this.totalWork, this.isCancelled());
- } finally {
- this.lock.readLock().unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#isCancelled()
- */
- public boolean isCancelled() {
- return this.cancelled.get();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#isDone()
- */
- public boolean isDone() {
- lock.readLock().lock();
- try {
- return worked >= totalWork;
- } finally {
- lock.readLock().unlock();
- }
- }
-
- /**
- * Method that is called in {@link #worked(double)} (which is called by {@link #createSubtask(double) subtasks}) when there
- * has been some positive work, or when the monitor is first marked as {@link #done()}.
- * <p>
- * This method implementation does nothing, but subclasses can easily override this method if they want to be updated with the
- * latest progress.
- * </p>
- */
- protected void notifyProgress() {
- // do nothing
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#setCancelled(boolean)
- */
- public void setCancelled( boolean value ) {
- this.cancelled.set(value);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#worked(double)
- */
- public void worked( double work ) {
- if (work > 0) {
- try {
- this.lock.writeLock().lock();
- if (this.worked < this.totalWork) {
- this.worked += work;
- if (this.worked > this.totalWork) this.worked = this.totalWork;
- }
- } finally {
- this.lock.writeLock().unlock();
- }
- notifyProgress();
- }
- }
-}
Copied: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubActivityMonitor.java (from rev 596, trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java)
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubActivityMonitor.java (rev 0)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubActivityMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,209 @@
+/*
+ * 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.monitor;
+
+import java.util.Locale;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.GuardedBy;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * This class is thread-safe except when accessing or adding {@link #getProblems() problems}. Problems must only be added by the
+ * {@link ActivityMonitor <strong>Updater</strong>}, and accessed by {@link ActivityMonitor Observers} only after the activity has
+ * been {@link #done() completed}.
+ *
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public class SubActivityMonitor implements ActivityMonitor {
+
+ @GuardedBy( "lock" )
+ private I18n taskName;
+ @GuardedBy( "lock" )
+ private Object[] params;
+ @GuardedBy( "lock" )
+ private double totalWork;
+ @GuardedBy( "lock" )
+ private double parentWorkScaleFactor;
+ @GuardedBy( "lock" )
+ private double submittedToParent;
+
+ private final double subtaskTotalInParent;
+ private final ActivityMonitor parent;
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ public SubActivityMonitor( final ActivityMonitor parent,
+ final double subtaskTotalInParent ) {
+ assert subtaskTotalInParent > 0;
+ assert parent != null;
+ this.parent = parent;
+ this.subtaskTotalInParent = subtaskTotalInParent;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, java.lang.Object[])
+ */
+ public void beginTask( double totalWork,
+ I18n name,
+ Object... params ) {
+ assert totalWork > 0;
+ try {
+ this.lock.writeLock().lock();
+ this.taskName = name;
+ this.params = params;
+ this.totalWork = totalWork;
+ this.parentWorkScaleFactor = ((float)subtaskTotalInParent) / ((float)totalWork);
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#createSubtask(double)
+ */
+ public ActivityMonitor createSubtask( double subtaskWork ) {
+ return new SubActivityMonitor(this, subtaskWork);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#done()
+ */
+ public void done() {
+ // Compute the total work for this task in terms of the parent ...
+ double workInParentRemaining = 0.0d;
+ try {
+ this.lock.writeLock().lock();
+ double totalWorkInParent = this.totalWork * this.parentWorkScaleFactor;
+ workInParentRemaining = totalWorkInParent - this.submittedToParent;
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ // Don't do this in the lock: it's incremental, but doing so might cause deadlock with future changes
+ this.parent.worked(workInParentRemaining);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getActivityName()
+ */
+ public String getActivityName() {
+ return parent.getActivityName();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getActivityName(java.util.Locale)
+ */
+ public String getActivityName( Locale locale ) {
+ return parent.getActivityName(locale);
+ }
+
+ /**
+ * @return parent
+ */
+ public ActivityMonitor getParent() {
+ return this.parent;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getProblems()
+ */
+ public Problems getProblems() {
+ return parent.getProblems();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#getStatus(java.util.Locale)
+ */
+ public ActivityStatus getStatus( Locale locale ) {
+ try {
+ this.lock.readLock().lock();
+ return new ActivityStatus(getActivityName(), this.taskName.text(locale, this.params), this.submittedToParent,
+ this.subtaskTotalInParent, this.isCancelled());
+ } finally {
+ this.lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#isCancelled()
+ */
+ public boolean isCancelled() {
+ return this.parent.isCancelled();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#isDone()
+ */
+ public boolean isDone() {
+ return parent.isDone();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#setCancelled(boolean)
+ */
+ public void setCancelled( boolean value ) {
+ this.parent.setCancelled(value);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ActivityMonitor#worked(double)
+ */
+ public void worked( double work ) {
+ if (this.isCancelled()) return;
+ if (work > 0) {
+ double workInParent = 0.0d;
+ try {
+ this.lock.writeLock().lock();
+ workInParent = work * parentWorkScaleFactor;
+ this.submittedToParent += workInParent;
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ // Don't do this in the lock: it's incremental, but doing so might cause deadlock with future changes
+ this.parent.worked(workInParent);
+ }
+ }
+}
Deleted: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,208 +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.monitor;
-
-import java.util.Locale;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import net.jcip.annotations.GuardedBy;
-import org.jboss.dna.common.collection.Problems;
-import org.jboss.dna.common.i18n.I18n;
-
-/**
- * This class is thread-safe except when accessing or adding {@link #getProblems() problems}. Problems must only be added by the
- * {@link ProgressMonitor <strong>Updater</strong>}, and accessed by {@link ProgressMonitor Observers} only after the activity has
- * been {@link #done() completed}.
- *
- * @author Randall Hauch
- */
-public class SubProgressMonitor implements ProgressMonitor {
-
- @GuardedBy( "lock" )
- private I18n taskName;
- @GuardedBy( "lock" )
- private Object[] params;
- @GuardedBy( "lock" )
- private double totalWork;
- @GuardedBy( "lock" )
- private double parentWorkScaleFactor;
- @GuardedBy( "lock" )
- private double submittedToParent;
-
- private final double subtaskTotalInParent;
- private final ProgressMonitor parent;
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
-
- public SubProgressMonitor( final ProgressMonitor parent,
- final double subtaskTotalInParent ) {
- assert subtaskTotalInParent > 0;
- assert parent != null;
- this.parent = parent;
- this.subtaskTotalInParent = subtaskTotalInParent;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, java.lang.Object[])
- */
- public void beginTask( double totalWork,
- I18n name,
- Object... params ) {
- assert totalWork > 0;
- try {
- this.lock.writeLock().lock();
- this.taskName = name;
- this.params = params;
- this.totalWork = totalWork;
- this.parentWorkScaleFactor = ((float)subtaskTotalInParent) / ((float)totalWork);
- } finally {
- this.lock.writeLock().unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#createSubtask(double)
- */
- public ProgressMonitor createSubtask( double subtaskWork ) {
- return new SubProgressMonitor(this, subtaskWork);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#done()
- */
- public void done() {
- // Compute the total work for this task in terms of the parent ...
- double workInParentRemaining = 0.0d;
- try {
- this.lock.writeLock().lock();
- double totalWorkInParent = this.totalWork * this.parentWorkScaleFactor;
- workInParentRemaining = totalWorkInParent - this.submittedToParent;
- } finally {
- this.lock.writeLock().unlock();
- }
- // Don't do this in the lock: it's incremental, but doing so might cause deadlock with future changes
- this.parent.worked(workInParentRemaining);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getActivityName()
- */
- public String getActivityName() {
- return this.parent.getActivityName();
- }
-
- /**
- * @return parent
- */
- public ProgressMonitor getParent() {
- return this.parent;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getParentActivityName()
- */
- public String getParentActivityName() {
- return parent.getParentActivityName();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems()
- */
- public Problems getProblems() {
- return parent.getProblems();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getStatus(java.util.Locale)
- */
- public ProgressStatus getStatus( Locale locale ) {
- try {
- this.lock.readLock().lock();
- return new ProgressStatus(this.getActivityName(), this.taskName.text(locale, this.params), this.submittedToParent,
- this.subtaskTotalInParent, this.isCancelled());
- } finally {
- this.lock.readLock().unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#isCancelled()
- */
- public boolean isCancelled() {
- return this.parent.isCancelled();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#isDone()
- */
- public boolean isDone() {
- return parent.isDone();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#setCancelled(boolean)
- */
- public void setCancelled( boolean value ) {
- this.parent.setCancelled(value);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#worked(double)
- */
- public void worked( double work ) {
- if (this.isCancelled()) return;
- if (work > 0) {
- double workInParent = 0.0d;
- try {
- this.lock.writeLock().lock();
- workInParent = work * parentWorkScaleFactor;
- this.submittedToParent += workInParent;
- } finally {
- this.lock.writeLock().unlock();
- }
- // Don't do this in the lock: it's incremental, but doing so might cause deadlock with future changes
- this.parent.worked(workInParent);
- }
- }
-}
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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties 2008-10-29 20:09:42 UTC (rev 599)
@@ -66,13 +66,13 @@
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
dateParsingFailure = Unable to parse the date "{0}" using the standard ISO 8601 format
-initialProgressMonitorTaskName =
-nullProgressMonitorTaskName = Not available
+initialActivityMonitorTaskName =
+nullActivityMonitorTaskName = Not available
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
-progressMonitorBeginTask = Beginning {0} ({1})
-progressMonitorStatus = {0}
+activityMonitorBeginTask = Beginning {0} ({1})
+activityMonitorStatus = {0}
requiredToSuppliedParameterMismatch = {0} parameter{1} supplied, but {2} parameter{3} required: "{4}" => "{5}"
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/component/ComponentLibraryTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/component/ComponentLibraryTest.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/ComponentLibraryTest.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -28,7 +28,7 @@
import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import java.util.List;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@@ -47,7 +47,7 @@
private String validDescription;
private String[] validClasspath;
@Mock
- private ProgressMonitor nullMonitor;
+ private ActivityMonitor nullMonitor;
@Before
public void beforeEach() {
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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentA.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -25,11 +25,13 @@
import java.util.concurrent.atomic.AtomicInteger;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.i18n.MockI18n;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
/**
* A sequencer that can be used for basic unit testing.
+ *
* @author Randall Hauch
+ * @author John Verhaeg
*/
@ThreadSafe
public class MockComponentA implements SampleComponent {
@@ -47,14 +49,14 @@
/**
* {@inheritDoc}
*/
- public void doSomething( ProgressMonitor progressMonitor ) {
+ public void doSomething( ActivityMonitor activityMonitor ) {
try {
- progressMonitor.beginTask(1, MockI18n.passthrough, "Incrementing counter");
+ activityMonitor.beginTask(1, MockI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
- progressMonitor.worked(1);
+ activityMonitor.worked(1);
} finally {
- progressMonitor.done();
+ activityMonitor.done();
}
}
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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/MockComponentB.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -25,11 +25,13 @@
import java.util.concurrent.atomic.AtomicInteger;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.i18n.MockI18n;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
/**
* A sequencer that can be used for basic unit testing.
+ *
* @author Randall Hauch
+ * @author John Verhaeg
*/
@ThreadSafe
public class MockComponentB implements SampleComponent {
@@ -47,14 +49,14 @@
/**
* {@inheritDoc}
*/
- public void doSomething( ProgressMonitor progressMonitor ) {
+ public void doSomething( ActivityMonitor activityMonitor ) {
try {
- progressMonitor.beginTask(1, MockI18n.passthrough, "Incrementing counter");
+ activityMonitor.beginTask(1, MockI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
- progressMonitor.worked(1);
+ activityMonitor.worked(1);
} finally {
- progressMonitor.done();
+ activityMonitor.done();
}
}
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/component/SampleComponent.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/component/SampleComponent.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/SampleComponent.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -21,12 +21,13 @@
*/
package org.jboss.dna.common.component;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
/**
* @author Randall Hauch
+ * @author John Verhaeg
*/
public interface SampleComponent extends Component<SampleComponentConfig> {
- public void doSomething( ProgressMonitor progressMonitor );
+ public void doSomething( ActivityMonitor activityMonitor );
}
Copied: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ActivityStatusTest.java (from rev 596, trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ProgressStatusTest.java)
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ActivityStatusTest.java (rev 0)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ActivityStatusTest.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,66 @@
+/*
+ * 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.monitor;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.number.IsCloseTo.closeTo;
+import static org.junit.Assert.assertThat;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public class ActivityStatusTest {
+
+ private ActivityStatus status;
+ private String validActivityName;
+ private String validTaskName;
+
+ @Before
+ public void beforeEach() {
+ this.validActivityName = "Reading from file X";
+ this.validTaskName = "Checking for file";
+ this.status = new ActivityStatus(this.validActivityName, this.validTaskName, 10.0d, false);
+ }
+
+ @Test
+ public void shouldComputePercentageAs100PercentIfWithinPrecision() {
+ assertThat(ActivityStatus.computePercentage(100.0d - (ActivityStatus.PERCENT_PRECISION / 2.0d), 100.0d),
+ is(closeTo(100.0d, ActivityStatus.PERCENT_PRECISION)));
+ }
+
+ @Test
+ public void shouldComputePercentageOfZeroWorkAsZero() {
+ // Note that we should not get a divide by zero !!!
+ assertThat(ActivityStatus.computePercentage(0.0d, 0.0d), is(closeTo(0.0d, ActivityStatus.PERCENT_PRECISION)));
+ assertThat(ActivityStatus.computePercentage(0.0d, 100.0d), is(closeTo(0.0d, ActivityStatus.PERCENT_PRECISION)));
+ }
+
+ @Test
+ public void shouldHaveToStringThatIncludesPercentage() {
+ // System.out.println(this.status);
+ assertThat(this.status.toString().indexOf("10.0 %") > 0, is(true));
+ }
+}
Deleted: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ProgressStatusTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ProgressStatusTest.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/ProgressStatusTest.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -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.common.monitor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.number.IsCloseTo.closeTo;
-import static org.junit.Assert.assertThat;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- */
-public class ProgressStatusTest {
-
- private ProgressStatus status;
- private String validActivityName;
- private String validTaskName;
-
- @Before
- public void beforeEach() {
- this.validActivityName = "Reading from file X";
- this.validTaskName = "Checking for file";
- this.status = new ProgressStatus(this.validActivityName, this.validTaskName, 10.0d, false);
- }
-
- @Test
- public void shouldComputePercentageAs100PercentIfWithinPrecision() {
- assertThat(ProgressStatus.computePercentage(100.0d - (ProgressStatus.PERCENT_PRECISION / 2.0d), 100.0d),
- is(closeTo(100.0d, ProgressStatus.PERCENT_PRECISION)));
- }
-
- @Test
- public void shouldComputePercentageOfZeroWorkAsZero() {
- // Note that we should not get a divide by zero !!!
- assertThat(ProgressStatus.computePercentage(0.0d, 0.0d), is(closeTo(0.0d, ProgressStatus.PERCENT_PRECISION)));
- assertThat(ProgressStatus.computePercentage(0.0d, 100.0d), is(closeTo(0.0d, ProgressStatus.PERCENT_PRECISION)));
- }
-
- @Test
- public void shouldHaveToStringThatIncludesPercentage() {
- // System.out.println(this.status);
- assertThat(this.status.toString().indexOf("10.0 %") > 0, is(true));
- }
-}
Copied: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingActivityMonitor.java (from rev 596, trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java)
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingActivityMonitor.java (rev 0)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingActivityMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,111 @@
+/*
+ * 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.monitor;
+
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.i18n.MockI18n;
+
+/**
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public class RecordingActivityMonitor extends ActivityMonitorWrapper {
+
+ private int beginTaskCount;
+ private int doneCount;
+ private int createSubtaskCount;
+ private int setCancelledCount;
+
+ public RecordingActivityMonitor( ActivityMonitor delegate ) {
+ super(delegate);
+ }
+
+ public RecordingActivityMonitor( String name ) {
+ this(new SimpleActivityMonitor(MockI18n.passthrough, name));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void beginTask( double totalWork,
+ I18n name,
+ Object... params ) {
+ ++beginTaskCount;
+ super.beginTask(totalWork, name, params);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void done() {
+ ++doneCount;
+ super.done();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ActivityMonitor createSubtask( double subtaskWork ) {
+ ++createSubtaskCount;
+ return super.createSubtask(subtaskWork);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setCancelled( boolean value ) {
+ ++setCancelledCount;
+ super.setCancelled(value);
+ }
+
+ /**
+ * @return beginTaskCount
+ */
+ public int getBeginTaskCount() {
+ return this.beginTaskCount;
+ }
+
+ /**
+ * @return doneCount
+ */
+ public int getDoneCount() {
+ return this.doneCount;
+ }
+
+ /**
+ * @return createSubtaskCount
+ */
+ public int getCreateSubtaskCount() {
+ return this.createSubtaskCount;
+ }
+
+ /**
+ * @return setCancelledCount
+ */
+ public int getSetCancelledCount() {
+ return this.setCancelledCount;
+ }
+}
Property changes on: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingActivityMonitor.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Deleted: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,114 +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.monitor;
-
-import org.jboss.dna.common.i18n.I18n;
-
-/**
- * @author Randall Hauch
- */
-public class RecordingProgressMonitor extends ProgressMonitorWrapper {
-
- private int beginTaskCount;
- private int doneCount;
- private int createSubtaskCount;
- private int setCancelledCount;
-
- public RecordingProgressMonitor( ProgressMonitor delegate ) {
- super(delegate);
- }
-
- public RecordingProgressMonitor( String name ) {
- this(name, null);
- }
-
- public RecordingProgressMonitor( String name,
- ProgressMonitor parentProgressMonitor ) {
- this(new SimpleProgressMonitor(name, parentProgressMonitor));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void beginTask( double totalWork,
- I18n name,
- Object... params ) {
- ++beginTaskCount;
- super.beginTask(totalWork, name, params);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void done() {
- ++doneCount;
- super.done();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public ProgressMonitor createSubtask( double subtaskWork ) {
- ++createSubtaskCount;
- return super.createSubtask(subtaskWork);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setCancelled( boolean value ) {
- ++setCancelledCount;
- super.setCancelled(value);
- }
-
- /**
- * @return beginTaskCount
- */
- public int getBeginTaskCount() {
- return this.beginTaskCount;
- }
-
- /**
- * @return doneCount
- */
- public int getDoneCount() {
- return this.doneCount;
- }
-
- /**
- * @return createSubtaskCount
- */
- public int getCreateSubtaskCount() {
- return this.createSubtaskCount;
- }
-
- /**
- * @return setCancelledCount
- */
- public int getSetCancelledCount() {
- return this.setCancelledCount;
- }
-}
Copied: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleActivityMonitorTest.java (from rev 596, trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java)
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleActivityMonitorTest.java (rev 0)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleActivityMonitorTest.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -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.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.number.IsCloseTo.closeTo;
+import static org.junit.Assert.assertThat;
+import java.util.Locale;
+import java.util.Set;
+import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.i18n.MockI18n;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public class SimpleActivityMonitorTest {
+
+ private static final String VALID_TASK_NAME = "Checking for file";
+
+ private ActivityMonitor monitor;
+
+ @Before
+ public void beforeEach() {
+ this.monitor = new SimpleActivityMonitor(MockI18n.passthrough, "Reading from file X");
+ }
+
+ @Test
+ public void shouldNotBeCancelledUponCreation() {
+ assertThat(monitor.isCancelled(), is(false));
+ }
+
+ @Test
+ public void shouldReturnActivityStatusWithEmptyMessageBeforeTaskIsBegun() {
+ ActivityStatus status = monitor.getStatus(Locale.FRANCE);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is(""));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is(""));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+ }
+
+ @Test
+ public void shouldReturnActivityStatusWithCorrectMessageAfterTaskIsBegun() {
+ monitor.beginTask(100, I18nMessages.testTaskName);
+ monitor.worked(10.0d);
+ ActivityStatus status = monitor.getStatus(Locale.FRANCE);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is("examinez le message"));
+ assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
+
+ status = monitor.getStatus(Locale.ENGLISH);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is("test task"));
+ assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
+
+ status = monitor.getStatus(Locale.getDefault());
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is("test task"));
+ assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
+
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is("test task"));
+ assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
+ }
+
+ @Test
+ public void shouldReturnActivityStatusWithCorrectMessageAndSubstitutedParametersAfterTaskIsBegun() {
+ monitor.beginTask(100, I18nMessages.testTaskName2, 2);
+ monitor.worked(10.0d);
+ ActivityStatus status = monitor.getStatus(Locale.FRANCE);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is("examinez le message 2"));
+ assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
+
+ status = monitor.getStatus(Locale.ENGLISH);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is("second test task 2"));
+ assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
+
+ status = monitor.getStatus(Locale.getDefault());
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is("second test task 2"));
+ assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
+
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getMessage(), is("second test task 2"));
+ assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
+ }
+
+ @Test
+ public void shouldHaveProgressOfZeroPercentUponCreation() {
+ ActivityStatus status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(""));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+ }
+
+ @Test
+ public void shouldHaveProgressOfZeroPercentUponBeginningTask() {
+ this.monitor.beginTask(100, MockI18n.passthrough, VALID_TASK_NAME);
+ ActivityStatus status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+ }
+
+ @Test
+ public void shouldShowProperStatus() {
+ this.monitor.beginTask(1000, MockI18n.passthrough, VALID_TASK_NAME);
+ ActivityStatus status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+ for (int i = 1; i <= 9; ++i) {
+ this.monitor.worked(100);
+ // Check the monitor's status ...
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(10 * i, 0.001d)));
+ assertThat(status.isDone(), is(false));
+ }
+ monitor.done();
+ // Check the monitor's status shows 100%
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
+ assertThat(status.isDone(), is(true));
+ }
+
+ @Test
+ public void shouldShowProperStatusUsingSubtasks() {
+ monitor.beginTask(1000, MockI18n.passthrough, VALID_TASK_NAME);
+ ActivityStatus status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+
+ // Create subtasks ...
+ for (int i = 1; i <= 9; ++i) {
+ ActivityMonitor subtask = monitor.createSubtask(100);
+ assertThat(subtask, is(notNullValue()));
+ assertThat(subtask, is(instanceOf(SubActivityMonitor.class)));
+ assertThat(((SubActivityMonitor)subtask).getParent(), is(sameInstance(monitor)));
+
+ String subtaskName = "Subtask " + i;
+ 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);
+
+ // Check the submonitor's status
+ status = subtask.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(subtaskName));
+ assertThat(status.getPercentWorked(), is(closeTo(10 * j, 0.001d)));
+ assertThat(status.isDone(), is(j == 10));
+
+ // System.out.println(status);
+ }
+ subtask.done();
+
+ // Check the main monitor's status
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(10 * i, 0.001d)));
+ assertThat(status.isDone(), is(false));
+ }
+ monitor.done();
+
+ // Check the monitor's status shows 100%
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
+ assertThat(status.isDone(), is(true));
+ }
+
+ @Test
+ public void shouldAllowDoneToBeCalledEvenAfterFinished() {
+ monitor.beginTask(1000, MockI18n.passthrough, VALID_TASK_NAME);
+ ActivityStatus status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+ assertThat(status.isDone(), is(false));
+
+ for (int i = 0; i != 3; ++i) {
+ // Just mark it as done ...
+ monitor.done();
+
+ // Check the status ...
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
+ assertThat(status.isDone(), is(true));
+ }
+ }
+
+ @Test
+ public void shouldNotBeMarkedAsDoneAfterCancel() {
+ monitor.beginTask(100, MockI18n.passthrough, VALID_TASK_NAME);
+ monitor.setCancelled(true);
+ assertThat(monitor.isCancelled(), is(true));
+ assertThat(monitor.isDone(), is(false));
+ }
+
+ @Test
+ public void shouldAllowCancelToBeRejected() {
+ monitor.beginTask(1000, MockI18n.passthrough, VALID_TASK_NAME);
+ ActivityStatus status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+ for (int i = 1; i <= 9; ++i) {
+ monitor.worked(100);
+
+ // Check the monitor's status ...
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(10 * i, 0.001d)));
+ assertThat(status.isDone(), is(false));
+
+ // Cancel the activity ...
+ monitor.setCancelled(true);
+ assertThat(monitor.isCancelled(), is(true));
+ }
+ monitor.done();
+ // Check the monitor's status shows 100%
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
+ assertThat(status.isDone(), is(true));
+
+ }
+
+ @Test
+ public void shouldContinueToRecordWorkEvenWhenCancelled() {
+ monitor.beginTask(1000, MockI18n.passthrough, VALID_TASK_NAME);
+ ActivityStatus status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
+ for (int i = 1; i <= 9; ++i) {
+ monitor.worked(100);
+
+ // Check the monitor's status ...
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(10 * i, 0.001d)));
+ assertThat(status.isDone(), is(false));
+
+ // Cancel the activity ...
+ monitor.setCancelled(true);
+ assertThat(monitor.isCancelled(), is(monitor.isCancelled()));
+ }
+ monitor.done();
+ // Check the monitor's status shows 100%
+ status = monitor.getStatus(null);
+ assertThat(status, is(notNullValue()));
+ assertThat(status.getActivityName(), is(monitor.getActivityName()));
+ assertThat(status.getMessage(), is(VALID_TASK_NAME));
+ assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
+ assertThat(status.isDone(), is(true));
+ assertThat(monitor.isCancelled(), is(true));
+ }
+
+ @Test
+ public void shouldRecordProblems() {
+ monitor.beginTask(1000, MockI18n.passthrough, VALID_TASK_NAME);
+ monitor.getProblems().addWarning(MockI18n.passthrough);
+ monitor.done();
+ assertThat(monitor.getProblems().hasWarnings(), is(true));
+ }
+
+ public static class I18nMessages {
+
+ public static I18n testTaskName;
+ public static I18n testTaskName2;
+
+ static {
+ try {
+ I18n.initialize(SimpleActivityMonitorTest.I18nMessages.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(CommonI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(CommonI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(CommonI18n.class, locale);
+ }
+
+ }
+}
Deleted: 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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/SimpleProgressMonitorTest.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,358 +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.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.number.IsCloseTo.closeTo;
-import static org.junit.Assert.assertThat;
-import java.util.Locale;
-import java.util.Set;
-import org.jboss.dna.common.CommonI18n;
-import org.jboss.dna.common.i18n.I18n;
-import org.jboss.dna.common.i18n.MockI18n;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- * @author John Verhaeg
- */
-public class SimpleProgressMonitorTest {
-
- private ProgressMonitor monitor;
- private String validActivityName;
- private String validTaskName;
-
- @Before
- public void beforeEach() {
- this.validActivityName = "Reading from file X";
- this.validTaskName = "Checking for file";
- this.monitor = new SimpleProgressMonitor(this.validActivityName);
- }
-
- @Test
- public void shouldNotBeCancelledUponCreation() {
- assertThat(monitor.isCancelled(), is(false));
- }
-
- @Test
- public void shouldReturnProgressStatusWithEmptyMessageBeforeTaskIsBegun() {
- ProgressStatus status = monitor.getStatus(Locale.FRANCE);
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is(""));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
-
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is(""));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
- }
-
- @Test
- public void shouldReturnProgressStatusWithCorrectMessageAfterTaskIsBegun() {
- monitor.beginTask(100, I18nMessages.testTaskName);
- monitor.worked(10.0d);
- ProgressStatus status = monitor.getStatus(Locale.FRANCE);
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is("examinez le message"));
- assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
-
- status = monitor.getStatus(Locale.ENGLISH);
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is("test task"));
- assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
-
- status = monitor.getStatus(Locale.getDefault());
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is("test task"));
- assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
-
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is("test task"));
- assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
- }
-
- @Test
- public void shouldReturnProgressStatusWithCorrectMessageAndSubstitutedParametersAfterTaskIsBegun() {
- monitor.beginTask(100, I18nMessages.testTaskName2, 2);
- monitor.worked(10.0d);
- ProgressStatus status = monitor.getStatus(Locale.FRANCE);
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is("examinez le message 2"));
- assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
-
- status = monitor.getStatus(Locale.ENGLISH);
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is("second test task 2"));
- assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
-
- status = monitor.getStatus(Locale.getDefault());
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is("second test task 2"));
- assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
-
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getMessage(), is("second test task 2"));
- assertThat(status.getPercentWorked(), is(closeTo(10.0d, 0.001d)));
- }
-
- @Test
- public void shouldHaveProgressOfZeroPercentUponCreation() {
- ProgressStatus status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(""));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
- }
-
- @Test
- public void shouldHaveProgressOfZeroPercentUponBeginningTask() {
- this.monitor.beginTask(100, MockI18n.passthrough, validTaskName);
- ProgressStatus status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
- }
-
- @Test
- public void shouldShowProperProgress() {
- this.monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
- ProgressStatus status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
- for (int i = 1; i <= 9; ++i) {
- this.monitor.worked(100);
- // Check the monitor's status ...
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(10 * i, 0.001d)));
- assertThat(status.isDone(), is(false));
- }
- monitor.done();
- // Check the monitor's status shows 100%
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
- assertThat(status.isDone(), is(true));
- }
-
- @Test
- public void shouldShowProperProgressUsingSubtasks() {
- monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
- ProgressStatus status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
-
- // Create subtasks ...
- for (int i = 1; i <= 9; ++i) {
- ProgressMonitor subtask = monitor.createSubtask(100);
- assertThat(subtask, is(notNullValue()));
- assertThat(subtask, is(instanceOf(SubProgressMonitor.class)));
- assertThat(((SubProgressMonitor)subtask).getParent(), is(sameInstance(monitor)));
-
- String subtaskName = "Subtask " + i;
- 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);
-
- // Check the submonitor's status
- status = subtask.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(subtaskName));
- assertThat(status.getPercentWorked(), is(closeTo(10 * j, 0.001d)));
- assertThat(status.isDone(), is(j == 10));
-
- // System.out.println(status);
- }
- subtask.done();
-
- // Check the main monitor's status
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(10 * i, 0.001d)));
- assertThat(status.isDone(), is(false));
- }
- monitor.done();
-
- // Check the monitor's status shows 100%
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
- assertThat(status.isDone(), is(true));
- }
-
- @Test
- public void shouldAllowDoneToBeCalledEvenAfterFinished() {
- monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
- ProgressStatus status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
- assertThat(status.isDone(), is(false));
-
- for (int i = 0; i != 3; ++i) {
- // Just mark it as done ...
- monitor.done();
-
- // Check the status ...
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
- assertThat(status.isDone(), is(true));
- }
- }
-
- @Test
- public void shouldNotBeMarkedAsDoneAfterCancel() {
- monitor.beginTask(100, MockI18n.passthrough, validTaskName);
- monitor.setCancelled(true);
- assertThat(monitor.isCancelled(), is(true));
- assertThat(monitor.isDone(), is(false));
- }
-
- @Test
- public void shouldAllowCancelToBeRejected() {
- monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
- ProgressStatus status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
- for (int i = 1; i <= 9; ++i) {
- monitor.worked(100);
-
- // Check the monitor's status ...
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(10 * i, 0.001d)));
- assertThat(status.isDone(), is(false));
-
- // Cancel the activity ...
- monitor.setCancelled(true);
- assertThat(monitor.isCancelled(), is(true));
- }
- monitor.done();
- // Check the monitor's status shows 100%
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
- assertThat(status.isDone(), is(true));
-
- }
-
- @Test
- public void shouldContinueToRecordWorkEvenWhenCancelled() {
- monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
- ProgressStatus status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(0.0d, 0.001d)));
- for (int i = 1; i <= 9; ++i) {
- monitor.worked(100);
-
- // Check the monitor's status ...
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(10 * i, 0.001d)));
- assertThat(status.isDone(), is(false));
-
- // Cancel the activity ...
- monitor.setCancelled(true);
- assertThat(monitor.isCancelled(), is(monitor.isCancelled()));
- }
- monitor.done();
- // Check the monitor's status shows 100%
- status = monitor.getStatus(null);
- assertThat(status, is(notNullValue()));
- assertThat(status.getActivityName(), is(sameInstance(monitor.getActivityName())));
- assertThat(status.getMessage(), is(validTaskName));
- assertThat(status.getPercentWorked(), is(closeTo(100, 0.001d)));
- assertThat(status.isDone(), is(true));
- assertThat(monitor.isCancelled(), is(true));
- }
-
- @Test
- public void shouldRecordProblems() {
- monitor.beginTask(1000, MockI18n.passthrough, validTaskName);
- monitor.getProblems().addWarning(MockI18n.passthrough);
- monitor.done();
- assertThat(monitor.getProblems().hasWarnings(), is(true));
- }
-
- public static class I18nMessages {
-
- public static I18n testTaskName;
- public static I18n testTaskName2;
-
- static {
- try {
- I18n.initialize(SimpleProgressMonitorTest.I18nMessages.class);
- } catch (final Exception err) {
- System.err.println(err);
- }
- }
-
- public static Set<Locale> getLocalizationProblemLocales() {
- return I18n.getLocalizationProblemLocales(CommonI18n.class);
- }
-
- public static Set<String> getLocalizationProblems() {
- return I18n.getLocalizationProblems(CommonI18n.class);
- }
-
- public static Set<String> getLocalizationProblems( Locale locale ) {
- return I18n.getLocalizationProblems(CommonI18n.class, locale);
- }
-
- }
-}
Copied: trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_en.properties (from rev 598, trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_en.properties)
===================================================================
--- trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_en.properties (rev 0)
+++ trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_en.properties 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,2 @@
+testTaskName = test task
+testTaskName2 = second test task {0}
\ No newline at end of file
Property changes on: trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_en.properties
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ text/plain
Copied: trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_fr.properties (from rev 598, trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_fr.properties)
===================================================================
--- trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_fr.properties (rev 0)
+++ trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_fr.properties 2008-10-29 20:09:42 UTC (rev 599)
@@ -0,0 +1,2 @@
+testTaskName = examinez le message
+testTaskName2 = examinez le message {0}
\ No newline at end of file
Property changes on: trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleActivityMonitorTest$I18nMessages_fr.properties
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ text/plain
Deleted: trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_en.properties
===================================================================
--- trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_en.properties 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_en.properties 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,2 +0,0 @@
-testTaskName = test task
-testTaskName2 = second test task {0}
\ No newline at end of file
Deleted: trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_fr.properties
===================================================================
--- trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_fr.properties 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-common/src/test/resources/org/jboss/dna/common/monitor/SimpleProgressMonitorTest$I18nMessages_fr.properties 2008-10-29 20:09:42 UTC (rev 599)
@@ -1,2 +0,0 @@
-testTaskName = examinez le message
-testTaskName2 = examinez le message {0}
\ No newline at end of file
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -25,7 +25,7 @@
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import org.jboss.dna.common.component.ClassLoaderFactory;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.properties.NamespaceRegistry;
import org.jboss.dna.graph.properties.Property;
@@ -50,6 +50,13 @@
AccessControlContext getAccessControlContext();
/**
+ * Returns the thread-safe activity monitor associated with this execution context.
+ *
+ * @return the activity monitor; never <code>null</code>;
+ */
+ ActivityMonitor getActivityMonitor();
+
+ /**
* Return a logger associated with this context. This logger records only those activities within the context and provide a
* way to capture the context-specific activities. All log messages are also sent to the system logger, so classes that log
* via this mechanism should <i>not</i> also {@link Logger#getLogger(Class) obtain a system logger}.
@@ -84,13 +91,6 @@
NamespaceRegistry getNamespaceRegistry();
/**
- * Returns the thread-safe progress monitor associated with this execution context.
- *
- * @return the progress monitor; never <code>null</code>;
- */
- ProgressMonitor getProgressMonitor();
-
- /**
* Get the factory for creating {@link Property} objects.
*
* @return the property factory; never <code>null</code>
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContexts.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContexts.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContexts.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -24,7 +24,7 @@
import java.security.AccessControlContext;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.properties.NameFactory;
@@ -188,10 +188,10 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.ExecutionContext#getProgressMonitor()
+ * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
*/
- public ProgressMonitor getProgressMonitor() {
- return delegate.getProgressMonitor();
+ public ActivityMonitor getActivityMonitor() {
+ return delegate.getActivityMonitor();
}
/**
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/BasicExecutionContext.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/BasicExecutionContext.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/BasicExecutionContext.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -25,10 +25,11 @@
import java.security.AccessController;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.component.ClassLoaderFactory;
import org.jboss.dna.common.component.StandardClassLoaderFactory;
-import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.common.monitor.SimpleProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
+import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.properties.NamespaceRegistry;
@@ -51,7 +52,7 @@
private final PropertyFactory propertyFactory;
private final ValueFactories valueFactories;
private final NamespaceRegistry namespaceRegistry;
- private final ProgressMonitor progressMonitor;
+ private final ActivityMonitor activityMonitor;
public BasicExecutionContext() {
this(null, null, null, null, null, null);
@@ -68,24 +69,24 @@
public BasicExecutionContext( NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
PropertyFactory propertyFactory,
- ProgressMonitor progressMonitor ) {
- this(null, null, namespaceRegistry, valueFactories, propertyFactory, progressMonitor);
+ ActivityMonitor activityMonitor ) {
+ this(null, null, namespaceRegistry, valueFactories, propertyFactory, activityMonitor);
}
public BasicExecutionContext( LoginContext loginContext,
NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
PropertyFactory propertyFactory,
- ProgressMonitor progressMonitor ) {
- this(loginContext, null, namespaceRegistry, valueFactories, propertyFactory, progressMonitor);
+ ActivityMonitor activityMonitor ) {
+ this(loginContext, null, namespaceRegistry, valueFactories, propertyFactory, activityMonitor);
}
public BasicExecutionContext( AccessControlContext accessControlContext,
NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
PropertyFactory propertyFactory,
- ProgressMonitor progressMonitor ) {
- this(null, accessControlContext, namespaceRegistry, valueFactories, propertyFactory, progressMonitor);
+ ActivityMonitor activityMonitor ) {
+ this(null, accessControlContext, namespaceRegistry, valueFactories, propertyFactory, activityMonitor);
}
/*
@@ -96,7 +97,7 @@
NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
PropertyFactory propertyFactory,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
this.loginContext = loginContext;
this.accessControlContext = accessControlContext;
if (loginContext == null) {
@@ -107,7 +108,7 @@
this.namespaceRegistry = namespaceRegistry == null ? new BasicNamespaceRegistry() : namespaceRegistry;
this.valueFactories = valueFactories == null ? new StandardValueFactories(this.namespaceRegistry) : valueFactories;
this.propertyFactory = propertyFactory == null ? new BasicPropertyFactory(this.valueFactories) : propertyFactory;
- this.progressMonitor = progressMonitor == null ? new SimpleProgressMonitor(null) : progressMonitor;
+ this.activityMonitor = activityMonitor == null ? new SimpleActivityMonitor(CommonI18n.nullActivityMonitorTaskName) : activityMonitor;
this.classLoaderFactory = new StandardClassLoaderFactory();
}
@@ -148,10 +149,10 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.ExecutionContext#getProgressMonitor()
+ * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
*/
- public ProgressMonitor getProgressMonitor() {
- return progressMonitor;
+ public ActivityMonitor getActivityMonitor() {
+ return activityMonitor;
}
/**
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/sequencers/StreamSequencer.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/sequencers/StreamSequencer.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/sequencers/StreamSequencer.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -22,7 +22,7 @@
package org.jboss.dna.graph.sequencers;
import java.io.InputStream;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
/**
* The interface for a DNA sequencer that processes a property as a stream to extract information from the content and store in
@@ -32,6 +32,7 @@
* </p>
*
* @author Randall Hauch
+ * @author John Verhaeg
*/
public interface StreamSequencer {
@@ -44,30 +45,30 @@
* 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
+ * This operation should report progress to the supplied {@link ActivityMonitor}. At the beginning of the operation, call
+ * {@link ActivityMonitor#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
+ * periodically reporting work by specifying the {@link ActivityMonitor#worked(double) amount of work} that has was just
+ * completed or by {@link ActivityMonitor#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.
+ * The implementation should also periodically check whether the operation has been {@link ActivityMonitor#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.
+ * Finally, the implementation should call {@link ActivityMonitor#done()} when the operation has finished.
* </p>
*
* @param stream the stream with the data to be sequenced; never <code>null</code>
* @param output the output from the sequencing operation; never <code>null</code>
* @param context the context for the sequencing operation; never <code>null</code>
- * @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}.
+ * @param activityMonitor the activity 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 ActivityMonitor#isCancelled() cancelled}.
*/
void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor );
+ ActivityMonitor activityMonitor );
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencers/MockSequencerContext.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencers/MockSequencerContext.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencers/MockSequencerContext.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -26,7 +26,7 @@
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.properties.Name;
@@ -39,7 +39,7 @@
import org.jboss.dna.graph.properties.basic.StandardValueFactories;
/**
- * @author jverhaeg
+ * @author John Verhaeg
*/
@Immutable
public class MockSequencerContext implements SequencerContext {
@@ -150,9 +150,9 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.ExecutionContext#getProgressMonitor()
+ * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
*/
- public ProgressMonitor getProgressMonitor() {
+ public ActivityMonitor getActivityMonitor() {
return null;
}
Modified: 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 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/Sequencer.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -27,7 +27,7 @@
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.common.monitor.ActivityMonitor;
import org.jboss.dna.repository.observation.NodeChange;
import org.jboss.dna.repository.observation.NodeChangeListener;
import org.jboss.dna.repository.observation.NodeChanges;
@@ -41,7 +41,9 @@
* <p>
* Implementations must provide a no-argument constructor.
* </p>
+ *
* @author Randall Hauch
+ * @author John Verhaeg
*/
@ThreadSafe
public interface Sequencer extends Component<SequencerConfig> {
@@ -50,13 +52,13 @@
* Execute the sequencing operation on the supplied node, which has recently been created or changed. The implementation of
* this method is responsible for {@link JcrExecutionContext#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.
+ * (and any other acquired resources), even in the case of {@link ActivityMonitor#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
+ * 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.
@@ -67,34 +69,39 @@
* 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
+ * This operation should report progress to the supplied {@link ActivityMonitor}. At the beginning of the operation, call
+ * {@link ActivityMonitor#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
+ * periodically reporting work by specifying the {@link ActivityMonitor#worked(double) amount of work} that has was just
+ * completed or by {@link ActivityMonitor#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.
+ * The implementation should also periodically check whether the operation has been {@link ActivityMonitor#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.
+ * Finally, the implementation should call {@link ActivityMonitor#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 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
+ * 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}.
+ * @param activityMonitor the activity 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 ActivityMonitor#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, JcrExecutionContext context, ProgressMonitor progress )
- throws RepositoryException, SequencerException;
+ void execute( Node input,
+ String sequencedPropertyName,
+ NodeChange changes,
+ Set<RepositoryNodePath> outputPaths,
+ JcrExecutionContext context,
+ ActivityMonitor activityMonitor ) throws RepositoryException, SequencerException;
}
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerNodeContext.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerNodeContext.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerNodeContext.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -35,7 +35,7 @@
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.properties.Name;
@@ -264,10 +264,10 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.ExecutionContext#getProgressMonitor()
+ * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
*/
- public ProgressMonitor getProgressMonitor() {
- return context.getProgressMonitor();
+ public ActivityMonitor getActivityMonitor() {
+ return context.getActivityMonitor();
}
/**
Modified: 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 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -46,9 +46,9 @@
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.monitor.ActivityMonitor;
+import org.jboss.dna.common.monitor.LoggingActivityMonitor;
+import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.common.util.Logger;
@@ -514,12 +514,12 @@
}
} else {
// Run each of those sequencers ...
- ProgressMonitor progressMonitor = new SimpleProgressMonitor(RepositoryI18n.sequencerTask.text(changedNode));
+ ActivityMonitor activityMonitor = new SimpleActivityMonitor(RepositoryI18n.sequencerTask, changedNode);
if (logger.isTraceEnabled()) {
- progressMonitor = new LoggingProgressMonitor(progressMonitor, logger, Logger.Level.TRACE);
+ activityMonitor = new LoggingActivityMonitor(activityMonitor, logger, Logger.Level.TRACE);
}
try {
- progressMonitor.beginTask(sequencerCalls.size(), RepositoryI18n.sequencerTask, changedNode);
+ activityMonitor.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();
@@ -532,7 +532,7 @@
// Create a new execution context for each sequencer
final Context executionContext = new Context(context);
- final ProgressMonitor sequenceMonitor = progressMonitor.createSubtask(1);
+ final ActivityMonitor sequenceMonitor = activityMonitor.createSubtask(1);
try {
sequenceMonitor.beginTask(100, RepositoryI18n.sequencerSubtask, sequencerName);
sequencer.execute(node,
@@ -563,7 +563,7 @@
}
this.statistics.recordNodeSequenced();
} finally {
- progressMonitor.done();
+ activityMonitor.done();
}
}
} finally {
@@ -642,10 +642,10 @@
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.graph.ExecutionContext#getProgressMonitor()
+ * @see org.jboss.dna.graph.ExecutionContext#getActivityMonitor()
*/
- public ProgressMonitor getProgressMonitor() {
- return delegate.getProgressMonitor();
+ public ActivityMonitor getActivityMonitor() {
+ return delegate.getActivityMonitor();
}
/**
Modified: 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 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapter.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -31,7 +31,7 @@
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.properties.Binary;
import org.jboss.dna.graph.properties.DateTime;
@@ -49,6 +49,7 @@
* An adapter class that wraps a {@link StreamSequencer} instance to be a {@link Sequencer}.
*
* @author Randall Hauch
+ * @author John Verhaeg
*/
public class StreamSequencerAdapter implements Sequencer {
@@ -81,14 +82,14 @@
NodeChange changes,
Set<RepositoryNodePath> outputPaths,
JcrExecutionContext execContext,
- ProgressMonitor progressMonitor ) throws RepositoryException, SequencerException {
+ ActivityMonitor activityMonitor ) throws RepositoryException, SequencerException {
// 'sequencedPropertyName' contains the name of the modified property on 'input' that resulted in 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());
+ activityMonitor.beginTask(100, RepositoryI18n.sequencingPropertyOnNode, sequencedPropertyName, input.getPath());
// Get the property that contains the data, given by 'propertyName' ...
Property sequencedProperty = null;
@@ -98,13 +99,13 @@
String msg = RepositoryI18n.unableToFindPropertyForSequencing.text(sequencedPropertyName, input.getPath());
throw new SequencerException(msg, e);
}
- progressMonitor.worked(10);
+ activityMonitor.worked(10);
// Get the binary property with the image content, and build the image metadata from the image ...
SequencerOutputMap output = new SequencerOutputMap(execContext.getValueFactories());
InputStream stream = null;
Throwable firstError = null;
- ProgressMonitor sequencingMonitor = progressMonitor.createSubtask(50);
+ ActivityMonitor sequencingMonitor = activityMonitor.createSubtask(50);
try {
stream = sequencedProperty.getStream();
SequencerNodeContext sequencerContext = new SequencerNodeContext(input, sequencedProperty, execContext);
@@ -131,8 +132,8 @@
}
// Find each output node and save the image metadata there ...
- ProgressMonitor writingProgress = progressMonitor.createSubtask(40);
- writingProgress.beginTask(outputPaths.size(),
+ ActivityMonitor writingActivity = activityMonitor.createSubtask(40);
+ writingActivity.beginTask(outputPaths.size(),
RepositoryI18n.writingOutputSequencedFromPropertyOnNodes,
sequencedPropertyName,
input.getPath(),
@@ -155,14 +156,14 @@
session.save();
}
} finally {
- writingProgress.worked(1);
+ writingActivity.worked(1);
// Always close the session ...
if (session != null) session.logout();
}
}
- writingProgress.done();
+ writingActivity.done();
} finally {
- progressMonitor.done();
+ activityMonitor.done();
}
}
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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerA.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -29,14 +29,16 @@
import javax.jcr.Node;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.i18n.MockI18n;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.repository.observation.NodeChange;
import org.jboss.dna.repository.util.JcrExecutionContext;
import org.jboss.dna.repository.util.RepositoryNodePath;
/**
* A sequencer that can be used for basic unit testing.
+ *
* @author Randall Hauch
+ * @author John Verhaeg
*/
@ThreadSafe
public class MockSequencerA implements Sequencer {
@@ -49,7 +51,8 @@
this.latch = new CountDownLatch(numExpected);
}
- public boolean awaitExecution( long timeout, TimeUnit unit ) throws InterruptedException {
+ public boolean awaitExecution( long timeout,
+ TimeUnit unit ) throws InterruptedException {
return this.latch.await(timeout, unit);
}
@@ -63,15 +66,20 @@
/**
* {@inheritDoc}
*/
- public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, JcrExecutionContext context, ProgressMonitor progress ) {
+ public void execute( Node input,
+ String sequencedPropertyName,
+ NodeChange changes,
+ Set<RepositoryNodePath> outputPaths,
+ JcrExecutionContext context,
+ ActivityMonitor activityMonitor ) {
try {
- progress.beginTask(1, MockI18n.passthrough, "Incrementing counter");
+ activityMonitor.beginTask(1, MockI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
this.latch.countDown();
- progress.worked(1);
+ activityMonitor.worked(1);
} finally {
- progress.done();
+ activityMonitor.done();
}
}
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-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/MockSequencerB.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -29,14 +29,16 @@
import javax.jcr.Node;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.i18n.MockI18n;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.repository.observation.NodeChange;
import org.jboss.dna.repository.util.JcrExecutionContext;
import org.jboss.dna.repository.util.RepositoryNodePath;
/**
* A sequencer that can be used for basic unit testing.
+ *
* @author Randall Hauch
+ * @author John Verhaeg
*/
@ThreadSafe
public class MockSequencerB implements Sequencer {
@@ -49,7 +51,8 @@
this.latch = new CountDownLatch(numExpected);
}
- public boolean awaitExecution( long timeout, TimeUnit unit ) throws InterruptedException {
+ public boolean awaitExecution( long timeout,
+ TimeUnit unit ) throws InterruptedException {
return this.latch.await(timeout, unit);
}
@@ -63,15 +66,20 @@
/**
* {@inheritDoc}
*/
- public void execute( Node input, String sequencedPropertyName, NodeChange changes, Set<RepositoryNodePath> outputPaths, JcrExecutionContext context, ProgressMonitor progress ) {
+ public void execute( Node input,
+ String sequencedPropertyName,
+ NodeChange changes,
+ Set<RepositoryNodePath> outputPaths,
+ JcrExecutionContext context,
+ ActivityMonitor activityMonitor ) {
try {
- progress.beginTask(1, MockI18n.passthrough, "Incrementing counter");
+ activityMonitor.beginTask(1, MockI18n.passthrough, "Incrementing counter");
// increment the counter and record the progress ...
this.counter.incrementAndGet();
this.latch.countDown();
- progress.worked(1);
+ activityMonitor.worked(1);
} finally {
- progress.done();
+ activityMonitor.done();
}
}
Modified: 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 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/StreamSequencerAdapterTest.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -37,8 +37,8 @@
import javax.jcr.observation.Event;
import org.jboss.dna.common.collection.Problem;
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.common.monitor.ActivityMonitor;
+import org.jboss.dna.common.monitor.RecordingActivityMonitor;
import org.jboss.dna.graph.properties.NamespaceRegistry;
import org.jboss.dna.graph.properties.Path;
import org.jboss.dna.graph.sequencers.SequencerContext;
@@ -70,7 +70,7 @@
private SequencerOutputMap sequencerOutput;
private String sampleData = "The little brown fox didn't something bad.";
private JcrExecutionContext context;
- private RecordingProgressMonitor progressMonitor;
+ private RecordingActivityMonitor activityMonitor;
private String repositoryWorkspaceName = "something";
@Before
@@ -86,7 +86,7 @@
NamespaceRegistry registry = new JcrNamespaceRegistry(sessionFactory, "doesn't matter");
this.context = new BasicJcrExecutionContext(sessionFactory, registry, null, null);
this.sequencerOutput = new SequencerOutputMap(this.context.getValueFactories());
- this.progressMonitor = new RecordingProgressMonitor(StreamSequencerAdapterTest.class.getName());
+ this.activityMonitor = new RecordingActivityMonitor(StreamSequencerAdapterTest.class.getName());
final SequencerOutputMap finalOutput = sequencerOutput;
this.streamSequencer = new StreamSequencer() {
@@ -97,7 +97,7 @@
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
for (SequencerOutputMap.Entry entry : finalOutput) {
Path nodePath = entry.getPath();
for (SequencerOutputMap.PropertyValue property : entry.getPropertyValues()) {
@@ -135,11 +135,11 @@
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
try {
- sequencer.sequence(stream, output, context, progressMonitor);
+ sequencer.sequence(stream, output, context, activityMonitor);
} catch (AssertionError err) {
- progressMonitor.getProblems().addError(err, null);
+ activityMonitor.getProblems().addError(err, null);
}
}
};
@@ -154,8 +154,8 @@
Set<RepositoryNodePath> outputPaths = new HashSet<RepositoryNodePath>();
outputPaths.add(new RepositoryNodePath(repositoryWorkspaceName, outputNode.getPath()));
sequencerOutput.setProperty("alpha/beta", "isSomething", true);
- adapter.execute(inputNode, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
- for (Problem problem : progressMonitor.getProblems()) {
+ adapter.execute(inputNode, "sequencedProperty", nodeChange, outputPaths, context, activityMonitor);
+ for (Problem problem : activityMonitor.getProblems()) {
throw (AssertionError)problem.getThrowable();
}
}
@@ -219,7 +219,7 @@
sequencerOutput.setProperty("alpha/beta", "isSomething", true);
// Call the sequencer ...
- sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, activityMonitor);
}
@Test( expected = SequencerException.class )
@@ -252,7 +252,7 @@
sequencerOutput.setProperty("alpha/beta", "isSomething", true);
// Call the sequencer, which should cause the exception ...
- sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, activityMonitor);
}
@Test
@@ -285,7 +285,7 @@
sequencerOutput.setProperty("alpha/beta", "isSomething", true);
// Call the sequencer ...
- sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, activityMonitor);
// Check to see that the output nodes have been created ...
assertThat(session.getRootNode().hasNode("d/e"), is(true));
@@ -317,7 +317,7 @@
sequencerOutput.setProperty("alpha/beta", "isSomething", true);
// Call the sequencer ...
- sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, activityMonitor);
// Check to see that the "/d/e" node has been created ...
assertThat(session.getRootNode().hasNode("d/e"), is(true));
@@ -351,7 +351,7 @@
sequencerOutput.setProperty("alpha/beta", "isSomething", true);
// Call the sequencer ...
- sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, progressMonitor);
+ sequencer.execute(nodeC, "sequencedProperty", nodeChange, outputPaths, context, activityMonitor);
// Check to see that the output nodes have been created ...
assertThat(session.getRootNode().hasNode("d/e"), is(true));
@@ -381,7 +381,7 @@
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
assertThat(stream, notNullValue());
}
});
@@ -394,7 +394,7 @@
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
assertThat(output, notNullValue());
}
});
@@ -407,21 +407,21 @@
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
assertThat(context, notNullValue());
}
});
}
@Test
- public void shouldPassNonNullProgressMonitorToSequencer() throws Exception {
+ public void shouldPassNonNullActivityMonitorToSequencer() throws Exception {
testSequencer(new StreamSequencer() {
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
- assertThat(progressMonitor, notNullValue());
+ ActivityMonitor activityMonitor ) {
+ assertThat(activityMonitor, notNullValue());
}
});
}
Modified: trunk/extensions/dna-sequencer-images/src/main/java/org/jboss/dna/sequencer/images/ImageMetadataSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-images/src/main/java/org/jboss/dna/sequencer/images/ImageMetadataSequencer.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/extensions/dna-sequencer-images/src/main/java/org/jboss/dna/sequencer/images/ImageMetadataSequencer.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -22,7 +22,7 @@
package org.jboss.dna.sequencer.images;
import java.io.InputStream;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.graph.properties.NameFactory;
import org.jboss.dna.graph.properties.Path;
import org.jboss.dna.graph.properties.PathFactory;
@@ -87,13 +87,13 @@
/**
* {@inheritDoc}
*
- * @see StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext, ProgressMonitor)
+ * @see StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext, ActivityMonitor)
*/
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
- progressMonitor.beginTask(10, ImageSequencerI18n.sequencerTaskName);
+ ActivityMonitor activityMonitor ) {
+ activityMonitor.beginTask(10, ImageSequencerI18n.sequencerTaskName);
ImageMetadata metadata = new ImageMetadata();
metadata.setInput(stream);
@@ -104,8 +104,8 @@
if (!metadata.check()) {
metadata = null;
}
- progressMonitor.worked(5);
- if (progressMonitor.isCancelled()) return;
+ activityMonitor.worked(5);
+ if (activityMonitor.isCancelled()) return;
// Generate the output graph if we found useful metadata ...
if (metadata != null) {
@@ -130,6 +130,6 @@
output.setProperty(metadataNode, nameFactory.create(IMAGE_PHYSICAL_HEIGHT_INCHES), metadata.getPhysicalHeightInch());
}
- progressMonitor.done();
+ activityMonitor.done();
}
}
Modified: trunk/extensions/dna-sequencer-images/src/test/java/org/jboss/dna/sequencer/images/ImageMetadataSequencerTest.java
===================================================================
--- trunk/extensions/dna-sequencer-images/src/test/java/org/jboss/dna/sequencer/images/ImageMetadataSequencerTest.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/extensions/dna-sequencer-images/src/test/java/org/jboss/dna/sequencer/images/ImageMetadataSequencerTest.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -28,8 +28,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
-import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.common.monitor.SimpleProgressMonitor;
+import org.jboss.dna.common.i18n.MockI18n;
+import org.jboss.dna.common.monitor.ActivityMonitor;
+import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.graph.sequencers.MockSequencerContext;
import org.jboss.dna.graph.sequencers.MockSequencerOutput;
import org.jboss.dna.graph.sequencers.SequencerContext;
@@ -46,7 +47,7 @@
private ImageMetadataSequencer sequencer;
private InputStream content;
private MockSequencerOutput output;
- private ProgressMonitor progress;
+ private ActivityMonitor activityMonitor;
private URL cautionGif;
private URL cautionJpg;
private URL cautionPict;
@@ -59,7 +60,7 @@
context = new MockSequencerContext();
context.getNamespaceRegistry().register("image", "http://jboss.org/dna/images/1.0");
output = new MockSequencerOutput(context);
- progress = new SimpleProgressMonitor("Test activity");
+ activityMonitor = new SimpleActivityMonitor(MockI18n.passthrough, "Test Activity");
cautionGif = this.getClass().getClassLoader().getResource("caution.gif");
cautionJpg = this.getClass().getClassLoader().getResource("caution.jpg");
cautionPict = this.getClass().getClassLoader().getResource("caution.pict");
@@ -83,7 +84,7 @@
assertThat(url, is(notNullValue()));
content = url.openStream();
assertThat(content, is(notNullValue()));
- sequencer.sequence(content, output, context, progress);
+ sequencer.sequence(content, output, context, activityMonitor);
assertThat(output.getPropertyValues("image:metadata", "jcr:primaryType"), is(new Object[] {"image:metadata"}));
assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"), is(new Object[] {"image/jpeg"}));
assertThat(output.getPropertyValues("image:metadata", "image:formatName"), is(new Object[] {"JPEG"}));
@@ -106,7 +107,7 @@
assertThat(url, is(notNullValue()));
content = url.openStream();
assertThat(content, is(notNullValue()));
- sequencer.sequence(content, output, context, progress);
+ sequencer.sequence(content, output, context, activityMonitor);
assertThat(output.getPropertyValues("image:metadata", "jcr:primaryType"), is(new Object[] {"image:metadata"}));
assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"), is(new Object[] {"image/png"}));
assertThat(output.getPropertyValues("image:metadata", "image:formatName"), is(new Object[] {"PNG"}));
@@ -127,7 +128,7 @@
assertThat(url, is(notNullValue()));
content = url.openStream();
assertThat(content, is(notNullValue()));
- sequencer.sequence(content, output, context, progress);
+ sequencer.sequence(content, output, context, activityMonitor);
assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"), is(new Object[] {"image/gif"}));
assertThat(output.getPropertyValues("image:metadata", "image:formatName"), is(new Object[] {"GIF"}));
assertThat(output.getPropertyValues("image:metadata", "image:width"), is(new Object[] {48}));
@@ -147,7 +148,7 @@
assertThat(url, is(notNullValue()));
content = url.openStream();
assertThat(content, is(notNullValue()));
- sequencer.sequence(content, output, context, progress);
+ sequencer.sequence(content, output, context, activityMonitor);
assertThat(output.hasProperties(), is(false));
}
Modified: trunk/extensions/dna-sequencer-java/src/main/java/org/jboss/dna/sequencer/java/JavaMetadataSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-java/src/main/java/org/jboss/dna/sequencer/java/JavaMetadataSequencer.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/extensions/dna-sequencer-java/src/main/java/org/jboss/dna/sequencer/java/JavaMetadataSequencer.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -25,7 +25,7 @@
import java.io.InputStream;
import java.util.List;
import org.apache.commons.lang.StringUtils;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.graph.properties.NameFactory;
import org.jboss.dna.graph.properties.Path;
import org.jboss.dna.graph.properties.PathFactory;
@@ -176,21 +176,21 @@
*
* @see org.jboss.dna.graph.sequencers.StreamSequencer#sequence(java.io.InputStream,
* org.jboss.dna.graph.sequencers.SequencerOutput, org.jboss.dna.graph.sequencers.SequencerContext,
- * org.jboss.dna.common.monitor.ProgressMonitor)
+ * org.jboss.dna.common.monitor.ActivityMonitor)
*/
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
- progressMonitor.beginTask(10, JavaMetadataI18n.sequencerTaskName);
+ ActivityMonitor activityMonitor ) {
+ activityMonitor.beginTask(10, JavaMetadataI18n.sequencerTaskName);
JavaMetadata javaMetadata = null;
NameFactory nameFactory = context.getValueFactories().getNameFactory();
PathFactory pathFactory = context.getValueFactories().getPathFactory();
try {
- javaMetadata = JavaMetadata.instance(stream, JavaMetadataUtil.length(stream), null, progressMonitor.createSubtask(10));
- if (progressMonitor.isCancelled()) return;
+ javaMetadata = JavaMetadata.instance(stream, JavaMetadataUtil.length(stream), null, activityMonitor.createSubtask(10));
+ if (activityMonitor.isCancelled()) return;
} catch (IOException e) {
e.printStackTrace();
return;
@@ -721,6 +721,6 @@
}
}
- progressMonitor.done();
+ activityMonitor.done();
}
}
Modified: trunk/extensions/dna-sequencer-java/src/main/java/org/jboss/dna/sequencer/java/metadata/JavaMetadata.java
===================================================================
--- trunk/extensions/dna-sequencer-java/src/main/java/org/jboss/dna/sequencer/java/metadata/JavaMetadata.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/extensions/dna-sequencer-java/src/main/java/org/jboss/dna/sequencer/java/metadata/JavaMetadata.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -24,13 +24,14 @@
import java.io.InputStream;
import java.util.List;
import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.sequencer.java.AbstractJavaMetadata;
import org.jboss.dna.sequencer.java.CompilationUnitParser;
import org.jboss.dna.sequencer.java.JavaMetadataUtil;
/**
* @author Serge Pagop
+ * @author John Verhaeg
*/
public class JavaMetadata extends AbstractJavaMetadata {
@@ -52,7 +53,7 @@
* @param inputStream - the <code>InputStream</code> in our case a <code>FileInputStream</code> of the java file.
* @param length - the length of the java file.
* @param encoding - the encoding that can be used.
- * @param progressMonitor - The basic <code>ProgressMonitor</code> that facilitates the updating and monitoring of progress
+ * @param activityMonitor - The basic <code>ActivityMonitor</code> that facilitates the updating and monitoring of progress
* towards the completion of an activity.
* @return the new instace of <code>JavaMetadata</code>
* @see java.io.File#length()
@@ -60,7 +61,7 @@
public static JavaMetadata instance( InputStream inputStream,
long length,
String encoding,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
JavaMetadata javaMetadata = new JavaMetadata();
char[] source = null;
Modified: trunk/extensions/dna-sequencer-java/src/test/java/org/jboss/dna/sequencer/java/JavaMetadataSequencerTest.java
===================================================================
--- trunk/extensions/dna-sequencer-java/src/test/java/org/jboss/dna/sequencer/java/JavaMetadataSequencerTest.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/extensions/dna-sequencer-java/src/test/java/org/jboss/dna/sequencer/java/JavaMetadataSequencerTest.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -29,8 +29,9 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.common.monitor.SimpleProgressMonitor;
+import org.jboss.dna.common.i18n.MockI18n;
+import org.jboss.dna.common.monitor.ActivityMonitor;
+import org.jboss.dna.common.monitor.SimpleActivityMonitor;
import org.jboss.dna.graph.sequencers.MockSequencerContext;
import org.jboss.dna.graph.sequencers.MockSequencerOutput;
import org.jboss.dna.graph.sequencers.SequencerContext;
@@ -46,7 +47,7 @@
private JavaMetadataSequencer sequencer;
private InputStream content;
private MockSequencerOutput output;
- private ProgressMonitor progress;
+ private ActivityMonitor activityMonitor;
private File source;
private SequencerContext context;
@@ -56,7 +57,7 @@
context.getNamespaceRegistry().register("java", "http://jboss.org/dna/java/1.0");
sequencer = new JavaMetadataSequencer();
output = new MockSequencerOutput(context);
- this.progress = new SimpleProgressMonitor("Test java monitor activity");
+ this.activityMonitor = new SimpleActivityMonitor(MockI18n.passthrough, "Test java monitor activity");
source = new File("src/test/workspace/projectX/src/org/acme/MySource.java");
}
@@ -79,7 +80,7 @@
public void shouldGenerateMetadataForJavaSourceFile() throws IOException {
content = getJavaSrc(source);
assertThat(content, is(notNullValue()));
- sequencer.sequence(content, output, context, progress);
+ sequencer.sequence(content, output, context, activityMonitor);
assertThat(output.getPropertyValues("java:compilationUnit", "jcr:primaryType"), is(new Object[] {"java:compilationUnit"}));
// support sequencing package declaration( FQL name of the package). Not supported is to get information for package
Modified: trunk/extensions/dna-sequencer-mp3/src/main/java/org/jboss/dna/sequencer/mp3/Mp3MetadataSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-mp3/src/main/java/org/jboss/dna/sequencer/mp3/Mp3MetadataSequencer.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/extensions/dna-sequencer-mp3/src/main/java/org/jboss/dna/sequencer/mp3/Mp3MetadataSequencer.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -22,7 +22,7 @@
package org.jboss.dna.sequencer.mp3;
import java.io.InputStream;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.graph.sequencers.SequencerContext;
import org.jboss.dna.graph.sequencers.SequencerOutput;
import org.jboss.dna.graph.sequencers.StreamSequencer;
@@ -47,6 +47,7 @@
*
* @author Stefano Maestri
* @author Randall Hauch
+ * @author John Verhaeg
*/
public class Mp3MetadataSequencer implements StreamSequencer {
@@ -61,12 +62,12 @@
/**
* {@inheritDoc}
*
- * @see StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext, ProgressMonitor)
+ * @see StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext, ActivityMonitor)
*/
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
Mp3Metadata metadata = Mp3Metadata.instance(stream);
if (metadata != null) {
Modified: trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/MSOfficeMetadataSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/MSOfficeMetadataSequencer.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/extensions/dna-sequencer-msoffice/src/main/java/org/jboss/dna/sequencer/msoffice/MSOfficeMetadataSequencer.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -24,7 +24,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.graph.sequencers.SequencerContext;
import org.jboss.dna.graph.sequencers.SequencerOutput;
import org.jboss.dna.graph.sequencers.StreamSequencer;
@@ -75,6 +75,7 @@
* </p>
*
* @author Michael Trezzi
+ * @author John Verhaeg
*/
public class MSOfficeMetadataSequencer implements StreamSequencer {
@@ -115,11 +116,11 @@
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
- progressMonitor.beginTask(10, MSOfficeMetadataI18n.sequencerTaskName);
+ ActivityMonitor activityMonitor ) {
+ activityMonitor.beginTask(10, MSOfficeMetadataI18n.sequencerTaskName);
MSOfficeMetadata metadata = MSOfficeMetadataReader.instance(stream);
- progressMonitor.worked(3);
+ activityMonitor.worked(3);
String mimeType = context.getMimeType();
@@ -146,7 +147,7 @@
} else {
return;
}
- progressMonitor.worked(1);
+ activityMonitor.worked(1);
// process PowerPoint specific metadata
if (mimeType.equals("application/vnd.ms-powerpoint")) { // replace true with check if it's ppt file being sequenced
try {
@@ -164,7 +165,7 @@
context.getLogger(this.getClass()).debug(e, "Error while extracting the PowerPoint metadata");
}
}
- progressMonitor.worked(2);
+ activityMonitor.worked(2);
if (mimeType.equals("application/vnd.ms-word")) {
// Sometime in the future this will sequence WORD Table of contents.
@@ -176,7 +177,7 @@
}
}
- progressMonitor.worked(2);
+ activityMonitor.worked(2);
if (mimeType.equals("application/vnd.ms-excel")) {
try {
@@ -192,7 +193,7 @@
context.getLogger(this.getClass()).debug(e, "Error while extracting the Excel metadata");
}
}
- progressMonitor.worked(2);
- progressMonitor.done();
+ activityMonitor.worked(2);
+ activityMonitor.done();
}
}
Modified: trunk/extensions/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/ZipSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/ZipSequencer.java 2008-10-29 18:23:01 UTC (rev 598)
+++ trunk/extensions/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/ZipSequencer.java 2008-10-29 20:09:42 UTC (rev 599)
@@ -26,13 +26,14 @@
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
-import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.ActivityMonitor;
import org.jboss.dna.graph.sequencers.SequencerContext;
import org.jboss.dna.graph.sequencers.SequencerOutput;
import org.jboss.dna.graph.sequencers.StreamSequencer;
/**
* @author Michael Trezzi
+ * @author John Verhaeg
*/
public class ZipSequencer implements StreamSequencer {
@@ -41,12 +42,12 @@
*
* @see org.jboss.dna.graph.sequencers.StreamSequencer#sequence(java.io.InputStream,
* org.jboss.dna.graph.sequencers.SequencerOutput, org.jboss.dna.graph.sequencers.SequencerContext,
- * org.jboss.dna.common.monitor.ProgressMonitor)
+ * org.jboss.dna.common.monitor.ActivityMonitor)
*/
public void sequence( InputStream stream,
SequencerOutput output,
SequencerContext context,
- ProgressMonitor progressMonitor ) {
+ ActivityMonitor activityMonitor ) {
try {
ZipInputStream in = new ZipInputStream(stream);
ZipEntry entry = in.getNextEntry();
15 years, 6 months
DNA SVN: r598 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph and 29 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-10-29 14:23:01 -0400 (Wed, 29 Oct 2008)
New Revision: 598
Added:
trunk/extensions/dna-sequencer-xml/
trunk/extensions/dna-sequencer-xml/.classpath
trunk/extensions/dna-sequencer-xml/.project
trunk/extensions/dna-sequencer-xml/pom.xml
trunk/extensions/dna-sequencer-xml/src/
trunk/extensions/dna-sequencer-xml/src/main/
trunk/extensions/dna-sequencer-xml/src/main/java/
trunk/extensions/dna-sequencer-xml/src/main/java/org/
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/DnaDtdLexicon.java
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/DnaXmlLexicon.java
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencer.java
trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencerI18n.java
trunk/extensions/dna-sequencer-xml/src/main/resources/
trunk/extensions/dna-sequencer-xml/src/main/resources/org/
trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/
trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/
trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/
trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/
trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/XmlSequencerI18n.properties
trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/xml.cnd
trunk/extensions/dna-sequencer-xml/src/test/
trunk/extensions/dna-sequencer-xml/src/test/java/
trunk/extensions/dna-sequencer-xml/src/test/java/org/
trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/
trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/
trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/
trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/
trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java
trunk/extensions/dna-sequencer-xml/src/test/resources/
trunk/extensions/dna-sequencer-xml/src/test/resources/CurrencyFormatterExample.mxml
trunk/extensions/dna-sequencer-xml/src/test/resources/Descriptor.1.0.xsd
trunk/extensions/dna-sequencer-xml/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml
trunk/extensions/dna-sequencer-xml/src/test/resources/log4j.properties
trunk/extensions/dna-sequencer-xml/src/test/resources/master.xml
trunk/extensions/dna-sequencer-xml/src/test/resources/plugin.xml
Removed:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/DnaDtdLexicon.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/DnaXmlLexicon.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlSequencer.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlSequencerTest.java
trunk/dna-graph/src/test/resources/CurrencyFormatterExample.mxml
trunk/dna-graph/src/test/resources/Descriptor.1.0.xsd
trunk/dna-graph/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml
trunk/dna-graph/src/test/resources/master.xml
trunk/dna-graph/src/test/resources/plugin.xml
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java
trunk/pom.xml
Log:
DNA-243 - Change (and move) XML Sequencer to use more general-purpose XML importer
http://jira.jboss.com/jira/browse/DNA-243
Moved the XmlSequencer into a separate extension project.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -75,13 +75,6 @@
public static I18n actualNewLocationMustHaveSameParentAsOldLocation;
public static I18n actualNewLocationMustHaveSameNameAsRequest;
- // XML Sequencer
- public static I18n errorSequencingXmlDocument;
- public static I18n fatalErrorSequencingXmlDocument;
- public static I18n sequencingXmlDocument;
- public static I18n canceledSequencingXmlDocument;
- public static I18n warningSequencingXmlDocument;
-
public static I18n errorImportingContent;
public static I18n unableToFindRepositorySourceWithName;
Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/DnaDtdLexicon.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/DnaDtdLexicon.java 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/DnaDtdLexicon.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -1,42 +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.graph.xml;
-
-import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.basic.BasicName;
-
-/**
- * @author Randall Hauch
- */
-public class DnaDtdLexicon {
-
- public static class Namespace {
- public static final String URI = "http://www.jboss.org/dna/dtd/1.0";
- public static final String PREFIX = "dnadtd";
- }
-
- public static final Name NAME = new BasicName(Namespace.URI, "name");
- public static final Name PUBLIC_ID = new BasicName(Namespace.URI, "publicId");
- public static final Name SYSTEM_ID = new BasicName(Namespace.URI, "systemId");
- public static final Name VALUE = new BasicName(Namespace.URI, "value");
- public static final Name ENTITY = new BasicName(Namespace.URI, "entity");
-}
Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/DnaXmlLexicon.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/DnaXmlLexicon.java 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/DnaXmlLexicon.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -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.graph.xml;
-
-import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.basic.BasicName;
-
-/**
- * @author Randall Hauch
- */
-public class DnaXmlLexicon {
-
- public static class Namespace {
- public static final String URI = "http://www.jboss.org/dna/xml/1.0";
- public static final String PREFIX = "dnaxml";
- }
-
- public static final Name CDATA = new BasicName(Namespace.URI, "cData");
- public static final Name CDATA_CONTENT = new BasicName(Namespace.URI, "cDataContent");
- public static final Name COMMENT = new BasicName(Namespace.URI, "comment");
- public static final Name COMMENT_CONTENT = new BasicName(Namespace.URI, "commentContent");
- public static final Name DOCUMENT = new BasicName(Namespace.URI, "document");
- public static final Name ELEMENT_CONTENT = new BasicName(Namespace.URI, "elementContent");
- public static final Name PROCESSING_INSTRUCTION = new BasicName(Namespace.URI, "processingInstruction");
- public static final Name PROCESSING_INSTRUCTION_CONTENT = new BasicName(Namespace.URI, "processingInstructionContent");
- public static final Name TARGET = new BasicName(Namespace.URI, "target");
-}
Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlSequencer.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlSequencer.java 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlSequencer.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -1,703 +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.graph.xml;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.common.util.StringUtil;
-import org.jboss.dna.graph.GraphI18n;
-import org.jboss.dna.graph.JcrLexicon;
-import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.NameFactory;
-import org.jboss.dna.graph.properties.NamespaceRegistry;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.sequencers.SequencerContext;
-import org.jboss.dna.graph.sequencers.SequencerOutput;
-import org.jboss.dna.graph.sequencers.StreamSequencer;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXNotRecognizedException;
-import org.xml.sax.SAXNotSupportedException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.DefaultHandler2;
-import org.xml.sax.helpers.XMLReaderFactory;
-
-/**
- * @author John Verhaeg
- */
-public class XmlSequencer implements StreamSequencer {
-
- private static final String DEFAULT_PRIMARY_TYPE = "nt:unstructured";
- private static final String DECL_HANDLER_FEATURE = "http://xml.org/sax/properties/declaration-handler";
- private static final String ENTITY_RESOLVER_2_FEATURE = "http://xml.org/sax/features/use-entity-resolver2";
- private static final String LEXICAL_HANDLER_FEATURE = "http://xml.org/sax/properties/lexical-handler";
- private static final String RESOLVE_DTD_URIS_FEATURE = "http://xml.org/sax/features/resolve-dtd-uris";
- private static final String LOAD_EXTERNAL_DTDS_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.sequencers.StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext,
- * ProgressMonitor)
- */
- public void sequence( InputStream stream,
- SequencerOutput output,
- SequencerContext context,
- ProgressMonitor monitor ) {
- monitor.beginTask(100.0, GraphI18n.sequencingXmlDocument);
- XMLReader reader;
- try {
- reader = XMLReaderFactory.createXMLReader();
- Handler handler = new Handler(output, context, monitor);
- reader.setContentHandler(handler);
- reader.setErrorHandler(handler);
- // Ensure handler acting as entity resolver 2
- reader.setProperty(DECL_HANDLER_FEATURE, handler);
- // Ensure handler acting as lexical handler
- reader.setProperty(LEXICAL_HANDLER_FEATURE, handler);
- // Ensure handler acting as entity resolver 2
- setFeature(reader, ENTITY_RESOLVER_2_FEATURE, true);
- // Prevent loading of external DTDs
- setFeature(reader, LOAD_EXTERNAL_DTDS_FEATURE, false);
- // Prevent the resolving of DTD entities into fully-qualified URIS
- setFeature(reader, RESOLVE_DTD_URIS_FEATURE, false);
- // Parse XML document
- reader.parse(new InputSource(stream));
- } catch (Exception error) {
- context.getLogger(getClass()).error(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
- monitor.getProblems().addError(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
- } finally {
- monitor.done();
- }
- }
-
- /**
- * Sets the reader's named feature to the supplied value, only if the feature is not already set to that value. This method
- * does nothing if the feature is not known to the reader.
- *
- * @param reader the reader; may not be null
- * @param featureName the name of the feature; may not be null
- * @param value the value for the feature
- */
- private void setFeature( XMLReader reader,
- String featureName,
- boolean value ) {
- try {
- if (reader.getFeature(featureName) != value) {
- reader.setFeature(featureName, value);
- }
- } catch (SAXNotRecognizedException meansFeatureNotRecognized) {
- } catch (SAXNotSupportedException meansFeatureNotSupported) {
- }
- }
-
- private final class Handler extends DefaultHandler2 {
-
- private final SequencerOutput output;
- private final SequencerContext context;
- private final ProgressMonitor monitor;
-
- private double progress;
-
- private Path path; // The DNA path of the node representing the current XML element
-
- // Cached instances of the name factory and commonly referenced names
- private final NameFactory nameFactory;
- private Name defaultPrimaryType;
-
- // Recursive map used to track the number of occurrences of names for elements under a particular path
- private Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name, List<IndexedName>>();
-
- // The stack of recursive maps being processed, with the head entry being the map for the current path
- private final LinkedList<Map<Name, List<IndexedName>>> nameToIndexedNamesMapStack = new LinkedList<Map<Name, List<IndexedName>>>();
-
- // The stack of XML namespace in scope, with the head entry being namespace of the closest ancestor element declaring a
- // namespace.
- private final LinkedList<String> nsStack = new LinkedList<String>();
-
- // Builder used to concatenate concurrent lines of CDATA into a single value.
- private StringBuilder cDataBuilder;
-
- // Builder used to concatenate concurrent lines of element content and entity evaluations into a single value.
- private StringBuilder contentBuilder;
-
- // The entity being processed
- private String entity;
-
- Handler( SequencerOutput output,
- SequencerContext context,
- ProgressMonitor monitor ) {
- assert output != null;
- assert monitor != null;
- assert context != null;
- this.output = output;
- this.context = context;
- this.monitor = monitor;
- // Initialize path to a an empty path relative to the SequencerOutput's target path.
- path = context.getValueFactories().getPathFactory().createRelativePath();
- // Cache name factory since it is frequently used
- nameFactory = context.getValueFactories().getNameFactory();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#attributeDecl(java.lang.String, java.lang.String, java.lang.String,
- * java.lang.String, java.lang.String)
- */
- @Override
- public void attributeDecl( String name,
- String name2,
- String type,
- String mode,
- String value ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
- */
- @Override
- public void characters( char[] ch,
- int start,
- int length ) throws SAXException {
- stopIfCancelled();
- String content = String.valueOf(ch, start, length);
- // Check if data should be appended to previously parsed CDATA
- if (cDataBuilder == null) {
- // If content is for an entity, replace with entity reference
- if (entity != null) {
- content = '&' + entity + ';';
- }
- // Check if first line of content
- if (contentBuilder == null) {
- contentBuilder = new StringBuilder(content);
- } else {
- // Append additional lines or entity evaluations to previous content, separated by a space
- if (entity == null) {
- contentBuilder.append(' ');
- }
- contentBuilder.append(content);
- // Text within builder will be output when another element or CDATA is encountered
- }
- } else {
- cDataBuilder.append(ch, start, length);
- // Text within builder will be output at the end of CDATA
- }
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#comment(char[], int, int)
- */
- @Override
- public void comment( char[] ch,
- int start,
- int length ) throws SAXException {
- stopIfCancelled();
- // Output separate nodes for each comment since multiple are allowed
- startElement(DnaXmlLexicon.COMMENT);
- output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.COMMENT);
- output.setProperty(path, DnaXmlLexicon.COMMENT_CONTENT, String.valueOf(ch, start, length));
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#elementDecl(java.lang.String, java.lang.String)
- */
- @Override
- public void elementDecl( String name,
- String model ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#endCDATA()
- */
- @Override
- public void endCDATA() throws SAXException {
- stopIfCancelled();
- // Output CDATA built in characters() method
- output.setProperty(path, DnaXmlLexicon.CDATA_CONTENT, cDataBuilder.toString());
- endElement();
- // Null-out builder to free memory
- cDataBuilder = null;
- updateProgress();
- }
-
- private void endContent() {
- if (contentBuilder != null) {
- // Normalize content
- String content = StringUtil.normalize(contentBuilder.toString());
- // Null-out builder to setup for subsequent content.
- // Must be done before call to startElement below to prevent infinite loop.
- contentBuilder = null;
- // Skip if nothing in content but whitespace
- if (content.length() > 0) {
- // Create separate node for each content entry since entries can be interspersed amongst child elements
- startElement(DnaXmlLexicon.ELEMENT_CONTENT);
- output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.ELEMENT_CONTENT);
- output.setProperty(path, DnaXmlLexicon.ELEMENT_CONTENT, content);
- endElement();
- }
- }
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#endDocument()
- */
- @Override
- public void endDocument() throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#endDTD()
- */
- @Override
- public void endDTD() throws SAXException {
- stopIfCancelled();
- }
-
- private void endElement() {
- // Recover parent's path, namespace, and indexedName map, clearing the ended element's map to free memory
- path = path.getParent();
- nameToIndexedNamesMap.clear();
- nameToIndexedNamesMap = nameToIndexedNamesMapStack.removeFirst();
- nsStack.removeFirst();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
- */
- @Override
- public void endElement( String uri,
- String localName,
- String name ) throws SAXException {
- stopIfCancelled();
- // Check if content still needs to be output
- endContent();
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#endEntity(java.lang.String)
- */
- @Override
- public void endEntity( String name ) throws SAXException {
- stopIfCancelled();
- entity = null;
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
- */
- @Override
- public void error( SAXParseException error ) {
- context.getLogger(XmlSequencer.class).error(error, GraphI18n.errorSequencingXmlDocument, error);
- monitor.getProblems().addError(error, GraphI18n.errorSequencingXmlDocument, error);
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#externalEntityDecl(java.lang.String, java.lang.String, java.lang.String)
- */
- @Override
- public void externalEntityDecl( String name,
- String publicId,
- String systemId ) throws SAXException {
- stopIfCancelled();
- // Add "synthetic" entity container to path to help prevent name collisions with XML elements
- Name entityName = DnaDtdLexicon.ENTITY;
- startElement(entityName);
- output.setProperty(path, JcrLexicon.PRIMARY_TYPE, entityName);
- output.setProperty(path, nameFactory.create(DnaDtdLexicon.NAME), name);
- output.setProperty(path, nameFactory.create(DnaDtdLexicon.PUBLIC_ID), publicId);
- output.setProperty(path, nameFactory.create(DnaDtdLexicon.SYSTEM_ID), systemId);
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
- */
- @Override
- public void fatalError( SAXParseException error ) {
- context.getLogger(XmlSequencer.class).error(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
- monitor.getProblems().addError(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
- }
-
- private Name getDefaultPrimaryType() {
- if (defaultPrimaryType == null) {
- defaultPrimaryType = nameFactory.create(DEFAULT_PRIMARY_TYPE);
- }
- return defaultPrimaryType;
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#ignorableWhitespace(char[], int, int)
- */
- @Override
- public void ignorableWhitespace( char[] ch,
- int start,
- int length ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#internalEntityDecl(java.lang.String, java.lang.String)
- */
- @Override
- public void internalEntityDecl( String name,
- String value ) throws SAXException {
- stopIfCancelled();
- // Add "synthetic" entity container to path to help prevent name collisions with XML elements
- Name entityName = DnaDtdLexicon.ENTITY;
- startElement(entityName);
- output.setProperty(path, JcrLexicon.PRIMARY_TYPE, entityName);
- output.setProperty(path, DnaDtdLexicon.NAME, name);
- output.setProperty(path, DnaDtdLexicon.VALUE, value);
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#notationDecl(java.lang.String, java.lang.String, java.lang.String)
- */
- @Override
- public void notationDecl( String name,
- String publicId,
- String systemId ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#processingInstruction(java.lang.String, java.lang.String)
- */
- @Override
- public void processingInstruction( String target,
- String data ) throws SAXException {
- stopIfCancelled();
- // Output separate nodes for each instruction since multiple are allowed
- Name name = DnaXmlLexicon.PROCESSING_INSTRUCTION;
- startElement(name);
- output.setProperty(path, JcrLexicon.PRIMARY_TYPE, name);
- output.setProperty(path, DnaXmlLexicon.TARGET, target);
- output.setProperty(path, DnaXmlLexicon.PROCESSING_INSTRUCTION_CONTENT, data);
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#skippedEntity(java.lang.String)
- */
- @Override
- public void skippedEntity( String name ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#startCDATA()
- */
- @Override
- public void startCDATA() throws SAXException {
- stopIfCancelled();
- // Output separate nodes for each CDATA since multiple are allowed
- startElement(DnaXmlLexicon.CDATA);
- // Prepare builder for concatenating consecutive lines of CDATA
- cDataBuilder = new StringBuilder();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#startDocument()
- */
- @Override
- public void startDocument() throws SAXException {
- stopIfCancelled();
- output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.DOCUMENT);
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#startDTD(java.lang.String, java.lang.String, java.lang.String)
- */
- @Override
- public void startDTD( String name,
- String publicId,
- String systemId ) throws SAXException {
- stopIfCancelled();
- output.setProperty(path, DnaDtdLexicon.NAME, name);
- output.setProperty(path, DnaDtdLexicon.PUBLIC_ID, publicId);
- output.setProperty(path, DnaDtdLexicon.SYSTEM_ID, systemId);
- updateProgress();
- }
-
- private void startElement( Name name ) {
- // Check if content still needs to be output
- endContent();
- // Add name to list of indexed names for this element to ensure we use the correct index (which is the size of the
- // list)
- List<IndexedName> indexedNames = nameToIndexedNamesMap.get(name);
- if (indexedNames == null) {
- indexedNames = new ArrayList<IndexedName>();
- nameToIndexedNamesMap.put(name, indexedNames);
- }
- IndexedName indexedName = new IndexedName();
- indexedNames.add(indexedName);
- // Add element name and the appropriate index to the path.
- // Per the JCR spec, the index must be relative to same-name sibling nodes
- path = context.getValueFactories().getPathFactory().create(path, name, indexedNames.size());
- path = path.getNormalizedPath();
- // Add the indexed name map to the stack and set the current map to the new element's map
- nameToIndexedNamesMapStack.addFirst(nameToIndexedNamesMap);
- nameToIndexedNamesMap = indexedName.nameToIndexedNamesMap;
- // Set the current namespace to whatever is declared by this element, or if not declared, to its nearest ancestor that
- // does declare a namespace.
- String ns = name.getNamespaceUri();
- if (ns.length() == 0) {
- nsStack.addFirst(nsStack.isEmpty() ? "" : nsStack.getFirst());
- } else {
- nsStack.addFirst(ns);
- }
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String,
- * org.xml.sax.Attributes)
- */
- @Override
- public void startElement( String uri,
- String localName,
- String name,
- Attributes attributes ) throws SAXException {
- stopIfCancelled();
- // Look for the "jcr:name" attribute, and use that if it's there
- Name type = getDefaultPrimaryType();
- Name nameObj = nameFactory.create(name);
- for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
- String ns = attributes.getURI(ndx);
- String attrLocalName = attributes.getLocalName(ndx);
- Object value = attributes.getValue(ndx);
- String jcrNsUri = context.getNamespaceRegistry().getNamespaceForPrefix("jcr");
- if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("name")) {
- nameObj = nameFactory.create(value);
- break;
- }
- }
- startElement(nameObj);
- output.setProperty(path, JcrLexicon.PRIMARY_TYPE, type);
- // Output this element's attributes using the attribute's namespace, if supplied, or the current namespace in scope.
- String inheritedNs = nsStack.getFirst();
- for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
- String ns = attributes.getURI(ndx);
- String attrLocalName = attributes.getLocalName(ndx);
- Object value = attributes.getValue(ndx);
- String jcrNsUri = context.getNamespaceRegistry().getNamespaceForPrefix("jcr");
- if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("primaryType")) {
- value = nameFactory.create(value);
- }
- if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("name")) {
- continue;
- }
- output.setProperty(path, nameFactory.create(ns.length() == 0 ? inheritedNs : ns, attrLocalName), value);
- }
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#startEntity(java.lang.String)
- */
- @Override
- public void startEntity( String name ) throws SAXException {
- stopIfCancelled();
- entity = name;
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#startPrefixMapping(java.lang.String, java.lang.String)
- */
- @Override
- public void startPrefixMapping( String prefix,
- String uri ) throws SAXException {
- stopIfCancelled();
- // Register any unregistered namespaces
- NamespaceRegistry registry = context.getNamespaceRegistry();
- if (!registry.isRegisteredNamespaceUri(uri)) {
- registry.register(prefix, uri);
- }
- updateProgress();
- }
-
- private void stopIfCancelled() throws SAXException {
- if (monitor.isCancelled()) {
- throw new SAXException(GraphI18n.canceledSequencingXmlDocument.text());
- }
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String,
- * java.lang.String)
- */
- @Override
- public void unparsedEntityDecl( String name,
- String publicId,
- String systemId,
- String notationName ) throws SAXException {
- stopIfCancelled();
- }
-
- private void updateProgress() {
- if (progress == 100.0) {
- progress = 1;
- } else {
- progress++;
- }
- monitor.worked(progress);
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
- */
- @Override
- public void warning( SAXParseException warning ) {
- context.getLogger(XmlSequencer.class).warn(warning, GraphI18n.warningSequencingXmlDocument);
- monitor.getProblems().addWarning(warning, GraphI18n.warningSequencingXmlDocument, warning);
- }
- }
-
- private class IndexedName {
-
- Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name, List<IndexedName>>();
-
- IndexedName() {
- }
- }
-}
Modified: trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
===================================================================
--- trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2008-10-29 18:23:01 UTC (rev 598)
@@ -62,12 +62,6 @@
actualNewLocationMustHaveSameParentAsOldLocation = The new location of {0} must be a sibling of the old location of {1}
actualNewLocationMustHaveSameNameAsRequest = The new location of {0} must have the same name as in the request ({1})
-errorSequencingXmlDocument = An error was received while sequencing XML: {0}
-fatalErrorSequencingXmlDocument = A fatal error was received while sequencing XML: {0}
-sequencingXmlDocument = Sequencing XML
-canceledSequencingXmlDocument = Canceled sequencing XML
-warningSequencingXmlDocument = A warning was received while sequencing XML: {0}
-
errorImportingContent = Error importing {0} content from {1}
unableToFindRepositorySourceWithName = Unable to find a repository source named "{0}"
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -47,8 +47,6 @@
import org.jboss.dna.graph.requests.CompositeRequest;
import org.jboss.dna.graph.requests.CreateNodeRequest;
import org.jboss.dna.graph.requests.Request;
-import org.jboss.dna.graph.xml.DnaDtdLexicon;
-import org.jboss.dna.graph.xml.DnaXmlLexicon;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@@ -76,8 +74,6 @@
xmlContent = new File("src/test/resources/repositoryImporterTestData1.xml").toURI();
context = new BasicExecutionContext();
context.getNamespaceRegistry().register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
- context.getNamespaceRegistry().register(DnaXmlLexicon.Namespace.PREFIX, DnaXmlLexicon.Namespace.URI);
- context.getNamespaceRegistry().register(DnaDtdLexicon.Namespace.PREFIX, DnaDtdLexicon.Namespace.URI);
context.getNamespaceRegistry().register("jcr", "http://www.jcp.org/jcr/1.0");
context.getNamespaceRegistry().register("nt", "http://www.jcp.org/jcr/nt/1.0");
sourceName = "sourceA";
Deleted: trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlSequencerTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlSequencerTest.java 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlSequencerTest.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -1,221 +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.graph.xml;
-
-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.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.common.monitor.SimpleProgressMonitor;
-import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.sequencers.MockSequencerContext;
-import org.jboss.dna.graph.sequencers.MockSequencerOutput;
-import org.jboss.dna.graph.sequencers.SequencerContext;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author John Verhaeg
- */
-public class XmlSequencerTest {
-
- private static final String CDATA = "dnaxml:cData";
- private static final String CDATA_CONTENT = "dnaxml:cDataContent";
- private static final String COMMENT = "dnaxml:comment";
- private static final String COMMENT_CONTENT = "dnaxml:commentContent";
- private static final String DOCUMENT = "dnaxml:document";
- private static final String DTD_NAME = "dnadtd:name";
- private static final String DTD_PUBLIC_ID = "dnadtd:publicId";
- private static final String DTD_SYSTEM_ID = "dnadtd:systemId";
- private static final String DTD_VALUE = "dnadtd:value";
- private static final String ELEMENT_CONTENT = "dnaxml:elementContent";
- private static final String ENTITY = "dnadtd:entity";
- private static final String PI = "dnaxml:processingInstruction";
- private static final String PI_CONTENT = "dnaxml:processingInstructionContent";
- private static final String TARGET = "dnaxml:target";
-
- private XmlSequencer sequencer;
- private InputStream stream;
- private MockSequencerOutput output;
- private ProgressMonitor monitor;
- private URL xml1;
- private URL xml2;
- private URL xml3;
- private URL xml4;
- private URL xsd;
- private SequencerContext context;
-
- @Before
- public void beforeEach() {
- sequencer = new XmlSequencer();
- context = new MockSequencerContext();
- output = new MockSequencerOutput(context);
- monitor = new SimpleProgressMonitor("Test activity");
- xml1 = this.getClass().getClassLoader().getResource("jackrabbitInMemoryTestRepositoryConfig.xml");
- assertThat(xml1, is(notNullValue()));
- xml2 = this.getClass().getClassLoader().getResource("master.xml");
- assertThat(xml2, is(notNullValue()));
- xml3 = this.getClass().getClassLoader().getResource("CurrencyFormatterExample.mxml");
- assertThat(xml3, is(notNullValue()));
- xml4 = this.getClass().getClassLoader().getResource("plugin.xml");
- assertThat(xml4, is(notNullValue()));
- xsd = this.getClass().getClassLoader().getResource("Descriptor.1.0.xsd");
- assertThat(xsd, is(notNullValue()));
- }
-
- @After
- public void afterEach() throws Exception {
- if (stream != null) {
- try {
- stream.close();
- } finally {
- stream = null;
- }
- }
- }
-
- @Test
- public void shouldSequenceXml() throws IOException {
- verifyDocument(xml1);
- verifyName(COMMENT + "[1]", "jcr:primaryType", COMMENT);
- String text = verify(COMMENT + "[1]", COMMENT_CONTENT, String.class);
- assertThat(text.startsWith("\n Licensed to the Apache Software Foundation (ASF)"), is(true));
- assertThat(text.endsWith(" limitations under the License.\n"), is(true));
- verifyString("/", DTD_NAME, "Repository");
- verifyString("/", DTD_PUBLIC_ID, "-//The Apache Software Foundation//DTD Jackrabbit 1.2//EN");
- verifyString("/", DTD_SYSTEM_ID, "http://jackrabbit.apache.org/dtd/repository-1.2.dtd");
- verifyName(COMMENT + "[2]", "jcr:primaryType", COMMENT);
- verifyString(COMMENT + "[2]", COMMENT_CONTENT, " Example Repository Configuration File ");
- verifyName("Repository[1]", "jcr:primaryType", "nt:unstructured");
- verifyName("Repository[1]/" + COMMENT + "[1]", "jcr:primaryType", COMMENT);
- }
-
- @Test
- public void shouldHandleNamespaces() throws IOException {
- verifyDocument(xml2);
- verifyName("book[1]/bookinfo[1]/xi:include[1]", "jcr:primaryType", "nt:unstructured");
- verifyString("book[1]/bookinfo[1]/xi:include[1]", "xi:href", "Author_Group.xml");
- verifyName("book[1]/bookinfo[1]/xi:include[2]", "jcr:primaryType", "nt:unstructured");
- verifyString("book[1]/bookinfo[1]/xi:include[2]", "xi:href", "Legal_Notice.xml");
- }
-
- @Test
- public void shouldSequenceEntityDeclarations() throws IOException {
- verifyDocument(xml2);
- verifyName(ENTITY + "[1]", "jcr:primaryType", ENTITY);
- verifyString(ENTITY + "[1]", DTD_NAME, "%RH-ENTITIES");
- verifyString(ENTITY + "[1]", DTD_SYSTEM_ID, "Common_Config/rh-entities.ent");
- verifyName(ENTITY + "[2]", "jcr:primaryType", ENTITY);
- verifyString(ENTITY + "[2]", DTD_NAME, "versionNumber");
- verifyString(ENTITY + "[2]", DTD_VALUE, "0.1");
- verifyName(ENTITY + "[3]", "jcr:primaryType", ENTITY);
- verifyString(ENTITY + "[3]", DTD_NAME, "copyrightYear");
- verifyString(ENTITY + "[3]", DTD_VALUE, "2008");
- }
-
- @Test
- public void shouldSequenceElementContent() throws IOException {
- verifyDocument(xml2);
- verifyString("book[1]/chapter[4]/sect1[1]/para[8]/" + ELEMENT_CONTENT + "[1]",
- ELEMENT_CONTENT,
- "The path expression is more complicated."
- + " Sequencer path expressions are used by the sequencing service to determine whether a particular changed node should be sequenced."
- + " The expressions consist of two parts: a selection criteria and an output expression."
- + " Here's a simple example:");
- verifyString("book[1]/chapter[4]/sect1[1]/para[8]/programlisting[1]/" + ELEMENT_CONTENT + "[1]",
- ELEMENT_CONTENT,
- "/a/b/c@title => /d/e/f");
- }
-
- @Test
- public void shouldSequenceCData() throws IOException {
- verifyDocument(xml3);
- verifyString("mx:Application[1]/mx:Script[1]/" + CDATA + "[1]",
- CDATA_CONTENT,
- "\n\n" + " import mx.events.ValidationResultEvent;\t\t\t\n"
- + " private var vResult:ValidationResultEvent;\n" + "\t\t\t\n"
- + " // Event handler to validate and format input.\n"
- + " private function Format():void {\n" + " \n"
- + " vResult = numVal.validate();\n\n"
- + " if (vResult.type==ValidationResultEvent.VALID) {\n"
- + " var temp:Number=Number(priceUS.text); \n"
- + " formattedUSPrice.text= usdFormatter.format(temp);\n" + " }\n"
- + " \n" + " else {\n"
- + " formattedUSPrice.text=\"\";\n" + " }\n" + " }\n"
- + " ");
- }
-
- @Test
- public void shouldSequenceProcessingInstructions() throws IOException {
- verifyDocument(xml4);
- verifyName(PI + "[1]", "jcr:primaryType", PI);
- verifyString(PI + "[1]", TARGET, "eclipse");
- verifyString(PI + "[1]", PI_CONTENT, "version=\"3.0\"");
- }
-
- @Test
- public void shouldSequenceXsds() throws IOException {
- verifyDocument(xsd);
- verifyName("xs:schema[1]", "jcr:primaryType", "nt:unstructured");
- verifyString("xs:schema[1]", "xs:targetNamespace", "http://ns.adobe.com/air/application/1.0");
- verifyString("xs:schema[1]", "xs:elementFormDefault", "qualified");
- verifyName("xs:schema[1]/xs:element[1]", "jcr:primaryType", "nt:unstructured");
- verifyString("xs:schema[1]/xs:element[1]", "xs:name", "application");
- }
-
- private <T> T verify( String nodePath,
- String property,
- Class<T> expectedClass ) {
- Object[] values = output.getPropertyValues(nodePath.length() == 0 ? "." : nodePath, property);
- assertThat(values, notNullValue());
- assertThat(values.length, is(1));
- Object value = values[0];
- assertThat(value, instanceOf(expectedClass));
- return expectedClass.cast(value);
- }
-
- private void verifyDocument( URL url ) throws IOException {
- stream = url.openStream();
- assertThat(stream, is(notNullValue()));
- sequencer.sequence(stream, output, context, monitor);
- verifyName("", "jcr:primaryType", DOCUMENT);
- }
-
- private void verifyName( String nodePath,
- String property,
- String expectedName ) {
- Name name = verify(nodePath, property, Name.class);
- assertThat(name, is(context.getValueFactories().getNameFactory().create(expectedName)));
- }
-
- private void verifyString( String nodePath,
- String property,
- String expectedString ) {
- String string = verify(nodePath, property, String.class);
- assertThat(string, is(expectedString));
- }
-}
Deleted: trunk/dna-graph/src/test/resources/CurrencyFormatterExample.mxml
===================================================================
--- trunk/dna-graph/src/test/resources/CurrencyFormatterExample.mxml 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/test/resources/CurrencyFormatterExample.mxml 2008-10-29 18:23:01 UTC (rev 598)
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Simple example to demonstrate the CurrencyFormatter. -->
-<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
-
- <mx:Script>
- <![CDATA[
-
- import mx.events.ValidationResultEvent;
- private var vResult:ValidationResultEvent;
-
- // Event handler to validate and format input.
- private function Format():void {
-
- vResult = numVal.validate();
-
- if (vResult.type==ValidationResultEvent.VALID) {
- var temp:Number=Number(priceUS.text);
- formattedUSPrice.text= usdFormatter.format(temp);
- }
-
- else {
- formattedUSPrice.text="";
- }
- }
- ]]>
- </mx:Script>
-
- <mx:CurrencyFormatter id="usdFormatter" precision="2"
- currencySymbol="$" decimalSeparatorFrom="."
- decimalSeparatorTo="." useNegativeSign="true"
- useThousandsSeparator="true" alignSymbol="left"/>
-
- <mx:NumberValidator id="numVal" source="{priceUS}" property="text"
- allowNegative="true" domain="real"/>
-
- <mx:Panel title="CurrencyFormatter Example" width="75%" height="75%"
- paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
-
- <mx:Form>
- <mx:FormItem label="Enter U.S. dollar amount:">
- <mx:TextInput id="priceUS" text="" width="50%"/>
- </mx:FormItem>
-
- <mx:FormItem label="Formatted amount: ">
- <mx:TextInput id="formattedUSPrice" text="" width="50%" editable="false"/>
- </mx:FormItem>
-
- <mx:FormItem>
- <mx:Button label="Validate and Format" click="Format();"/>
- </mx:FormItem>
- </mx:Form>
-
- </mx:Panel>
-</mx:Application>
Deleted: trunk/dna-graph/src/test/resources/Descriptor.1.0.xsd
===================================================================
--- trunk/dna-graph/src/test/resources/Descriptor.1.0.xsd 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/test/resources/Descriptor.1.0.xsd 2008-10-29 18:23:01 UTC (rev 598)
@@ -1,127 +0,0 @@
-<?xml version="1.0"?>
-<xs:schema
- xmlns:xs="http://www.w3.org/2001/XMLSchema"
- targetNamespace="http://ns.adobe.com/air/application/1.0"
- xmlns="http://ns.adobe.com/air/application/1.0"
- elementFormDefault="qualified"
->
- <xs:element name="application">
- <xs:complexType>
- <xs:all>
- <!-- About this application -->
- <xs:element name="id">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:pattern value="[A-Za-z0-9\-\.]{1,212}"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="name" type="xs:string" minOccurs="0"/>
- <xs:element name="version" type="xs:string"/>
- <xs:element name="filename">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <!-- name cannot begin with a ' ' (space), have any of these characters: *"/:<>?\|, and end with a . (dot) or ' ' (space) -->
- <xs:pattern value='[^\*"/:><\?\\\|\. ]|[^\*"/:><\?\\\| ][^\*"/:><\?\\\|]*[^\*"/:><\?\\\|\. ]'/>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="description" type="xs:string" minOccurs="0"/>
- <xs:element name="copyright" type="xs:string" minOccurs="0"/>
- <xs:element name="icon" type="IconType" minOccurs="0"/>
-
- <!-- How to start this application -->
- <xs:element name="initialWindow">
- <xs:complexType>
- <xs:all>
- <xs:element name="content" type="xs:anyURI" minOccurs="1" />
- <xs:element name="title" type="xs:string" minOccurs="0" />
-
- <xs:element name="systemChrome" minOccurs="0" >
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value="none"/>
- <xs:enumeration value="standard"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="transparent" type="xs:boolean" minOccurs="0" />
- <xs:element name="visible" type="xs:boolean" minOccurs="0" />
-
- <xs:element name="minimizable" type="xs:boolean" minOccurs="0" />
- <xs:element name="maximizable" type="xs:boolean" minOccurs="0" />
- <xs:element name="resizable" type="xs:boolean" minOccurs="0" />
-
- <xs:element name="x" type="xs:int" minOccurs="0" />
- <xs:element name="y" type="xs:int" minOccurs="0" />
- <xs:element name="width" type="xs:unsignedInt" minOccurs="0" />
- <xs:element name="height" type="xs:unsignedInt" minOccurs="0" />
- <xs:element name="minSize" type="BoundsSizeType" minOccurs="0" />
- <xs:element name="maxSize" type="BoundsSizeType" minOccurs="0" />
- </xs:all>
- </xs:complexType>
- </xs:element>
-
- <!-- About installing this application -->
- <xs:element name="installFolder" minOccurs="0">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <!-- installFolder cannot begin with a / (forward-slash) or a ' ' (space), have any of these characters: *":<>?\|, and end with a . (dot) or ' ' (space) -->
- <xs:pattern value='[^\*"/:><\?\\\|\. ]|[^\*"/:><\?\\\| ][^\*":><\?\\\|]*[^\*":><\?\\\|\. ]'/>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="programMenuFolder" minOccurs="0">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <!-- programMenuFolder cannot begin with a / (forward-slash) or a ' ' (space), have any of these characters: *":<>?\|, and end with a . (dot) or ' ' (space) -->
- <xs:pattern value='[^\*"/:><\?\\\|\. ]|[^\*"/:><\?\\\| ][^\*":><\?\\\|]*[^\*":><\?\\\|\. ]'/>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
-
- <!-- Features this application can opt in to -->
- <xs:element name="customUpdateUI" type="xs:boolean" minOccurs="0"/>
- <xs:element name="allowBrowserInvocation" type="xs:boolean" minOccurs="0"/>
- <xs:element name="fileTypes" minOccurs="0">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="fileType" minOccurs="0" maxOccurs="unbounded">
- <xs:complexType>
- <xs:all>
- <xs:element name="name" type="xs:string"/>
- <xs:element name="extension" type="xs:string"/>
- <xs:element name="description" type="xs:string" minOccurs="0"/>
- <xs:element name="contentType" type="xs:string" minOccurs="0"/>
- <xs:element name="icon" type="IconType" minOccurs="0"/>
- </xs:all>
- </xs:complexType>
- </xs:element>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- </xs:all>
-
- <!-- About the runtime version required -->
- <xs:attribute name="minimumPatchLevel" type="xs:unsignedInt"/>
- </xs:complexType>
- </xs:element>
-
- <!-- Type definitions -->
- <xs:complexType name="IconType">
- <xs:all>
- <xs:element name="image16x16" type="xs:anyURI" minOccurs="0"/>
- <xs:element name="image32x32" type="xs:anyURI" minOccurs="0"/>
- <xs:element name="image48x48" type="xs:anyURI" minOccurs="0"/>
- <xs:element name="image128x128" type="xs:anyURI" minOccurs="0"/>
- </xs:all>
- </xs:complexType>
- <xs:simpleType name="UnsignedIntListType">
- <xs:list itemType="xs:unsignedInt"/>
- </xs:simpleType>
- <xs:simpleType name="BoundsSizeType">
- <xs:restriction base="UnsignedIntListType">
- <xs:length value="2"/>
- </xs:restriction>
- </xs:simpleType>
-</xs:schema>
Deleted: trunk/dna-graph/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml
===================================================================
--- trunk/dna-graph/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml 2008-10-29 18:23:01 UTC (rev 598)
@@ -1,116 +0,0 @@
-<?xml version="1.0"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.2//EN"
- "http://jackrabbit.apache.org/dtd/repository-1.2.dtd">
-<!-- Example Repository Configuration File -->
-<Repository>
- <!--
- virtual file system where the repository stores global state
- (e.g. registered namespaces, custom node types, etc.)
- -->
- <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem">
- <param name="path" value="${rep.home}/repository"/>
- </FileSystem>
-
- <!--
- security configuration
- -->
- <Security appName="Jackrabbit">
- <!--
- access manager:
- class: FQN of class implementing the AccessManager interface
- -->
- <AccessManager class="org.apache.jackrabbit.core.security.SimpleAccessManager">
- <!-- <param name="config" value="${rep.home}/access.xml"/> -->
- </AccessManager>
-
- <LoginModule class="org.apache.jackrabbit.core.security.SimpleLoginModule">
- <!-- anonymous user name ('anonymous' is the default value) -->
- <param name="anonymousId" value="anonymous"/>
- <!--
- default user name to be used instead of the anonymous user
- when no login credentials are provided (unset by default)
- -->
- <!-- <param name="defaultUserId" value="superuser"/> -->
- </LoginModule>
- </Security>
-
- <!--
- location of workspaces root directory and name of default workspace
- -->
- <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
- <!--
- workspace configuration template:
- used to create the initial workspace if there's no workspace yet
- -->
- <Workspace name="Jackrabbit Core">
- <!--
- virtual file system of the workspace:
- class: FQN of class implementing the FileSystem interface
- -->
-
- <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem">
- <param name="path" value="${wsp.home}"/>
- </FileSystem>
- <!--
- persistence manager of the workspace:
- class: FQN of class implementing the PersistenceManager interface
- -->
- <PersistenceManager class="org.apache.jackrabbit.core.persistence.mem.InMemPersistenceManager">
- <param name="persistent" value="false"/>
- </PersistenceManager>
- <!--
- Search index and the file system it uses.
- class: FQN of class implementing the QueryHandler interface
- -->
- <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
- <param name="path" value="${wsp.home}/index"/>
- </SearchIndex>
- </Workspace>
-
- <!--
- Configures the versioning
- -->
- <Versioning rootPath="${rep.home}/version">
- <!--
- Configures the filesystem to use for versioning for the respective
- persistence manager
- -->
- <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem">
- <param name="path" value="${rep.home}/version" />
- </FileSystem>
-
- <!--
- Configures the persistence manager to be used for persisting version state.
- Please note that the current versioning implementation is based on
- a 'normal' persistence manager, but this could change in future
- implementations.
- -->
- <PersistenceManager class="org.apache.jackrabbit.core.persistence.mem.InMemPersistenceManager">
- <param name="persistent" value="false"/>
- </PersistenceManager>
- </Versioning>
-
- <!--
- Search index for content that is shared repository wide
- (/jcr:system tree, contains mainly versions)
- -->
- <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
- <param name="path" value="${rep.home}/repository/index"/>
- </SearchIndex>
-</Repository>
Deleted: trunk/dna-graph/src/test/resources/master.xml
===================================================================
--- trunk/dna-graph/src/test/resources/master.xml 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/test/resources/master.xml 2008-10-29 18:23:01 UTC (rev 598)
@@ -1,1890 +0,0 @@
-<!--
- ~ JBoss, Home of Professional Open Source.
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program 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 distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
-<!ENTITY % RH-ENTITIES SYSTEM "Common_Config/rh-entities.ent">
-<!ENTITY versionNumber "0.1">
-<!ENTITY copyrightYear "2008">
-<!ENTITY copyrightHolder "Red Hat Middleware, LLC.">]>
-<book>
- <bookinfo>
- <title>JBoss DNA</title>
- <subtitle>Getting Started Guide</subtitle>
- <releaseinfo>&versionNumber;
- </releaseinfo>
- <productnumber>&versionNumber;
- </productnumber>
- <issuenum>1</issuenum>
- <mediaobject>
- <imageobject role="fo">
- <imagedata fileref="images/dna-logo.png" align="center" />
- </imageobject>
- <imageobject role="pdf">
- <imagedata fileref="images/dna-logo.png" scale="75" align="center" />
- </imageobject>
- <imageobject role="html">
- <imagedata fileref="images/dna-logo.png" depth="3cm" />
- </imageobject>
- <imageobject role="xhtml">
- <imagedata fileref="images/dna-logo.png" depth="3cm" />
- </imageobject>
- <imageobject role="xhtml_single">
- <imagedata fileref="images/dna-logo.png" depth="3cm" />
- </imageobject>
- </mediaobject>
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Author_Group.xml" />
- <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Legal_Notice.xml" />
- </bookinfo>
- <preface id="preface" revision="1">
- <title>What this book covers</title>
- <para>The goal of this book is to help you learn about JBoss DNA and how you can use it in your own applications to get the
- most out of your JCR repositories.</para>
- <para>The first part of the book starts out with an introduction to content repositories and an overview of the JCR API,
- both of which are important aspects of JBoss DNA. This is followed by an overview of the JBoss DNA project, its
- architecture, and a basic roadmap for what's coming next.</para>
- <para>The next part of the book covers how to download and build the examples, how to use JBoss DNA with existing
- repositories, and how to build and use custom sequencers.</para>
- <para>
- If you have any questions or comments, please feel free to contact JBoss DNA's
- <ulink url="mailto:dna-users@jboss.org">user mailing list</ulink>
- or use the
- <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=272">user forums</ulink>
- . If you'd like to get involved on the project, join the
- <ulink url="http://www.jboss.org/dna/lists.html">mailing lists</ulink>
- ,
- <ulink url="http://www.jboss.org/dna/subversion.html">download the code</ulink>
- and get it building, and visit our
- <ulink url="http://jira.jboss.org/jira/browse/DNA">JIRA issue management system</ulink>
- . If there's something in particular you're interested in, talk with the community - there may be others interested in the
- same thing.
- </para>
- </preface>
- <chapter id="introduction">
- <title>Introduction</title>
- <para>There are a lot of choices for how applications can store information persistently so that it can be accessed at a
- later time and by other processes. The challenge developers face is how to use an approach that most closely matches the
- needs of their application. This choice becomes more important as developers choose to focus their efforts on
- application-specific logic, delegating much of the responsibilities for persistence to libraries and frameworks.</para>
- <para>
- Perhaps one of the easiest techniques is to simply store information in
- <emphasis>files</emphasis>
- . The Java language makes working with files relatively easy, but Java really doesn't provide many bells and whistles. So
- using files is an easy choice when the information is either not complicated (for example property files), or when users may
- need to read or change the information outside of the application (for example log files or configuration files). But using
- files to persist information becomes more difficult as the information becomes more complex, as the volume of it increases,
- or if it needs to be accessed by multiple processes. For these situations, other techniques often offer better choices.
- </para>
- <para>
- Another technique built into the Java language is
- <emphasis>Java serialization</emphasis>
- , which is capable of persisting the state of an object graph so that it can be read back in at a later time. However, Java
- serialization can quickly become tricky if the classes are changed, and so it's beneficial usually when the information is
- persisted for a very short period of time. For example, serialization is sometimes used to send an object graph from one
- process to another.
- </para>
- <para>
- One of the more popular persistence technologies is the
- <emphasis>relational database</emphasis>
- . Relational database management systems have been around for decades and are very capable. The Java Database Connectivity
- (JDBC) API provides a standard interface for connecting to and interacting with relational databases. However, it is a
- low-level API that requires a lot of code to use correctly, and it still doesn't abstract away the DBMS-specific SQL
- grammar. Also, working with relational data in an object-oriented language can feel somewhat unnatural, so many developers
- map this data to classes that fit much more cleanly into their application. The problem is that manually creating this
- mapping layer requires a lot of repetitive and non-trivial JDBC code.
- </para>
- <para>
- <emphasis>Object-relational mapping</emphasis>
- libraries automate the creation of this mapping layer and result in far less code that is much more maintainable with
- performance that is often as good as (if not better than) handwritten JDBC code. The new
- <ulink url="http://java.sun.com/developer/technicalArticles/J2EE/jpa/">Java Persistence API (JPA)</ulink>
- provide a standard mechanism for defining the mappings (through annotations) and working with these entity objects. Several
- commercial and open-source libraries implement JPA, and some even offer additional capabilities and features that go beyond
- JPA. For example,
- <ulink url="http://www.hibernate.org">Hibernate</ulink>
- is one of the most feature-rich JPA implementations and offers object caching, statement caching, extra association
- mappings, and other features that help to improve performance and usefulness.
- </para>
- <para>
- While relational databases and JPA are solutions that work for many applications, they become more limited in cases when the
- information structure is highly flexible, is not known
- <emphasis>a priori</emphasis>
- , or is subject to frequent change and customization. In these situations,
- <emphasis>content repositories</emphasis>
- may offer a better choice for persistence. Content repositories are almost a hybrid between relational databases and file
- systems, and typically provide other capabilities as well, including versioning, indexing, search, access control,
- transactions, and observation. Because of this, content repositories are used by content management systems (CMS), document
- management systems (DMS), and other applications that manage electronic files (e.g., documents, images, multi-media, web
- content, etc.) and metadata associated with them (e.g., author, date, status, security information, etc.). The
- <ulink url="http://www.jcp.org/en/jsr/detail?id=170">Content Repository for Java technology API</ulink>
- provides a standard Java API for working with content repositories. Abbreviated "JCR", this API was developed as part of the
- Java Community Process under
- <ulink url="http://www.jcp.org/en/jsr/detail?id=170">JSR-170</ulink>
- and is being revised under
- <ulink url="http://www.jcp.org/en/jsr/detail?id=283">JSR-283</ulink>
- .
- </para>
- <para>
- The
- <emphasis>JBoss DNA project</emphasis>
- is building the tools and services that surround content repositories. Nearly all of these capabilities are to be hidden
- below the JCR API and involve automated processing of the information in the repository. Thus, JBoss DNA can add value to
- existing repository implementations. For example, JCR repositories offer the ability to upload files into the repository and
- have the file content indexed for search purposes. JBoss DNA also defines a library for "sequencing" content - to extract
- meaningful information from that content and store it in the repository, where it can then be searched, accessed, and
- analyzed using the JCR API.
- </para>
- <para> JBoss DNA is building other features as well. One goal of JBoss DNA is to create federated repositories that
- dynamically merge the information from multiple databases, services, applications, and other JCR repositories. Another is to
- create customized views based upon the type of data and the role of the user that is accessing the data. And yet another is
- to create a REST-ful API to allow the JCR content to be accessed easily by other applications written in other languages.
- </para>
- <para>
- The
- <link linkend="jboss_dna">next chapter</link>
- in this book goes into more detail about JBoss DNA and its architecture, the different components, what's available now, and
- what's coming in future releases.
- <link linkend="downloading_and_running">Chapter 3</link>
- then provides instructions for downloading and running the sequencer examples for the current release.
- <link linkend="using_dna">Chapter 4</link>
- walks through how to use JBoss DNA in your applications, while
- <link linkend="custom_sequencers">Chapter 5</link>
- goes over how to create custom sequencers. Finally,
- <link linkend="future_directions">Chapter 6</link>
- wraps things up with a discussion about the future of JBoss DNA.
- </para>
- </chapter>
- <chapter id="jboss_dna">
- <title>Understanding JBoss DNA</title>
- <sect1 id="jboss_dna_overview">
- <title>Overview</title>
- <para>JBoss DNA is a repository and set of tools that make it easy to capture, version, analyze, and understand the
- fundamental building blocks of information. As models, service and process definitions, schemas, source code, and other
- artifacts are added to the repository, JBoss DNA "sequences" the makeup of these components and extracts their structure
- and interdependencies. The JBoss DNA web application allows end users to access, visualize, and edit this information in
- the terminology and structure they are familiar with. Such domain-specific solutions can be easily created with little or
- no programming.</para>
- <para> JBoss DNA supports the Java Content Repository (JCR) standard and is able to provide a single integrated view of
- multiple repositories, external databases, services, and applications, ensuring that JBoss DNA has access to the latest
- and most reliable master data. For instance, DNA could provide in a single view valuable insight into the business
- processes and process-level services impacted by a change to in an intermediary web server operation defined via WSDL.
- Similarly, a user could quickly view and navigate the dependencies between the data source models and transformation
- information stored within a content repository, the code base stored within a version control system, and the database
- schemas used by an application.</para>
- </sect1>
- <sect1 id="architecture">
- <title>Architecture</title>
- <para>The architecture for JBoss DNA consists of several major components that will be built on top of standard APIs,
- including JCR, JDBC, JNDI and HTTP. The goal is to allow these components to be assembled as needed and add value on top
- of other DNA components or third-party systems that support these standard APIs.</para>
- <mediaobject>
- <imageobject role="fo">
- <imagedata align="center" fileref="images/dna-architecture.png" />
- </imageobject>
- <imageobject role="html">
- <imagedata align="center" fileref="images/dna-architecture.png" />
- </imageobject>
- </mediaobject>
- <para>
- As shown in the diagram above, the major components are (starting at the top):
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">DNA Eclipse Plugins</emphasis>
- enable Eclipse users to access the contents of a JBoss DNA repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA JDBC Driver</emphasis>
- provides a driver implementation, allowing JDBC-aware applications to connect to and use a JBoss DNA repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Remote JCR</emphasis>
- is a client-side component for accessing remote JCR repositories.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Web Application</emphasis>
- is used by end users and domain experts to visualize, search, edit, change and tag the repository content. The web
- application uses views to define how different types of information are to be presented and edited in
- domain-specific ways. The goal is that this web application is easily customized and branded for inclusion into
- other solutions and application systems. The DNA Web Application operates upon any JCR-compliant repository,
- although it does rely upon the DNA analysis and templating services.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Publishing Server</emphasis>
- allows content to be downloaded, uploaded, and edited using the Atom Publishing Protocol. With the DNA Publishing
- Server, the content of the repository can easily be created, read, edited, and deleted using the standard HTTP
- operations of POST, GET, PUT, and DELETE (respectively). More and more tools are being created that support working
- with Atom Publishing servers. The DNA Publishing Server operates upon any JCR-compliant repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA WebDAV Server</emphasis>
- allows clients such as Microsoft Windows and Apple OS X to connect to, read, and edit the content in the repository
- using the WebDAV standard. Since WebDAV is an extension of HTTP, web browsers are able to read (but not modify) the
- content served by a WebDAV compliant server. The DNA WebDAV Server operates upon any JCR-compliant repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Sequencers</emphasis>
- are pluggable components that make it possible for content to be uploaded to the repository and automatically
- processed to extract meaningful structure and place that structure in the repository. Once this information is in
- the repository, it can be viewed, edited, analyzed, searched, and related to other content. DNA defines a Java
- interface that sequencers must implement. DNA sequencers operate upon any JCR-compliant repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Analyses</emphasis>
- are pluggable components that analyze content and the relationships between content to generate reports or to answer
- queries. DNA will include some standard analyzers, like dependency analysis and similarity analysis, that are
- commonly needed by many different solutions. DNA analyzers operate upon any JCR-compliant repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Views</emphasis>
- are definitions of how types of information are to be presented in a user interface to allow for creation, reading,
- editing, and deletion of information. DNA view definitions consist of data stored in a JCR repository, and as such
- views can be easily added, changed or removed entirely by using the DNA Web Application, requiring no programming.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Federation</emphasis>
- is an implementation of the JCR API that builds the content within the repository by accessing and integrating
- information from multiple sources. DNA Federation allows the integration of external systems, like other JCR
- repositories, databases, applications, and services.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Connectors</emphasis>
- are used to communicate with these external sources of information. In the federation engine, each source is able to
- contribute node structure and node properties to any part of the federated graph, although typically many connectors
- will contribute most of their information to isolated subgraphs. The result is that integration from a wide range of
- systems can be integrated and accessed through the DNA Web Application, DNA Publishing Server, and DNA WebDAV
- Server. Connectors also may optionally participate in distributed transactions by exposing an XAResource.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">DNA Maven</emphasis>
- is a classloader library compatible with Maven 2 project dependencies. This allows the creation of Java ClassLoader
- instances using Maven 2 style paths, and all dependencies are transitively managed and included.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- Continue reading the rest of this chapter for more detail about the
- <link linkend="sequencers">sequencing framework</link>
- available in this release, or the
- <link linkend="federation">federation engine</link>
- and
- <link linkend="federation_connectors">connectors</link>
- that will be the focus of the next release. Or, skip to the
- <link linkend="downloading_and_running">examples</link>
- to see how to start using JBoss DNA &versionNumber;
- today.
- </para>
- </sect1>
- <sect1 id="sequencers">
- <title>Sequencing content</title>
- <para> The current JBoss DNA release contains a sequencing framework that is designed to sequence data (typically files)
- stored in a JCR repository to automatically extract meaningful and useful information. This additional information is then
- saved back into the repository, where it can be accessed and used.</para>
- <para> In other words, you can just upload various kinds of files into a JCR repository, and DNA automatically processes
- those files to extract meaningful structured information. For example, load DDL files into the repository, and let
- sequencers extract the structure and metadata for the database schema. Load Hibernate configuration files into the
- repository, and let sequencers extract the schema and mapping information. Load Java source into the repository, and let
- sequencers extract the class structure, JavaDoc, and annotations. Load a PNG, JPEG, or other image into the repository,
- and let sequencers extract the metadata from the image and save it in the repository. The same with XSDs, WSDL, WS
- policies, UML, MetaMatrix models, etc.</para>
- <para>
- JBoss DNA sequencers sit on top of existing JCR repositories (including federated repositories) - they basically extract
- more useful information from what's already stored in the repository. And they use the existing JCR versioning system. Each
- sequencer typically processes a single kind of file format or a single kind of content. </para>
- <para>The following sequencers are included in JBoss DNA:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">Image sequencer</emphasis>
- - A sequencer that processes the binary content of an image file, extracts the metadata for the image, and then
- writes that image metadata to the repository. It gets the file format, image resolution, number of bits per pixel
- (and optionally number of images), comments and physical resolution from JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM,
- PGM, PPM, and PSD files. (This sequencer may be improved in the future to also extract EXIF metadata from JPEG
- files; see
- <ulink url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ulink>
- .)
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">MP3 sequencer</emphasis>
- - A sequencer that processes the contents of an MP3 audio file, extracts the metadata for the file, and then
- writes that image metadata to the repository. It gets the title, author, album, year, and comment.
- (This sequencer may be improved in the future to also extract other ID3 metadata from other audio file formats; see
- <ulink url="http://jira.jboss.org/jira/browse/DNA-66">DNA-26</ulink>
- .)
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- As the community develops additional sequencers, they will also be included in JBoss DNA. Some of those that have been
- identified as being useful include:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">XML Schema Document (XSD) Sequencer</emphasis>
- - Process XSD files and extract the various elements, attributes, complex types, simple types, groups, and other
- information. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-32">DNA-32</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Web Service Definition Language (WSDL) Sequencer</emphasis>
- - Process WSDL files and extract the services, bindings, ports, operations, parameters, and other information. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-33">DNA-33</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Hibernate File Sequencer</emphasis>
- - Process Hibernate configuration (cfg.xml) and mapping (hbm.xml) files to extract the configuration and mapping
- information. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-61">DNA-61</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">XML Metadata Interchange (XMI) Sequencer</emphasis>
- - Process XMI documents that contain UML models or models using another metamodel, extracting the model structure
- into the repository. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-31">DNA-31</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">ZIP Archive Sequencer</emphasis>
- - Process ZIP archive files to extract (explode) the contents into the repository. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-63">DNA-63</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Java Archive (JAR) Sequencer</emphasis>
- - Process JAR files to extract (explode) the contents into the classes and file resources. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-64">DNA-64</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Java Class File Sequencer</emphasis>
- - Process Java class files (bytecode) to extract the class structure (including annotations) into the repository.
- (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-62">DNA-62</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Java Source File Sequencer</emphasis>
- - Process Java source files to extract the class structure (including annotations) into the repository. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-51">DNA-51</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">PDF Sequencer</emphasis>
- - Process PDF files to extract the document metadata, including table of contents. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-50">DNA-50</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Maven 2 POM Sequencer</emphasis>
- - Process Maven 2 Project Object Model (POM) files to extract the project information, dependencies, plugins, and
- other content. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-24">DNA-24</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Data Definition Language (DDL) Sequencer</emphasis>
- - Process various dialects of DDL, including that from Oracle, SQL Server, MySQL, PostgreSQL, and others. May need
- to be split up into a different sequencer for each dialect. (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ulink>
- )
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">MP3 and MP4 Sequencer</emphasis>
- - Process MP3 and MP4 audio files to extract the name of the song, artist, album, track number, and other metadata.
- (See
- <ulink url="http://jira.jboss.org/jira/browse/DNA-30">DNA-30</ulink>
- )
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- The
- <link linkend="using_dna">examples</link>
- in this book go into more detail about how sequencers are managed and used, and
- <link linkend="custom_sequencers">Chapter 5</link>
- goes into detail about how to write custom sequencers.
- </para>
- </sect1>
- <sect1 id="federation">
- <title>Federating content</title>
- <para>There is a lot of information stored in many of different places: databases, repositories, SCM systems,
- registries, file systems, services, etc. The purpose of the federation engine is to allow applications to use the JCR API
- to access that information as if it were all stored in a single JCR repository, but to really leave the information where
- it is.</para>
- <para>Why not just move the information into a JCR repository? Most likely there are existing applications that rely upon
- that information being where it is. If we were to move it, then all those applications would break. Or they'd have to be
- changed to use JCR. If the information is being used, the most practical thing is to leave it where it is.</para>
- <para>
- Then why not just copy the information into a JCR repository? Actually, there are times when it's perfectly reasonable to
- make a copy of the data. Perhaps the system managing the existing information cannot handle the additional load of more
- clients. Or, perhaps the information doesn't change, or it does change and we want snapshots that don't change. But more
- likely, the data
- <emphasis>does</emphasis>
- change. So if applications are to use the most current information and we make copies of the data, we have to keep the
- copies synchronized with the master. That's generally a lot of work.
- </para>
- <para>The JBoss DNA federation engine lets us leave the information where it is, yet lets client applications use the JCR
- API to access all the information without caring where the information really exists. If the underlying information
- changes, client applications using JCR observation will be notified of the changes. If a JBoss DNA federated repository is
- configured to allow updates, client applications can change the information in the repository and JBoss DNA will propagate
- those changes down to the original source.</para>
- <sect2 id="federation_connectors">
- <title>Connecting to information sources</title>
- <para>
- The JBoss DNA federation engine will use connectors to interact with different information sources to get at the content
- in those systems. Some ideas for connectors include:
- <itemizedlist>
- <listitem>
- <para>
- <emphasis role="strong">JCR Repository Connector</emphasis>
- - Connect to and interact with other JCR repositories.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">File System Connector</emphasis>
- - Expose the files and directories on a file system through JCR.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Maven 2 Repository Connector</emphasis>
- - Access and expose the contents of a Maven 2 repository (either on the local file system or via HTTP) through
- JCR.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">JDBC Metadata Connector</emphasis>
- - Connect to relational databases via JDBC and expose their schema as content in a repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">UDDI Connector</emphasis>
- - Interact with UDDI registries to integrate their content into a repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">SVN Connector</emphasis>
- - Interact with Subversion software configuration management (SCM) repositories to expose the managed resources
- through JCR. Consider using the
- <ulink url="http://svnkit.com/">SVNkit</ulink>
- (dual license) library for an API into Subversion.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">CVS Connector</emphasis>
- - Interact with CVS software configuration management (SCM) repositories to expose the managed resources through
- JCR.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">JDBC Storage Connector</emphasis>
- - Store and access information in a relational database. Also useful for persisting information in the federated
- repository not stored elsewhere.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">Distributed Database Connector</emphasis>
- - Store and access information in a
- <ulink url="http://www.hypertable.org/">Hypertable</ulink>
- or
- <ulink url="http://hadoop.apache.org/hbase/">HBase</ulink>
- distributed databases. Also useful for persisting information in the federated repository not stored elsewhere.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- If the connectors allow the information they contribute to be updated, they must provide an
- <code>XAResource</code>
- implementation that can be used with a Java Transaction Service. Connectors that provide read-only access need not
- provide an implementation.
- </para>
- <para>
- Also, connectors talk to
- <emphasis>sources</emphasis>
- of information, and it's quite likely that the same connector is used to talk to different sources. Each source contains
- the configuration details (e.g., connection information, location, properties, options, etc.) for working with that
- particular source, as well as a reference to the connector that should be used to establish connections to the source.
- And of course, sources can be added or removed without having to stop and restart the federated repository.
- </para>
- </sect2>
- <sect2 id="federation_graph">
- <title>Building the unified graph</title>
- <para> The federation engine works by effectively building up a single graph by querying each source and merging or
- unifying the responses. This information is cached, which improves performance, reduces the number of (potentially
- expensive) remote calls, reduces the load on the sources, and helps mitigate problems with source availability. As
- clients interact with the repository, this cache is consulted first. When the requested portion of the graph (or
- "subgraph") is contained completely in the cache, it is retuned immediately. However, if any part of the requested
- subgraph is not in the cache, each source is consulted for their contributions to that subgraph, and any results are
- cached.</para>
- <para> This basic flow makes it possible for the federated repository to build up a local cache of the integrated graph
- (or at least the portions that are used by clients). In fact, the federated repository caches information in a manner
- that is similar to that of the Domain Name System (DNS). As sources are consulted for their contributions, the source
- also specifies whether it is the authoritative source for this information (some sources that are themselves federated
- may not be the information's authority), whether the information may be modified, the time-to-live (TTL) value (the time
- after which the cached information should be refreshed), and the expiration time (the time after which the cached
- information is no longer valid). In effect, the source has complete control over how the information it contributes is
- cached and used.</para>
- <para>
- The federated repository also needs to incorporate
- <emphasis>negative caching</emphasis>
- , which is storage of the knowledge that something does not exist. Sources can be configured to contribute information
- only below certain paths (e.g.,
- <code>/A/B/C</code>
- ), and the federation engine can take advantage of this by never consulting that source for contributions to information
- on other paths. However, below that path, any negative responses must also be cached (with appropriate TTL and expiry
- parameters) to prevent the exclusion of that source (in case the source has information to contribute at a later time)
- or the frequent checking with the source.
- </para>
- </sect2>
- <sect2 id="federation_queries">
- <title>Searching and querying</title>
- <para> The JBoss DNA federated repository will also support queries against the integrated and unified graph. In some
- situations the query can be determined to apply to a single source, but in most situations the query must be planned
- (and possibly rewritten) such that it can be pushed down to all the appropriate sources. Also, the cached results must
- be consulted prior to returning the query results, as the results from one source might have contributions from another
- source.</para>
- <note>
- <para> It is hoped that the MetaMatrix query engine can be used for this purpose after it is open-sourced. This engine
- implements sophisticated query planning and optimization techniques for working efficiently with multiple sources.
- </para>
- </note>
- <para>Searching the whole federated repository is also important. This allows users to simply supply a handful of
- search terms, and to get results that are ranked based upon how close each result is to the search terms. (Searching is
- very different from querying, which involves specifying the exact semantics of what is to be searched and how the
- information is to be compared.) JBoss DNA will incorporate a search engine (e.g., likely to be Lucene) and will populate
- the engine's indexes using the federated content and the cached information. Notifications of changing information will
- be reflected in the indexes, but some sources may want to explicitly allow or disallow periodic crawling of their
- content.</para>
- </sect2>
- <sect2 id="federation_updates">
- <title>Updating content</title>
- <para>
- The JBoss DNA federated repositories also make it possible for client applications to make changes to the unified graph
- within the context of distributed transactions. According to the JCR API, client applications use the Java Transaction
- API (JTA) to control the boundaries of their transactions. Meanwhile, the federated repository uses a
- <ulink url="http://www.jboss.org/jbosstm/">distributed transaction service</ulink>
- to coordinate the XA resources provided by the connectors.
- </para>
- <para> It is quite possible that clients add properties to nodes in the unified graph, and that this information cannot be
- handled by the same underlying source that contributed to the node. In this case, the federated repository can be
- configured with a fallback source that will be used used to store this "extra" information.</para>
- <para>
- It is a goal that non-XA sources (i.e., sources that use connectors without XA resources) can participate in distributed
- transactions through the use of
- <emphasis>compensating transactions</emphasis>
- . Because the JBoss DNA federation engine implements the JCR observation system, it is capable of recording all of the
- changes made to the distributed graph (and those changes sent to each updatable source). Therefore, if a non-XA source
- is involved in a distributed transaction that must be rolled back, any changes made to non-XA sources can be undone. (Of
- course, this does not make the underlying source transactional: non-transactional sources still may expose the interim
- changes to other clients.)
- </para>
- </sect2>
- <sect2 id="federation_events">
- <title>Observing changes</title>
- <para> The JCR API supports observing a repository to receive notifications of additions, changes and deletions of nodes
- and properties. The JBoss DNA federated repository will support this API through two primary means.</para>
- <para> When the changes are made through the federated repository, the JBoss DNA federation engine is well aware of the
- set of changes that have been (or are being) made to the unified graph. These events are directly propagated to
- listeners.</para>
- <para> Sources have the ability to publish events, making it possible for the JBoss DNA federation engine and clients that
- have registered listeners to be notified of changes in the information managed by that source. These events are first
- processed by the federation engine and possibly altered based upon contributions from other sources. (The federation
- engine also uses these events to update or purge information in the cache, which may add to the event set.) The
- resulting (and possibly altered) event set is then sent to all client listeners.</para>
- </sect2>
- </sect1>
- </chapter>
- <!-- ====================================================================================================
- Chapter
- ==================================================================================================== -->
- <chapter id="downloading_and_running">
- <title>Running the example application</title>
- <para>
- This chapter provides instructions for downloading and running a sample application that demonstrates how JBoss DNA works
- with a JCR repository to automatically sequence changing content to extract useful information. So read on to get the simple
- application running, and then in the
- <link linkend="using_dna">next chapter</link>
- we'll dive into the source code for the example and show how to use JBoss DNA in your own applications.
- </para>
- <para>JBoss DNA uses Maven 2 for its build system, as is this example. Using Maven 2 has several advantages, including
- the ability to manage dependencies. If a library is needed, Maven automatically finds and downloads that library, plus
- everything that library needs. This means that it's very easy to build the examples - or even create a maven project that
- depends on the JBoss DNA JARs.</para>
- <note>
- <para>
- To use Maven with JBoss DNA, you'll need to have
- <ulink url="http://java.sun.com/javase/downloads/index_jdk5.jsp">JDK 5 or 6</ulink>
- and Maven 2.0.7 (or higher).
- </para>
- <para>
- Maven can be downloaded from
- <ulink url="http://maven.apache.org/">http://maven.apache.org/</ulink>
- , and is installed by unzipping the
- <code>maven-2.0.7-bin.zip</code>
- file to a convenient location on your local disk. Simply add
- <code>$MAVEN_HOME/bin</code>
- to your path and add the following profile to your
- <code>~/.m2/settings.xml</code>
- file:
- <programlisting role="XML" language="xml"><settings>
- <profiles>
- <profile>
- <id>jboss.repository</id>
- <activation>
- <property>
- <name>!jboss.repository.off</name>
- </property>
- </activation>
- <repositories>
- <repository>
- <id>snapshots.jboss.org</id>
- <url>http://snapshots.jboss.org/maven2</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- <repository>
- <id>repository.jboss.org</id>
- <url>http://repository.jboss.org/maven2</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
- </repositories>
- <pluginRepositories>
- <pluginRepository>
- <id>repository.jboss.org</id>
- <url>http://repository.jboss.org/maven2</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </pluginRepository>
- <pluginRepository>
- <id>snapshots.jboss.org</id>
- <url>http://snapshots.jboss.org/maven2</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </pluginRepository>
- </pluginRepositories>
- </profile>
- </profiles>
-</settings></programlisting>
- This profile informs Maven of the two JBoss repositories (snapshots and releases) that contain
- all of the JARs for JBoss DNA and all dependent libraries.</para>
- </note>
- <sect1 id="downloading">
- <title>Downloading and compiling</title>
- <para>The next step is to <ulink url="http://www.jboss.org/file-access/default/members/dna/downloads/0.1/jboss-...">download</ulink>
- the example for this Getting Started guide, and extract the contents to a convenient location on your local disk.
- You'll find the example contains the following files, which are organized according to the standard Maven directory structure:
- <programlisting>
-examples/pom.xml
- sequencers/pom.xml
- /src/main/assembly
- /config
- /java
- /resources
- /test/java
- /resources
- </programlisting>
- </para>
- <para>There are essentially two Maven projects: a <code>sequencers</code> project and a parent project. All of the source
- for the example is located in the <code>sequencers</code> subdirectory. And you may have noticed that none
- of the JBoss DNA libraries are there. This is where Maven comes in. The two <code>pom.xml</code> files tell
- Maven everything it needs to know about what libraries are required and how to build the example.</para>
- <para>In a terminal, go to the <code>examples</code> directory and run <emphasis role="strong"><code>mvn install</code></emphasis>.
- This command downloads all of the JARs necessary to compile and build the example, including the JBoss DNA libraries,
- the libraries they depend on, and any missing Maven components. (These are downloaded from the JBoss repositories
- only once and saved on your machine. This means that the next time you run Maven, all the libraries will
- already be available locally, and the build will run much faster.) The command then continues by compiling the example's source
- code (and unit tests) and running the unit tests. The build is successful if you see the following:
- <programlisting language="bash">$ mvn install
-...
-[INFO] ------------------------------------------------------------------------
-[INFO] Reactor Summary:
-[INFO] ------------------------------------------------------------------------
-[INFO] Getting Started examples .............................. SUCCESS [2.106s]
-[INFO] Sequencer Examples .................................... SUCCESS [9.768s]
-[INFO] ------------------------------------------------------------------------
-[INFO] ------------------------------------------------------------------------
-[INFO] BUILD SUCCESSFUL
-[INFO] ------------------------------------------------------------------------
-[INFO] Total time: 12 seconds
-[INFO] Finished at: Wed May 07 12:00:06 CDT 2008
-[INFO] Final Memory: 14M/28M
-[INFO] ------------------------------------------------------------------------
-$ </programlisting>
- If there are errors, check whether you have the correct version of Maven installed and that you've correctly updated
- your Maven settings as described above.</para>
- <para>If you've successfully built the examples, there will be a <code>examples/sequencers/target/dna-example-sequencers-basic.dir/</code>
- directory that contains the following:
- <itemizedlist>
- <listitem>
- <para><emphasis role="strong"><code>run.sh</code></emphasis> is the *nix shell script that will run the example.</para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">
- <code>log4j.properties</code>
- </emphasis>
- is the Log4J configuration file.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">
- <code>jackrabbitConfig.xml</code>
- </emphasis>
- is the Jackrabbit configuration file, which is set up to use a transient in-memory repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">
- <code>jackrabbitNodeTypes.cnd</code>
- </emphasis>
- defines the additional JCR node types used by this example.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">
- <code>sample1.mp3</code>
- </emphasis>
- is a sample MP3 audio file you'll use later to upload into the repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">
- <code>caution.gif</code>
- </emphasis>, <emphasis role="strong">
- <code>caution.png</code>
- </emphasis>, and <emphasis role="strong">
- <code>caution.jpg</code>
- </emphasis>
- are images that you'll use later and upload into the repository.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis role="strong">
- <code>lib</code>
- </emphasis>
- subdirectory contains the JARs for all of the JBoss DNA artifacts as well as those for other libraries required
- by JBoss DNA and the example.
- </para>
- </listitem>
- </itemizedlist>
- <note>
- <para>JBoss DNA 0.1 and the examples are currently tested with <ulink url="http://jackrabbit.apache.org/">Apache Jackrabbit</ulink> version 1.3.3.
- This version is stable and used by a number of other projects and applications. However, you should be able to use a newer
- version of Jackrabbit, as long as that version uses the same JCR API. For example, version 1.4.2 was released on March 26, 2008 and
- should be compatible.
- </para>
- <para>Just remember, if the version of Jackrabbit you want to use for these examples is not in the Maven repository,
- you'll have to either add it or add it locally. For more information, see the <ulink url="http://maven.apache.org/">Maven documentation</ulink>.
- </para>
- </note>
- </para>
- </sect1>
- <sect1 id="running">
- <title>Running the example</title>
- <para>This example consists of a client application that sets up an in-memory JCR repository and that allows a user to
- upload files into that repository. The client also sets up the DNA services with two sequencers so that if any of the
- uploaded files are PNG, JPEG, GIF, BMP or other images, DNA will automatically extract the image's metadata (e.g., image
- format, physical size, pixel density, etc.) and store that in the repository. Alternatively, if the uploaded file
- is an MP3 audio file, DNA will extract some of the ID3 metadata (e.g., the author, title, album, year and comment)
- and store that in the repository.</para>
- <para>
- To run the client application, go to the
- <code>examples/sequencers/target/dna-example-sequencers-basic.dir/
- </code>
- directory and type
- <code>./run.sh</code>
- . You should see the command-line client and its menus in your terminal:
- <figure id="xample-sequencer-cli-client">
- <title>Example Client</title>
- <graphic align="center" scale="100" fileref="images/example-sequencer-cli-client.png" />
- </figure>
- From this menu, you can upload a file into the repository, search for media in the repository, print sequencing statistics,
- or quit the application.
- </para>
- <para>
- The first step is to upload one of the example images. If you type 'u' and press return, you'll be prompted to supply the
- path to the file you want to upload. Since the application is running from within the
- <code>examples/sequencers/target/dna-example-sequencers-basic.dir/
- </code>
- directory, you can specify any of the files in that directory without specifying the path:
- <figure id="example-sequencer-upload">
- <title>Uploading an image using the Example Client</title>
- <graphic align="center" scale="100" fileref="images/example-sequencer-upload.png" />
- </figure>
- You can specify any fully-qualified or relative path. The application will notify you if it cannot find the file you
- specified. The example client configures JBoss DNA to sequence and MP3 audio files and image files with one of
- the following extensions (technically, nodes that have names ending in the following):
- <code>jpg</code>
- ,
- <code>jpeg</code>
- ,
- <code>gif</code>
- ,
- <code>bmp</code>
- ,
- <code>pcx</code>
- ,
- <code>png</code>
- ,
- <code>iff</code>
- ,
- <code>ras</code>
- ,
- <code>pbm</code>
- ,
- <code>pgm</code>
- ,
- <code>ppm</code>
- , and
- <code>psd</code>
- . Files with other extensions in the repository path will be ignored. For your convenience, the example provides several
- files that will be sequenced (
- <code>caution.png</code>
- ,
- <code>caution.jpg</code>
- ,
- <code>caution.gif</code>
- , and
- <code>sample1.mp3</code>
- ) and one image that will not be sequenced (
- <code>caution.pict</code>
- ). Feel free to try other files.
- </para>
- <para>
- After you have specified the file you want to upload, the example application asks you where in the repository you'd like to
- place the file. (If you want to use the suggested location, just press
- <code>return</code>
- .) The client application uses the JCR API to upload the file to that location in the repository, creating any nodes (of
- type
- <code>nt:folder</code>
- ) for any directories that don't exist, and creating a node (of type
- <code>nt:file</code>
- ) for the file. And, per the JCR specification, the application creates a
- <code>jcr:content</code>
- node (of type
- <code>nt:resource</code>
- ) under the file node. The file contents are placed on this
- <code>jcr:content</code>
- node in the
- <code>jcr:data</code>
- property. For example, if you specify
- <code>/a/b/caution.png</code>
- , the following structure will be created in the repository:<programlisting>
- /a (nt:folder)
- /b (nt:folder)
- /caution.png (nt:file)
- /jcr:content (nt:resource)
- @jcr:data = {contents of the file}
- @jcr:mimeType = {mime type of the file}
- @jcr:lastModified = {now}
- </programlisting>
- Other kinds of files are treated in a similar way.
- </para>
- <para>
- When the client uploads the file using the JCR API, DNA gets notified of the changes, consults the sequencers to see whether
- any of them are interested in the new or updated content, and if so runs those sequencers. The image sequencer processes image
- files for metadata, and any metadata found is stored under the
- <code>/images</code>
- branch of the repository. The MP3 sequencer processes MP3 audio files for metadata, and any metadata found is stored under the
- <code>/mp3s</code>
- branch of the repository. All of this happens asynchronously, so any DNA activity doesn't impede or slow down the client
- activities.
- </para>
- <para>
- So, after the file is uploaded, you can search the repository for the image metadata using the "s" menu option:
- <figure id="example-sequencer-search">
- <title>Searching for media using the Example Client</title>
- <graphic align="center" scale="100" fileref="images/example-sequencer-search.png" />
- </figure>
- Here are the search results after the <code>sample1.mp3</code> audio file has been uploaded (to the <code>/a/b/sample1.mp3</code> location):
- <figure id="example-sequencer-search-with-mp3">
- <title>Searching for media using the Example Client</title>
- <graphic align="center" scale="100" fileref="images/example-sequencer-search-with-mp3.png" />
- </figure>
- You can also display the sequencing statistics using the "d" menu option:
- <figure id="example-sequencer-statistics">
- <title>Sequencing statistics using the Example Client</title>
- <graphic align="center" scale="100" fileref="images/example-sequencer-statistics.png" />
- </figure>
- These stats show how many nodes were sequenced, and how many nodes were skipped because they didn't apply to the sequencer's
- criteria.
- </para>
- <note>
- <para>
- There will probably be more nodes skipped than sequenced, since there are more
- <code>nt:folder</code>
- and
- <code>nt:resource</code>
- nodes than there are
- <code>nt:file</code>
- nodes with acceptable names.
- </para>
- </note>
- <para>You can repeat this process with other files. Any file that isn't an image or MP3 files (as recognized by the sequencing configurations
- that we'll describe later) will not be sequenced.</para>
- </sect1>
- <sect1 id="downloading_and_running_review">
- <title>Summarizing what we just did</title>
- <para>In this chapter you downloaded and installed the example application and used it to upload files into a
- JCR repository. JBoss DNA automatically sequenced the image and/or MP3 files you uploaded, extracted the metadata from the
- files, and stored that metadata inside the repository. The application allowed you to see this metadata
- and the sequencing statistics.</para>
- <para>This application was very simplistic. In fact, running through the example probably only took you a minute or two.
- So while this application won't win any awards, it does show the basics of what JBoss DNA can do.</para>
- <para>In the <link linkend="using_dna">next chapter</link> we'll venture into the code to get an understanding
- of how JBoss DNA actually works and how you can use it in your own applications.</para>
- </sect1>
- </chapter>
-
- <!-- ====================================================================================================
- Chapter
- ==================================================================================================== -->
-<chapter id="using_dna">
- <title>Using JBoss DNA</title>
- <para>As we've mentioned before, JBoss DNA is able to work with existing JCR repositories. Your client applications
- make changes to the information in those repositories, and JBoss DNA automatically uses its sequencers to extract
- additional information from the uploaded files.</para>
- <note>
- <para>Configuring JBoss DNA sequencers is a bit more manual than is ideal. As you'll see, JBoss DNA uses dependency
- injection to allow a great deal of flexibility in how it can be configured and customized. However, the next release will
- provide a much easier mechanism for configuring not only the sequencer service but also the upcoming federation engine and
- JCR implementation.</para>
- </note>
- <sect1 id="sequencing_service">
- <title>Configuring the Sequencing Service</title>
- <para>
- The JBoss DNA <emphasis>sequencing service</emphasis> is the component that manages the <emphasis>sequencers</emphasis>
- , reacting to changes in JCR repositories and then running the appropriate sequencers.
- This involves processing the changes on a node, determining which (if any) sequencers should be run on that node,
- and for each sequencer constructing the execution environment, calling the sequencer, and saving the information
- generated by the sequencer.</para>
- <para>To set up the sequencing service, an instance is created, and dependent components are injected into
- the object. This includes among other things:
- <itemizedlist>
- <listitem>
- <para>An <emphasis>execution context</emphasis> that defines the context in which the service runs, including
- a factory for JCR sessions given names of the repository and workspace. This factory must be configured,
- and is how JBoss DNA knows about your JCR repositories and how to connect to them. More on this a bit later.</para>
- </listitem>
- <listitem>
- <para>An optional <emphasis>factory for class loaders</emphasis> used to load sequencers. If no factory is supplied,
- the service uses the current thread's context class loader (or if that is null, the class loader that loaded the
- sequencing service class).</para>
- </listitem>
- <listitem>
- <para>An <code>java.util.concurrent.ExecutorService</code> used to execute the sequencing activites. If none
- is supplied, a new single-threaded executor is created by calling <code>Executors.newSingleThreadExecutor()</code>.
- (This can easily be changed by subclassing and overriding the <code>SequencerService.createDefaultExecutorService()</code> method.)</para>
- </listitem>
- <listitem>
- <para>Filters for sequencers and events. By default, all sequencers are considered for "node added", "property added"
- and "property changed" events.</para>
- </listitem>
- </itemizedlist>
- </para>
- <para>As mentioned above, the <code>ExecutionContext</code> provides access to a <code>SessionFactory</code> that is used
- by JBoss DNA to establish sessions to your JCR repositories. Two implementations are available:
- <itemizedlist>
- <listitem>
- <para>The <code>JndiSessionFactory</code> looks up JCR <code>Repository</code> instances in JNDI using
- names that are supplied when creating sessions. This implementation also has methods to set the
- JCR <code>Credentials</code> for a given workspace name.</para>
- </listitem>
- <listitem>
- <para>The <code>SimpleSessionFactory</code> has methods to register the JCR <code>Repository</code> instances
- with names, as well as methods to set the JCR <code>Credentials</code> for a given workspace name.</para>
- </listitem>
- </itemizedlist>
- You can use the <code>SimpleExecutionContext</code> implementation of <code>ExecutionContext</code> and supply
- a <code>SessionFactory</code> instance, or you can provide your own implementation.
- </para>
- <para>Here's an example of how to instantiate and configure the SequencingService:
- <programlisting>
-SimpleSessionFactory sessionFactory = new SimpleSessionFactory();
-sessionFactory.registerRepository("Main Repository", this.repository);
-Credentials credentials = new SimpleCredentials("jsmith", "secret".toCharArray());
-sessionFactory.registerCredentials("Main Repository/Workspace1", credentials);
-ExecutionContext executionContext = new SimpleExecutionContext(sessionFactory);
-
-// Create the sequencing service, passing in the execution context ...
-SequencingService sequencingService = new SequencingService();
-sequencingService.setExecutionContext(executionContext);</programlisting>
- </para>
- <para>After the sequencing service is created and configured, it must be started. The SequencingService
- has an <emphasis>administration object</emphasis> (that is an instance of <code>ServiceAdministrator</code>)
- with <code>start()</code>, <code>pause()</code>, and <code>shutdown()</code> methods. The latter method will
- close the queue for sequencing, but will allow sequencing operations already running to complete normally.
- To wait until all sequencing operations have completed, simply call the <code>awaitTermination</code> method
- and pass it the maximum amount of time you want to wait.</para>
- <para>
- <programlisting>
-sequencingService.getAdministrator().start();</programlisting>
- </para>
- <para>The sequencing service must also be configured with the sequencers that it will use. This is done using the
- <code>addSequencer(SequencerConfig)</code> method and passing a <code>SequencerConfig</code> instance that
- you create. Here's an example:
- <programlisting>
-String name = "Image Sequencer";
-String desc = "Sequences image files to extract the characteristics of the image";
-String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
-String[] classpath = null; // Use the current classpath
-String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png))[*]/jcr:content[@jcr:data] => /images/$1"};
-SequencerConfig imageSequencerConfig = new SequencerConfig(name, desc, classname, classpath, pathExpressions);
-sequencingService.addSequencer(imageSequencerConfig);
-
-name = "Mp3 Sequencer";
-desc = "Sequences mp3 files to extract the id3 tags of the audio file";
-classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
-String[] mp3PathExpressions = {"//(*.mp3)[*]/jcr:content[@jcr:data] => /mp3s/$1"};
-SequencerConfig mp3SequencerConfig = new SequencerConfig(name, desc, classname, classpath, mp3PathExpressions);
-sequencingService.addSequencer(mp3SequencerConfig);</programlisting>
- This is pretty self-explanatory, except for the <code>classpath</code> and <code>pathExpression</code> parameters.
- The classpath parameter defines the classpath that is passed to the class loader factory mentioned above.
- Our sequencer is on the classpath, so we can simply use <code>null</code> here.
- </para>
- <para>The path expression is more complicated. Sequencer path expressions are used by the sequencing service to
- determine whether a particular changed node should be sequenced. The expressions consist of two parts: a selection
- criteria and an output expression. Here's a simple example:
- <programlisting>
-/a/b/c@title => /d/e/f</programlisting>
- Here, the <code>/a/b/c@title</code> is the selection criteria that applies when the <code>/a/b/c</code> node has a <code>title</code> property
- that is added or changed. When the selection criteria matches a change event, the sequencer will be run
- and any generated output will be inserted into the repository described by the output expression. In this example,
- the generated output would be placed at the <code>/d/e/f</code> node.
- </para>
- <note>
- <para>Sequencer path expressions can be fairly complex and may use wildcards, specificy same-name sibling indexes,
- provide optional and choice elements, and may capture parts of the selection criteria for use in the output expression.
- The path expression used in the image sequencer configuration example above shows a more complex example:
- <programlisting>
-//(*.(jpg|jpeg|gif|bmp|pcx|png))[*]/jcr:content[@jcr:data] => /images/$1</programlisting>
- This uses "//" to select any node at any level in the repository whose name ends with "." and one of the extensions (e.g., ".jpg", ".jpeg", etc.)
- and that has a child node named "jcr:content" that has a "jcr:data" property. It also selects the file name
- as the first capture group (the first set of parentheses) for use in the output expression.
- In this example, any sequencer output is placed on a node with that same file name under the "/images" node.
- </para>
- <para></para>
- <para>Other things are possible, too. For example, the name of the repository/workspace (as used by the <code>SessionFactory</code>)
- may be specified at the beginning of the select criteria and/or the output expression. This means it's possible to place
- the sequencer output in a different repository than the node being sequenced.</para>
- <para>For more detail about sequencer path expressions, see the <code>org.jboss.dna.repository.sequencer.SequencerPathExpression</code>
- class and the corresponding <code>org.jboss.dna.repository.sequencer.SequencerPathExpressionTest</code> test case.</para>
- </note>
- <para>After the service is started, it is ready to start reacting to changes in the repository. But it first
- must be wired to the repositories using a listener. This is accomplished using the <code>ObservationService</code>
- described in the <link linkend="observation_service">next section</link>.</para>
- </sect1>
- <sect1 id="observation_service">
- <title>Configuring the Observation Service</title>
- <para>The JBoss DNA <code>ObservationService</code> is responsible for listening to one or more JCR repositories
- and multiplexing the events to its listeners. Unlike JCR events, this framework embeds in the events the
- name of the repository and workspace that can be passed to a <code>SessionFactory</code> to obtain a session
- to the repository in which the change occurred. This simple design makes it very easy for JBoss DNA to
- concurrently work with multiple JCR repositories.</para>
- <para>Configuring an observation service is pretty easy, especially if you reuse the same <code>SessionFactory</code>
- supplied to the sequencing service. Here's an example:
- <programlisting>
-this.observationService = new ObservationService(sessionFactory);
-this.observationService.getAdministrator().start();</programlisting>
- </para>
- <note>
- <para>Both <code>ObservationService</code> and <code>SequencingService</code> implement
- <code>AdministeredService</code>, which has a <code>ServiceAdministrator</code> used to start, pause, and shutdown the
- service. In other words, the lifecycle of the services are managed in the same way.</para>
- </note>
- <para>
- After the observation service is started, listeners can be added. The <code>SequencingService</code> implements the required
- interface, and so it may be registered directly:
- <programlisting>
-observationService.addListener(sequencingService);</programlisting>
- </para>
- <para>Finally, the observation service must be wired to monitor one of your JCR repositories. This is done with
- one of the <code>monitor(...)</code> methods:
- <programlisting>
-int eventTypes = Event.NODE_ADDED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED;
-observationService.monitor("Main Repository/Workspace1", eventTypes);</programlisting>
- </para>
- <para>At this point, the observation service is listening to a JCR repository and forwarding the appropriate events
- to the sequencing service, which will asynchronously process the changes and sequence the information added to or changed in the repository.
- </para>
- </sect1>
- <sect1 id="shutting_down">
- <title>Shutting down JBoss DNA services</title>
- <para>The JBoss DNA services are utilizing resources and threads that must be released before your application is ready to shut down.
- The safe way to do this is to simply obtain the <code>ServiceAdministrator</code> for each service (via the <code>getServiceAdministrator()</code> method)
- and call <code>shutdown()</code>. As previously mentioned, the shutdown method will simply prevent new work from being processed
- and will not wait for existing work to be completed. If you want to wait until the service completes all its work, you must wait
- until the service terminates. Here's an example that shows how this is done:
- <programlisting>
-// Shut down the service and wait until it's all shut down ...
-sequencingService.getAdministrator().shutdown();
-sequencingService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
-
-// Shut down the observation service ...
-observationService.getAdministrator().shutdown();
-observationService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);</programlisting>
- </para>
- <para>At this point, we've covered how to configure and use the JBoss DNA services in your application.
- The next chapter goes back to the <link linkend="downloading_and_running">sample application</link> to show how all these pieces fit together.</para>
- </sect1>
- <sect1 id="example_application_review">
- <title>Reviewing the example application</title>
- <para>Recall that the example application consists of a client application that sets up an in-memory JCR repository and
- that allows a user to upload files into that repository. The client also sets up the DNA services with an image sequencer so
- that if any of the uploaded files are PNG, JPEG, GIF, BMP or other images, DNA will automatically extract the image's
- metadata (e.g., image format, physical size, pixel density, etc.) and store that in the repository. Or, if the client uploads
- MP3 audio files, the title, author, album, year, and comment are extracted from the audio file and stored in the repository.</para>
- <para>
- The example is comprised of 3 classes and 1 interface, located in the
- <code>src/main/java</code>
- directory:
- <programlisting>
- org/jboss/example/dna/sequencers/ConsoleInput.java
- /MediaInfo.java
- /SequencingClient.java
- /UserInterface.java</programlisting>
- </para>
- <para>
- <code>SequencingClient</code>
- is the class that contains the main application.
- <code>MediaInfo</code>
- is a simple Java object that encapsulates metadata about a media file (as generated by the sequencer), and used by the client to
- pass information to the
- <code>UserInterface</code>
- , which is an interface with methods that will be called at runtime to request data from the user.
- <code>ConsoleInput</code>
- is an implementation of this that creates a text user interface, allowing the user to operate the client from the command-line.
- We can easily create a graphical implementation of
- <code>UserInterface</code>
- at a later date. We can also create a mock implementation for testing purposes that simulates a user entering data. This
- allows us to check the behavior of the client automatically using conventional JUnit test cases, as demonstrated by the
- code in the
- <code>src/test/java</code>
- directory:
- <programlisting>
- org/jboss/example/dna/sequencers/SequencingClientTest.java
- /MockUserInterface.java</programlisting>
- </para>
- <para>
- If we look at the
- <code>SequencingClient</code>
- code, there are a handful of methods that encapsulate the various activities.
- </para>
- <note>
- <para>To keep the code shown in this book as readable as possible, some of the comments and error handling
- have been removed.</para>
- </note>
- <para>
- The
- <code>startRepository()</code>
- method starts up an in-memory Jackrabbit JCR repository. The bulk of this method is simply gathering and passing the
- information required by Jackrabbit. Because Jackrabbit's
- <code>TransientRepository</code>
- implementation shuts down after the last session is closed, the application maintains a session to ensure that the
- repository remains open throughout the application's lifetime. And finally, the node type needed by the image sequencer is
- registered with Jackrabbit.
- </para>
- <programlisting>
-public void startRepository() throws Exception {
- if (this.repository == null) {
- try {
-
- // Load the Jackrabbit configuration ...
- File configFile = new File(this.jackrabbitConfigPath);
- String pathToConfig = configFile.getAbsolutePath();
-
- // Find the directory where the Jackrabbit repository data will be stored ...
- File workingDirectory = new File(this.workingDirectory);
- String workingDirectoryPath = workingDirectory.getAbsolutePath();
-
- // Get the Jackrabbit custom node definition (CND) file ...
- URL cndFile = Thread.currentThread().getContextClassLoader().getResource("jackrabbitNodeTypes.cnd");
-
- // Create the Jackrabbit repository instance and establish a session to keep the repository alive ...
- this.repository = new TransientRepository(pathToConfig, workingDirectoryPath);
- if (this.username != null) {
- Credentials credentials = new SimpleCredentials(this.username, this.password);
- this.keepAliveSession = this.repository.login(credentials, this.workspaceName);
- } else {
- this.keepAliveSession = this.repository.login();
- }
-
- try {
- // Register the node types (only valid the first time) ...
- JackrabbitNodeTypeManager mgr = (JackrabbitNodeTypeManager)this.keepAliveSession.getWorkspace().getNodeTypeManager();
- mgr.registerNodeTypes(cndFile.openStream(), JackrabbitNodeTypeManager.TEXT_X_JCR_CND);
- } catch (RepositoryException e) {
- if (!e.getMessage().contains("already exists")) throw e;
- }
-
- } catch (Exception e) {
- this.repository = null;
- this.keepAliveSession = null;
- throw e;
- }
- }
-}</programlisting>
- <para>As you can see, this method really has nothing to do with JBoss DNA, other than setting up a JCR repository that JBoss
- DNA will use.</para>
- <para>
- The
- <code>shutdownRepository()</code>
- method shuts down the Jackrabbit transient repository by closing the "keep-alive session". Again, this method really does
- nothing specifically with JBoss DNA, but is needed to manage the JCR repository that JBoss DNA uses.
- <programlisting>
-public void shutdownRepository() throws Exception {
- if (this.repository != null) {
- try {
- this.keepAliveSession.logout();
- } finally {
- this.repository = null;
- this.keepAliveSession = null;
- }
- }
-}</programlisting>
- </para>
- <para>
- The
- <code>startDnaServices()</code>
- method first starts the JCR repository (if it was not already started), and proceeds to create and configure the
- <code>SequencingService</code>
- as described
- <link linkend="sequencing_service">earlier</link>
- . This involes setting up the
- <code>SessionFactory</code>
- and
- <code>ExecutionContext</code>
- , creating the
- <code>SequencingService</code>
- instance, and configuring the image sequencer. The method then continues by setting up the
- <code>ObservationService</code>
- as described
- <link linkend="observation_service">earlier</link>
- and starting the service.
- <programlisting>
-public void startDnaServices() throws Exception {
- if (this.repository == null) this.startRepository();
- if (this.sequencingService == null) {
-
- SimpleSessionFactory sessionFactory = new SimpleSessionFactory();
- sessionFactory.registerRepository(this.repositoryName, this.repository);
- if (this.username != null) {
- Credentials credentials = new SimpleCredentials(this.username, this.password);
- sessionFactory.registerCredentials(this.repositoryName + "/" + this.workspaceName, credentials);
- }
- this.executionContext = new SimpleExecutionContext(sessionFactory);
-
- // Create the sequencing service, passing in the execution context ...
- this.sequencingService = new SequencingService();
- this.sequencingService.setExecutionContext(executionContext);
-
- // Configure the sequencers.
- String name = "Image Sequencer";
- String desc = "Sequences image files to extract the characteristics of the image";
- String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
- String[] classpath = null; // Use the current classpath
- String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd))[*]/jcr:content[@jcr:data] => /images/$1"};
- SequencerConfig imageSequencerConfig = new SequencerConfig(name, desc, classname, classpath, pathExpressions);
- this.sequencingService.addSequencer(imageSequencerConfig);
-
- // Set up the MP3 sequencer ...
- name = "Mp3 Sequencer";
- desc = "Sequences mp3 files to extract the id3 tags of the audio file";
- classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
- String[] mp3PathExpressions = {"//(*.mp3)[*]/jcr:content[@jcr:data] => /mp3s/$1"};
- SequencerConfig mp3SequencerConfig = new SequencerConfig(name, desc, classname, classpath, mp3PathExpressions);
- this.sequencingService.addSequencer(mp3SequencerConfig);
-
- // Use the DNA observation service to listen to the JCR repository (or multiple ones), and
- // then register the sequencing service as a listener to this observation service...
- this.observationService = new ObservationService(this.executionContext.getSessionFactory());
- this.observationService.getAdministrator().start();
- this.observationService.addListener(this.sequencingService);
- this.observationService.monitor(this.repositoryName + "/" + this.workspaceName, Event.NODE_ADDED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED);
- }
- // Start up the sequencing service ...
- this.sequencingService.getAdministrator().start();
-}</programlisting>
- </para>
- <para>
- The
- <code>shutdownDnaServices()</code>
- method is pretty straightforward: it just calls shutdown on each of the services and waits until they terminate.
- <programlisting>
-public void shutdownDnaServices() throws Exception {
- if (this.sequencingService == null) return;
-
- // Shut down the service and wait until it's all shut down ...
- this.sequencingService.getAdministrator().shutdown();
- this.sequencingService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
-
- // Shut down the observation service ...
- this.observationService.getAdministrator().shutdown();
- this.observationService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
-}</programlisting>
- </para>
- <para>None of the other methods really do anything with JBoss DNA <emphasis>per se</emphasis>. Instead, they merely work with the repository
- using the JCR API.</para>
- <para>
- The <code>main</code> method of the <code>SequencingClient</code> class creates a <code>SequencingClient</code> instance,
- and passes a new <code>ConsoleInput</code> instance:
- <programlisting>
-public static void main( String[] args ) throws Exception {
- SequencingClient client = new SequencingClient();
- client.setRepositoryInformation("repo", "default", "jsmith", "secret".toCharArray());
- client.setUserInterface(new ConsoleInput(client));
-}</programlisting>
- </para>
- <para>If we look at the
- <code>ConsoleInput</code>
- constructor, it starts the repository, the DNA services, and a thread for the user interface. At this point, the constructor
- returns, but the main application continues under the user interface thread. When the user requests to quit,
- the user interface thread also shuts down the DNA services and JCR repository.
- <programlisting>
-public ConsoleInput( SequencerClient client ) {
- try {
- client.startRepository();
- client.startDnaServices();
-
- System.out.println(getMenu());
- Thread eventThread = new Thread(new Runnable() {
- private boolean quit = false;
- public void run() {
- try {
- while (!quit) {
- // Display the prompt and process the requested operation ...
- }
- } finally {
- try {
- // Terminate ...
- client.shutdownDnaServices();
- client.shutdownRepository();
- } catch (Exception err) {
- System.out.println("Error shutting down sequencing service and repository: " + err.getLocalizedMessage());
- err.printStackTrace(System.err);
- }
- }
- }
- });
- eventThread.start();
- } catch (Exception err) {
- System.out.println("Error: " + err.getLocalizedMessage());
- err.printStackTrace(System.err);
- }
-}</programlisting>
- </para>
- <para>At this point, we've reviewed all of the interesting code in the example application. However, feel free
- to play with the application, trying different things.
- </para>
- </sect1>
- <sect1 id="using_dna_review">
- <title>Summarizing what we just did</title>
- <para>In this chapter we covered the different JBoss DNA components and how they can be used in your application.
- Specifically, we described how the <code>SequencingService</code> and <code>ObservationService</code> can
- be configured and used. And we ended the chapter by reviewing the example application, which not only uses
- JBoss DNA, but also the repository via the JCR API.
- </para>
- </sect1>
-</chapter>
-
-<!-- ====================================================================================================
- Chapter
- ==================================================================================================== -->
-<chapter id="custom_sequencers">
- <title>Creating custom sequencers</title>
- <para>The current release of JBoss DNA comes with two sequencers: one that extracts metadata from a variety of image file formats,
- and another that extracts some of the ID3 metadata from MP3 audio files. However, it's very easy to create your own
- sequencers and to then configure JBoss DNA to use them in your own application.
- </para>
- <para>
- Creating a custom sequencer involves the following steps:
- <itemizedlist>
- <listitem>
- <para>Create a Maven 2 project for your sequencer;</para>
- </listitem>
- <listitem>
- <para>Implement the <code>org.jboss.dna.graph.sequencers.StreamSequencer</code> interface with your own implementation, and create unit tests to verify
- the functionality and expected behavior;</para>
- </listitem>
- <listitem>
- <para>Add the sequencer configuration to the JBoss DNA <code>SequencingService</code> in your application
- as described in the <link linkend="using_dna">previous chapter</link>; and</para>
- </listitem>
- <listitem>
- <para>Deploy the JAR file with your implementation (as well as any dependencies), and make them available to JBoss DNA
- in your application.</para>
- </listitem>
- </itemizedlist>
- It's that simple.
- </para>
- <sect1 id="custom_sequencer_project">
- <title>Creating the Maven 2 project</title>
- <para>The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
- Maven 2 automates a lot of the work, and since you're already <link linkend="downloading_and_running">set up to use Maven</link>,
- using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
- have to get the required libraries and manage the compiling and building process yourself.</para>
- <note>
- <para>JBoss DNA may provide in the future a Maven archetype for creating sequencer projects. If you'd find this useful
- and would like to help create it, please <link linkend="preface">join the community</link>.</para>
- </note>
- <note>
- <para>The <code>dna-sequencer-images</code> project is a small, self-contained sequencer implementation that
- has only the minimal dependencies. Starting with this project's source and modifying it to suit your needs may be the easiest way to get started.
- See the subversion repository: <ulink url="http://anonsvn.jboss.org/repos/dna/trunk/sequencers/dna-sequencer-images/">http://anonsvn.jboss.org/repos/dna/trunk/sequencers/dna-sequencer-images/</ulink>
- </para>
- </note>
- <para>You can create your Maven project any way you'd like. For examples, see the <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
- Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:
- <programlisting>
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-common</artifactId>
- <version>0.1</version>
-</dependency>
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-graph</artifactId>
- <version>0.1</version>
-</dependency>
-<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
-</dependency>
-</programlisting>
- These are minimum dependencies required for compiling a sequencer. Of course, you'll have to add
- other dependencies that your sequencer needs.</para>
- <para>As for testing, you probably will want to add more dependencies, such as those listed here:
-<programlisting>
-<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.4</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>org.hamcrest</groupId>
- <artifactId>hamcrest-library</artifactId>
- <version>1.1</version>
- <scope>test</scope>
-</dependency>
-<!-- Logging with Log4J -->
-<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.3</version>
- <scope>test</scope>
-</dependency>
-<dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <scope>test</scope>
-</dependency>
-</programlisting>
- Testing JBoss DNA sequencers does not require a JCR repository or the JBoss DNA services. (For more detail,
- see the <link linkend="testing_custom_sequencers">testing section</link>.) However, if you want to do
- integration testing with a JCR repository and the JBoss DNA services, you'll need additional dependencies for these libraries.
-<programlisting>
-<dependency>
- <groupId>org.jboss.dna</groupId>
- <artifactId>dna-repository</artifactId>
- <version>0.1</version>
- <scope>test</scope>
-</dependency>
-<!-- Java Content Repository API -->
-<dependency>
- <groupId>javax.jcr</groupId>
- <artifactId>jcr</artifactId>
- <version>1.0.1</version>
- <scope>test</scope>
-</dependency>
-<!-- Apache Jackrabbit (JCR Implementation) -->
-<dependency>
- <groupId>org.apache.jackrabbit</groupId>
- <artifactId>jackrabbit-api</artifactId>
- <version>1.3.3</version>
- <scope>test</scope>
- <!-- Exclude these since they are included in JDK 1.5 -->
- <exclusions>
- <exclusion>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- </exclusion>
- <exclusion>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- </exclusion>
- </exclusions>
-</dependency>
-<dependency>
- <groupId>org.apache.jackrabbit</groupId>
- <artifactId>jackrabbit-core</artifactId>
- <version>1.3.3</version>
- <scope>test</scope>
- <!-- Exclude these since they are included in JDK 1.5 -->
- <exclusions>
- <exclusion>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- </exclusion>
- <exclusion>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- </exclusion>
- </exclusions>
-</dependency>
-</programlisting>
- </para>
- <para>At this point, your project should be set up correctly, and you're ready to move on to
- <link linkend="custom_sequencer_implementation">writing the Java implementation</link> for your sequencer.
- </para>
- </sect1>
- <sect1 id="custom_sequencer_implementation">
- <title>Implementing the StreamSequencer interface</title>
- <para>After creating the project and setting up the dependencies, the next step is to create a Java class that implements
- the <code>org.jboss.dna.graph.sequencers.StreamSequencer</code> interface. This interface is very straightforward
- and involves a single method:
- <programlisting>
-public interface StreamSequencer {
-
- /**
- * Sequence the data found in the supplied stream, placing the output
- * information into the supplied map.
- *
- * @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 cancelled.
- */
- void sequence( InputStream stream, SequencerOutput output,
- ProgressMonitor progressMonitor );</programlisting>
- </para>
- <para>The job of a stream sequencer is to process the data in the supplied stream, and place into the <code>SequencerOutput</code>
- any information that is to go into the JCR repository. JBoss DNA figures out when your sequencer should be called
- (of course, using the sequencing configuration you'll add in a bit), and then makes sure the generated information
- is saved in the correct place in the repository.
- </para>
- <para>The <code>SequencerOutput</code> class is fairly easy to use. There are basically two methods you need to call.
- One method sets the property values, while the other sets references to other nodes in the repository. Use these
- methods to describe the properties of the nodes you want to create, using relative paths for the nodes and
- valid JCR property names for properties and references. JBoss DNA will ensure that nodes are created or updated
- whenever they're needed.
- <programlisting>
-public interface SequencerOutput {
-
- /**
- * Set the supplied property on the supplied node. The allowable
- * values are any of the following:
- * - primitives (which will be autoboxed)
- * - String instances
- * - String arrays
- * - byte arrays
- * - InputStream instances
- * - Calendar instances
- *
- * @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 );
-}</programlisting>
- </para>
- <para>JBoss DNA will create nodes of type <code>nt:unstructured</code> unless you specify the value for the
- <code>jcr:primaryType</code> property. You can also specify the values for the <code>jcr:mixinTypes</code> property
- if you want to add mixins to any node.
- </para>
- <para>For a complete example of a sequencer, let's look at the <code>org.jboss.dna.sequencers.image.ImageMetadataSequencer</code> implementation:
- <programlisting>
-public class ImageMetadataSequencer implements StreamSequencer {
-
- public static final String METADATA_NODE = "image:metadata";
- public static final String IMAGE_PRIMARY_TYPE = "jcr:primaryType";
- public static final String IMAGE_MIXINS = "jcr:mixinTypes";
- public static final String IMAGE_MIME_TYPE = "jcr:mimeType";
- public static final String IMAGE_ENCODING = "jcr:encoding";
- public static final String IMAGE_FORMAT_NAME = "image:formatName";
- public static final String IMAGE_WIDTH = "image:width";
- public static final String IMAGE_HEIGHT = "image:height";
- public static final String IMAGE_BITS_PER_PIXEL = "image:bitsPerPixel";
- public static final String IMAGE_PROGRESSIVE = "image:progressive";
- public static final String IMAGE_NUMBER_OF_IMAGES = "image:numberOfImages";
- public static final String IMAGE_PHYSICAL_WIDTH_DPI = "image:physicalWidthDpi";
- public static final String IMAGE_PHYSICAL_HEIGHT_DPI = "image:physicalHeightDpi";
- public static final String IMAGE_PHYSICAL_WIDTH_INCHES = "image:physicalWidthInches";
- public static final String IMAGE_PHYSICAL_HEIGHT_INCHES = "image:physicalHeightInches";
-
- /**
- * {@inheritDoc}
- */
- public void sequence( InputStream stream, SequencerOutput output,
- ProgressMonitor progressMonitor ) {
- progressMonitor.beginTask(10, ImageSequencerI18n.sequencerTaskName);
-
- ImageMetadata metadata = new ImageMetadata();
- metadata.setInput(stream);
- metadata.setDetermineImageNumber(true);
- metadata.setCollectComments(true);
-
- // Process the image stream and extract the metadata ...
- if (!metadata.check()) {
- metadata = null;
- }
- progressMonitor.worked(5);
- if (progressMonitor.isCancelled()) return;
-
- // Generate the output graph if we found useful metadata ...
- if (metadata != null) {
- // Place the image metadata into the output map ...
- output.setProperty(METADATA_NODE, IMAGE_PRIMARY_TYPE, "image:metadata");
- // output.psetProperty(METADATA_NODE, IMAGE_MIXINS, "");
- output.setProperty(METADATA_NODE, IMAGE_MIME_TYPE, metadata.getMimeType());
- // output.setProperty(METADATA_NODE, IMAGE_ENCODING, "");
- output.setProperty(METADATA_NODE, IMAGE_FORMAT_NAME, metadata.getFormatName());
- output.setProperty(METADATA_NODE, IMAGE_WIDTH, metadata.getWidth());
- output.setProperty(METADATA_NODE, IMAGE_HEIGHT, metadata.getHeight());
- output.setProperty(METADATA_NODE, IMAGE_BITS_PER_PIXEL, metadata.getBitsPerPixel());
- output.setProperty(METADATA_NODE, IMAGE_PROGRESSIVE, metadata.isProgressive());
- output.setProperty(METADATA_NODE, IMAGE_NUMBER_OF_IMAGES, metadata.getNumberOfImages());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_DPI, metadata.getPhysicalWidthDpi());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_DPI, metadata.getPhysicalHeightDpi());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_INCHES, metadata.getPhysicalWidthInch());
- output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_INCHES, metadata.getPhysicalHeightInch());
- }
-
- progressMonitor.done();
- }
-}</programlisting>
- </para>
- <para>
- Notice how the image metadata is extracted and the output graph is generated. A single node is created with the name <code>image:metadata</code>
- and with the <code>image:metadata</code> node type. No mixins are defined for the node, but several properties are set on the node
- using the values obtained from the image metadata. After this method returns, the constructed graph will be saved to the repository
- in all of the places defined by its configuration. (This is why only relative paths are used in the sequencer.)
- </para>
- <para>Also note how the progress monitor is used. Reporting progress through the supplied <code>ProgressMonitor</code> is very easy, and it ensures that JBoss DNA
- can accurately monitor and report the status of sequencing activities to the users. At the beginning of the operation, call
- <code>beginTask(...)</code> 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 incremental amount of work with the <code>worked(double)</code> method, or
- by creating a subtask with the <code>createSubtask(double)</code> method and reporting work against that subtask
- monitor.
- </para>
- <para>Your method should periodically use the ProgressMonitor's <code>isCancelled()</code> method to check whether the operation has been
- 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.
- </para>
- <para>
- Finally, when your sequencing operation is completed, it should call <code>done()</code> on the progress monitor.
- </para>
- </sect1>
- <sect1 id="testing_custom_sequencers">
- <title>Testing custom sequencers</title>
- <para>The sequencing framework was designed to make testing sequencers much easier. In particular, the
- <code>StreamSequencer</code> interface does not make use of the JCR API. So instead of requiring a fully-configured
- JCR repository and JBoss DNA system, unit tests for a sequencer can focus on testing that the content is
- processed correctly and the desired output graph is generated.</para>
- <note>
- <para>For a complete example of a sequencer unit test, see the <code>ImageMetadataSequencerTest</code> unit test
- in the <code>org.jboss.dna.sequencer.images</code> package of the <code>dna-sequencers-image</code> project.
- </para>
- </note>
- <para>The following code fragment shows one way of testing a sequencer, using JUnit 4.4 assertions and
- some of the classes made available by JBoss DNA. Of course,
- this example code does not do any error handling and does not make all the assertions a real test would.
- <programlisting>
-Sequencer sequencer = new ImageMetadataSequencer();
-MockSequencerOutput output = new MockSequencerOutput();
-ProgressMonitor progress = new SimpleProgressMonitor("Test activity");
-InputStream stream = null;
-try {
- stream = this.getClass().getClassLoader().getResource("caution.gif").openStream();
- sequencer.sequence(stream,output,progress); // writes to 'output'
- assertThat(output.getPropertyValues("image:metadata", "jcr:primaryType"),
- is(new Object[] {"image:metadata"}));
- assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"),
- is(new Object[] {"image/gif"}));
- // ... make more assertions here
- assertThat(output.hasReferences(), is(false));
-} finally {
- stream.close();
-}</programlisting>
- </para>
- <para>It's also useful to test that a sequencer produces no output for something it should not understand:
- <programlisting>
-Sequencer sequencer = new ImageMetadataSequencer();
-MockSequencerOutput output = new MockSequencerOutput();
-ProgressMonitor progress = new SimpleProgressMonitor("Test activity");
-InputStream stream = null;
-try {
- stream = this.getClass().getClassLoader().getResource("caution.pict").openStream();
- sequencer.sequence(stream,output,progress); // writes to 'output'
- assertThat(output.hasProperties(), is(false));
- assertThat(output.hasReferences(), is(false));
-} finally {
- stream.close();
-}</programlisting>
- </para>
- <para>These are just two simple tests that show ways of testing a sequencer. Some tests may get quite involved,
- especially if a lot of output data is produced.
- </para>
- <para>It may also be useful to create some integration tests
- that <link linkend="using_dna">configure JBoss DNA</link> to use a custom sequencer, and to then upload
- content using the JCR API, verifying that the custom sequencer did run. However, remember that JBoss DNA
- runs sequencers asynchronously in the background, and you must sychronize your tests to ensure that the
- sequencers have a chance to run before checking the results. (One way of doing this (although, granted, not always reliable) is to wait for a second
- after uploading your content, shutdown the <code>SequencingService</code> and await its termination,
- and then check that the sequencer output has been saved to the JCR repository. For an example of this technique,
- see the <code>SequencingClientTest</code> unit test in the example application.)
- </para>
- </sect1>
- <sect1 id="deploying_custom_sequencers">
- <title>Deploying custom sequencers</title>
- <para>The first step of deploying a sequencer consists of adding/changing the sequencer configuration (e.g., <code>SequencerConfig</code>)
- in the <code>SequencingService</code>. This was covered in the <link linkend="sequencing_service">previous chapter</link>.
- </para>
- <para>
- The second step is to make the sequencer implementation available to JBoss DNA. At this time, the JAR containing
- your new sequencer, as well as any JARs that your sequencer depends on, should be placed on your application classpath.</para>
- <note>
- <para>A future goal of JBoss DNA is to allow sequencers, connectors, and other extensions to be easily deployed into
- a runtime repository. This process will not only be much simpler, but it will also provide JBoss DNA
- with the information necessary to update configurations and create the appropriate class loaders for each extension.
- Having separate class loaders for each extension helps prevent the pollution of the common classpath,
- facilitates an isolated runtime environment to eliminate any dependency conflicts, and may potentially
- enable hot redeployment of newer extension versions.
- </para>
- </note>
- </sect1>
-</chapter>
-
-<!-- ====================================================================================================
- Chapter
- ==================================================================================================== -->
-<chapter id="future_directions">
- <title>Looking to the future</title>
- <para>What's next for JBoss DNA? Well, the sequencing system is just the beginning. With this release, the sequencing system
- is stable enough so that more <link linkend="sequencers">sequencers</link> can be developed and used within your own applications.
- If you're interested in getting involved with the JBoss DNA project, consider picking up one of the sequencers on our
- <ulink url="http://jira.jboss.org/jira/browse/DNA?report=com.atlassian.jira.plugin.sy...">roadmap</ulink>.
- Or, check out <ulink url="http://jira.jboss.org/jira/secure/IssueNavigator.jspa?reset=true&mode...">JIRA</ulink>
- for the list of sequencers we've thought of. If you think of one that's not there, please add it to JIRA!
- </para>
- <para>
- The next release will focus on creating the <link linkend="federation">federation engine</link> and connectors
- for several popular and ubiquitous systems. The 0.2 release will likely only federate information in a read-only manner,
- but updates will soon follow. Also, during the early part of the next release, the JBoss DNA project will switch to use JDK 6.
- Java 5 is being end-of-lifed, so we want to move to a supported JDK. However, a number of JBoss projects and products continue to
- require Java 5, so our next release will most likely use JDK 6 with Java 5 compatibility.</para>
- <para>
- Other components on our roadmap include a web user interface, a REST-ful server, and a view system that allows domain-specific
- views of information in the repository. These components are farther out on our roadmap, and at this time have not been
- targeted to a particular release. If any of these are of interest to you, please <link linkend="preface">get involved</link> in the community.
- </para>
-</chapter>
-</book>
\ No newline at end of file
Deleted: trunk/dna-graph/src/test/resources/plugin.xml
===================================================================
--- trunk/dna-graph/src/test/resources/plugin.xml 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/dna-graph/src/test/resources/plugin.xml 2008-10-29 18:23:01 UTC (rev 598)
@@ -1,91 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?eclipse version="3.0"?>
-<!-- (c) 2007 Varsity Gateway LLC. All rights reserved. -->
-<plugin
- id="com.metamatrix.metamodels.transformation"
- name="%pluginName"
- version="5.5.1"
- provider-name="%providerName"
- class="com.metamatrix.metamodels.transformation.TransformationPlugin">
-
- <runtime>
- <library name="metamodelsTransformation.jar">
- <export name="*"/>
- </library>
- </runtime>
- <requires>
- <import plugin="org.eclipse.emf.mapping" export="true"/>
- <import plugin="org.eclipse.emf.ecore" export="true"/>
- <import plugin="org.eclipse.emf.edit" export="true"/>
- <import plugin="org.eclipse.emf.ecore.edit" export="true"/>
- <import plugin="org.eclipse.core.runtime" export="true"/>
- <import plugin="com.metamatrix.core" export="true"/>
- <import plugin="com.metamatrix.metamodels.core" export="true"/>
- </requires>
-
-
-<!--
- Each extension below represents a single metamodel. Each metmodel is
- registered using under the specified <uri> value which must be the same
- eNS_URI value defined in the EPackage class for that metamodel.
- -->
- <extension
- id="transformation"
- name="%metamodelName"
- point="com.metamatrix.modeler.core.metamodel">
- <uri>
- http://www.metamatrix.com/metamodels/Transformation
- </uri>
- <alternateUri>
- mtkplugin:///com.metamatrix.metamodels.Transformation
- </alternateUri>
- <packageClass
- name="com.metamatrix.metamodels.transformation.TransformationPackage">
- </packageClass>
- <adapterClass
- name="com.metamatrix.metamodels.transformation.provider.TransformationItemProviderAdapterFactory">
- </adapterClass>
- <properties
- createAsPhysical="false"
- requiresProxies="false"
- participatoryOnly="true"
- createAsVirtual="false"
- supportsDiagrams="false"
- supportsExtension="true">
- </properties>
- </extension>
- <extension
- point="org.eclipse.emf.ecore.generated_package">
- <package
- uri="http://www.metamatrix.com/metamodels/Transformation"
- class="com.metamatrix.metamodels.transformation.TransformationPackage">
- </package>
- </extension>
-
- <extension
- id="mapping"
- name="%mappingMetamodelName"
- point="com.metamatrix.modeler.core.metamodel">
- <uri>
- http://www.eclipse.org/emf/2002/Mapping
- </uri>
- <alternateUri>
- mtkplugin:///www.eclipse.org/emf/2002/Mapping
- </alternateUri>
- <packageClass
- name="org.eclipse.emf.mapping.MappingPackage">
- </packageClass>
- <adapterClass
- name="org.eclipse.emf.mapping.provider.MappingItemProviderAdapterFactory">
- </adapterClass>
- <properties
- createAsPhysical="false"
- requiresProxies="false"
- participatoryOnly="true"
- createAsVirtual="false"
- supportsDiagrams="false"
- supportsExtension="false">
- </properties>
- </extension>
-
-</plugin>
Property changes on: trunk/extensions/dna-sequencer-xml
___________________________________________________________________
Name: svn:ignore
+ target
Added: trunk/extensions/dna-sequencer-xml/.classpath
===================================================================
--- trunk/extensions/dna-sequencer-xml/.classpath (rev 0)
+++ trunk/extensions/dna-sequencer-xml/.classpath 2008-10-29 18:23:01 UTC (rev 598)
@@ -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/extensions/dna-sequencer-xml/.project
===================================================================
--- trunk/extensions/dna-sequencer-xml/.project (rev 0)
+++ trunk/extensions/dna-sequencer-xml/.project 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>dna-sequencer-xml</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/extensions/dna-sequencer-xml/pom.xml
===================================================================
--- trunk/extensions/dna-sequencer-xml/pom.xml (rev 0)
+++ trunk/extensions/dna-sequencer-xml/pom.xml 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,92 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna</artifactId>
+ <version>0.3-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+ <!-- The groupId and version values are inherited from parent -->
+ <artifactId>dna-sequencer-xml</artifactId>
+ <packaging>jar</packaging>
+ <name>JBoss DNA XML Sequencer</name>
+ <description>JBoss DNA Sequencer that processes XML files</description>
+ <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>
+ <!--
+ Common
+ -->
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>${pom.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>${pom.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ Testing (note the scope)
+ -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ </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>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <!--
+ Java Concurrency in Practice annotations
+ -->
+ <dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ </dependency>
+ </dependencies>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
\ No newline at end of file
Added: trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/DnaDtdLexicon.java
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/DnaDtdLexicon.java (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/DnaDtdLexicon.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,42 @@
+/*
+ * 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.sequencer.xml;
+
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.basic.BasicName;
+
+/**
+ * @author Randall Hauch
+ */
+public class DnaDtdLexicon {
+
+ public static class Namespace {
+ public static final String URI = "http://www.jboss.org/dna/dtd/1.0";
+ public static final String PREFIX = "dnadtd";
+ }
+
+ public static final Name NAME = new BasicName(Namespace.URI, "name");
+ public static final Name PUBLIC_ID = new BasicName(Namespace.URI, "publicId");
+ public static final Name SYSTEM_ID = new BasicName(Namespace.URI, "systemId");
+ public static final Name VALUE = new BasicName(Namespace.URI, "value");
+ public static final Name ENTITY = new BasicName(Namespace.URI, "entity");
+}
Added: trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/DnaXmlLexicon.java
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/DnaXmlLexicon.java (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/DnaXmlLexicon.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,46 @@
+/*
+ * 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.sequencer.xml;
+
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.basic.BasicName;
+
+/**
+ * @author Randall Hauch
+ */
+public class DnaXmlLexicon {
+
+ public static class Namespace {
+ public static final String URI = "http://www.jboss.org/dna/xml/1.0";
+ public static final String PREFIX = "dnaxml";
+ }
+
+ public static final Name CDATA = new BasicName(Namespace.URI, "cData");
+ public static final Name CDATA_CONTENT = new BasicName(Namespace.URI, "cDataContent");
+ public static final Name COMMENT = new BasicName(Namespace.URI, "comment");
+ public static final Name COMMENT_CONTENT = new BasicName(Namespace.URI, "commentContent");
+ public static final Name DOCUMENT = new BasicName(Namespace.URI, "document");
+ public static final Name ELEMENT_CONTENT = new BasicName(Namespace.URI, "elementContent");
+ public static final Name PROCESSING_INSTRUCTION = new BasicName(Namespace.URI, "processingInstruction");
+ public static final Name PROCESSING_INSTRUCTION_CONTENT = new BasicName(Namespace.URI, "processingInstructionContent");
+ public static final Name TARGET = new BasicName(Namespace.URI, "target");
+}
Added: trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencer.java (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencer.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,702 @@
+/*
+ * 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.sequencer.xml;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.NameFactory;
+import org.jboss.dna.graph.properties.NamespaceRegistry;
+import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.sequencers.SequencerContext;
+import org.jboss.dna.graph.sequencers.SequencerOutput;
+import org.jboss.dna.graph.sequencers.StreamSequencer;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.DefaultHandler2;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * @author John Verhaeg
+ */
+public class XmlSequencer implements StreamSequencer {
+
+ private static final String DEFAULT_PRIMARY_TYPE = "nt:unstructured";
+ private static final String DECL_HANDLER_FEATURE = "http://xml.org/sax/properties/declaration-handler";
+ private static final String ENTITY_RESOLVER_2_FEATURE = "http://xml.org/sax/features/use-entity-resolver2";
+ private static final String LEXICAL_HANDLER_FEATURE = "http://xml.org/sax/properties/lexical-handler";
+ private static final String RESOLVE_DTD_URIS_FEATURE = "http://xml.org/sax/features/resolve-dtd-uris";
+ private static final String LOAD_EXTERNAL_DTDS_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.sequencers.StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext,
+ * ProgressMonitor)
+ */
+ public void sequence( InputStream stream,
+ SequencerOutput output,
+ SequencerContext context,
+ ProgressMonitor monitor ) {
+ monitor.beginTask(100.0, XmlSequencerI18n.sequencingXmlDocument);
+ XMLReader reader;
+ try {
+ reader = XMLReaderFactory.createXMLReader();
+ Handler handler = new Handler(output, context, monitor);
+ reader.setContentHandler(handler);
+ reader.setErrorHandler(handler);
+ // Ensure handler acting as entity resolver 2
+ reader.setProperty(DECL_HANDLER_FEATURE, handler);
+ // Ensure handler acting as lexical handler
+ reader.setProperty(LEXICAL_HANDLER_FEATURE, handler);
+ // Ensure handler acting as entity resolver 2
+ setFeature(reader, ENTITY_RESOLVER_2_FEATURE, true);
+ // Prevent loading of external DTDs
+ setFeature(reader, LOAD_EXTERNAL_DTDS_FEATURE, false);
+ // Prevent the resolving of DTD entities into fully-qualified URIS
+ setFeature(reader, RESOLVE_DTD_URIS_FEATURE, false);
+ // Parse XML document
+ reader.parse(new InputSource(stream));
+ } catch (Exception error) {
+ context.getLogger(getClass()).error(error, XmlSequencerI18n.fatalErrorSequencingXmlDocument, error);
+ monitor.getProblems().addError(error, XmlSequencerI18n.fatalErrorSequencingXmlDocument, error);
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * Sets the reader's named feature to the supplied value, only if the feature is not already set to that value. This method
+ * does nothing if the feature is not known to the reader.
+ *
+ * @param reader the reader; may not be null
+ * @param featureName the name of the feature; may not be null
+ * @param value the value for the feature
+ */
+ private void setFeature( XMLReader reader,
+ String featureName,
+ boolean value ) {
+ try {
+ if (reader.getFeature(featureName) != value) {
+ reader.setFeature(featureName, value);
+ }
+ } catch (SAXNotRecognizedException meansFeatureNotRecognized) {
+ } catch (SAXNotSupportedException meansFeatureNotSupported) {
+ }
+ }
+
+ private final class Handler extends DefaultHandler2 {
+
+ private final SequencerOutput output;
+ private final SequencerContext context;
+ private final ProgressMonitor monitor;
+
+ private double progress;
+
+ private Path path; // The DNA path of the node representing the current XML element
+
+ // Cached instances of the name factory and commonly referenced names
+ private final NameFactory nameFactory;
+ private Name defaultPrimaryType;
+
+ // Recursive map used to track the number of occurrences of names for elements under a particular path
+ private Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name, List<IndexedName>>();
+
+ // The stack of recursive maps being processed, with the head entry being the map for the current path
+ private final LinkedList<Map<Name, List<IndexedName>>> nameToIndexedNamesMapStack = new LinkedList<Map<Name, List<IndexedName>>>();
+
+ // The stack of XML namespace in scope, with the head entry being namespace of the closest ancestor element declaring a
+ // namespace.
+ private final LinkedList<String> nsStack = new LinkedList<String>();
+
+ // Builder used to concatenate concurrent lines of CDATA into a single value.
+ private StringBuilder cDataBuilder;
+
+ // Builder used to concatenate concurrent lines of element content and entity evaluations into a single value.
+ private StringBuilder contentBuilder;
+
+ // The entity being processed
+ private String entity;
+
+ Handler( SequencerOutput output,
+ SequencerContext context,
+ ProgressMonitor monitor ) {
+ assert output != null;
+ assert monitor != null;
+ assert context != null;
+ this.output = output;
+ this.context = context;
+ this.monitor = monitor;
+ // Initialize path to a an empty path relative to the SequencerOutput's target path.
+ path = context.getValueFactories().getPathFactory().createRelativePath();
+ // Cache name factory since it is frequently used
+ nameFactory = context.getValueFactories().getNameFactory();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#attributeDecl(java.lang.String, java.lang.String, java.lang.String,
+ * java.lang.String, java.lang.String)
+ */
+ @Override
+ public void attributeDecl( String name,
+ String name2,
+ String type,
+ String mode,
+ String value ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
+ */
+ @Override
+ public void characters( char[] ch,
+ int start,
+ int length ) throws SAXException {
+ stopIfCancelled();
+ String content = String.valueOf(ch, start, length);
+ // Check if data should be appended to previously parsed CDATA
+ if (cDataBuilder == null) {
+ // If content is for an entity, replace with entity reference
+ if (entity != null) {
+ content = '&' + entity + ';';
+ }
+ // Check if first line of content
+ if (contentBuilder == null) {
+ contentBuilder = new StringBuilder(content);
+ } else {
+ // Append additional lines or entity evaluations to previous content, separated by a space
+ if (entity == null) {
+ contentBuilder.append(' ');
+ }
+ contentBuilder.append(content);
+ // Text within builder will be output when another element or CDATA is encountered
+ }
+ } else {
+ cDataBuilder.append(ch, start, length);
+ // Text within builder will be output at the end of CDATA
+ }
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#comment(char[], int, int)
+ */
+ @Override
+ public void comment( char[] ch,
+ int start,
+ int length ) throws SAXException {
+ stopIfCancelled();
+ // Output separate nodes for each comment since multiple are allowed
+ startElement(DnaXmlLexicon.COMMENT);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.COMMENT);
+ output.setProperty(path, DnaXmlLexicon.COMMENT_CONTENT, String.valueOf(ch, start, length));
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#elementDecl(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void elementDecl( String name,
+ String model ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#endCDATA()
+ */
+ @Override
+ public void endCDATA() throws SAXException {
+ stopIfCancelled();
+ // Output CDATA built in characters() method
+ output.setProperty(path, DnaXmlLexicon.CDATA_CONTENT, cDataBuilder.toString());
+ endElement();
+ // Null-out builder to free memory
+ cDataBuilder = null;
+ updateProgress();
+ }
+
+ private void endContent() {
+ if (contentBuilder != null) {
+ // Normalize content
+ String content = StringUtil.normalize(contentBuilder.toString());
+ // Null-out builder to setup for subsequent content.
+ // Must be done before call to startElement below to prevent infinite loop.
+ contentBuilder = null;
+ // Skip if nothing in content but whitespace
+ if (content.length() > 0) {
+ // Create separate node for each content entry since entries can be interspersed amongst child elements
+ startElement(DnaXmlLexicon.ELEMENT_CONTENT);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.ELEMENT_CONTENT);
+ output.setProperty(path, DnaXmlLexicon.ELEMENT_CONTENT, content);
+ endElement();
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#endDocument()
+ */
+ @Override
+ public void endDocument() throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#endDTD()
+ */
+ @Override
+ public void endDTD() throws SAXException {
+ stopIfCancelled();
+ }
+
+ private void endElement() {
+ // Recover parent's path, namespace, and indexedName map, clearing the ended element's map to free memory
+ path = path.getParent();
+ nameToIndexedNamesMap.clear();
+ nameToIndexedNamesMap = nameToIndexedNamesMapStack.removeFirst();
+ nsStack.removeFirst();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void endElement( String uri,
+ String localName,
+ String name ) throws SAXException {
+ stopIfCancelled();
+ // Check if content still needs to be output
+ endContent();
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#endEntity(java.lang.String)
+ */
+ @Override
+ public void endEntity( String name ) throws SAXException {
+ stopIfCancelled();
+ entity = null;
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void error( SAXParseException error ) {
+ context.getLogger(XmlSequencer.class).error(error, XmlSequencerI18n.errorSequencingXmlDocument, error);
+ monitor.getProblems().addError(error, XmlSequencerI18n.errorSequencingXmlDocument, error);
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#externalEntityDecl(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void externalEntityDecl( String name,
+ String publicId,
+ String systemId ) throws SAXException {
+ stopIfCancelled();
+ // Add "synthetic" entity container to path to help prevent name collisions with XML elements
+ Name entityName = DnaDtdLexicon.ENTITY;
+ startElement(entityName);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, entityName);
+ output.setProperty(path, nameFactory.create(DnaDtdLexicon.NAME), name);
+ output.setProperty(path, nameFactory.create(DnaDtdLexicon.PUBLIC_ID), publicId);
+ output.setProperty(path, nameFactory.create(DnaDtdLexicon.SYSTEM_ID), systemId);
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void fatalError( SAXParseException error ) {
+ context.getLogger(XmlSequencer.class).error(error, XmlSequencerI18n.fatalErrorSequencingXmlDocument, error);
+ monitor.getProblems().addError(error, XmlSequencerI18n.fatalErrorSequencingXmlDocument, error);
+ }
+
+ private Name getDefaultPrimaryType() {
+ if (defaultPrimaryType == null) {
+ defaultPrimaryType = nameFactory.create(DEFAULT_PRIMARY_TYPE);
+ }
+ return defaultPrimaryType;
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#ignorableWhitespace(char[], int, int)
+ */
+ @Override
+ public void ignorableWhitespace( char[] ch,
+ int start,
+ int length ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#internalEntityDecl(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void internalEntityDecl( String name,
+ String value ) throws SAXException {
+ stopIfCancelled();
+ // Add "synthetic" entity container to path to help prevent name collisions with XML elements
+ Name entityName = DnaDtdLexicon.ENTITY;
+ startElement(entityName);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, entityName);
+ output.setProperty(path, DnaDtdLexicon.NAME, name);
+ output.setProperty(path, DnaDtdLexicon.VALUE, value);
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#notationDecl(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void notationDecl( String name,
+ String publicId,
+ String systemId ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#processingInstruction(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void processingInstruction( String target,
+ String data ) throws SAXException {
+ stopIfCancelled();
+ // Output separate nodes for each instruction since multiple are allowed
+ Name name = DnaXmlLexicon.PROCESSING_INSTRUCTION;
+ startElement(name);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, name);
+ output.setProperty(path, DnaXmlLexicon.TARGET, target);
+ output.setProperty(path, DnaXmlLexicon.PROCESSING_INSTRUCTION_CONTENT, data);
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#skippedEntity(java.lang.String)
+ */
+ @Override
+ public void skippedEntity( String name ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#startCDATA()
+ */
+ @Override
+ public void startCDATA() throws SAXException {
+ stopIfCancelled();
+ // Output separate nodes for each CDATA since multiple are allowed
+ startElement(DnaXmlLexicon.CDATA);
+ // Prepare builder for concatenating consecutive lines of CDATA
+ cDataBuilder = new StringBuilder();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#startDocument()
+ */
+ @Override
+ public void startDocument() throws SAXException {
+ stopIfCancelled();
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.DOCUMENT);
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#startDTD(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void startDTD( String name,
+ String publicId,
+ String systemId ) throws SAXException {
+ stopIfCancelled();
+ output.setProperty(path, DnaDtdLexicon.NAME, name);
+ output.setProperty(path, DnaDtdLexicon.PUBLIC_ID, publicId);
+ output.setProperty(path, DnaDtdLexicon.SYSTEM_ID, systemId);
+ updateProgress();
+ }
+
+ private void startElement( Name name ) {
+ // Check if content still needs to be output
+ endContent();
+ // Add name to list of indexed names for this element to ensure we use the correct index (which is the size of the
+ // list)
+ List<IndexedName> indexedNames = nameToIndexedNamesMap.get(name);
+ if (indexedNames == null) {
+ indexedNames = new ArrayList<IndexedName>();
+ nameToIndexedNamesMap.put(name, indexedNames);
+ }
+ IndexedName indexedName = new IndexedName();
+ indexedNames.add(indexedName);
+ // Add element name and the appropriate index to the path.
+ // Per the JCR spec, the index must be relative to same-name sibling nodes
+ path = context.getValueFactories().getPathFactory().create(path, name, indexedNames.size());
+ path = path.getNormalizedPath();
+ // Add the indexed name map to the stack and set the current map to the new element's map
+ nameToIndexedNamesMapStack.addFirst(nameToIndexedNamesMap);
+ nameToIndexedNamesMap = indexedName.nameToIndexedNamesMap;
+ // Set the current namespace to whatever is declared by this element, or if not declared, to its nearest ancestor that
+ // does declare a namespace.
+ String ns = name.getNamespaceUri();
+ if (ns.length() == 0) {
+ nsStack.addFirst(nsStack.isEmpty() ? "" : nsStack.getFirst());
+ } else {
+ nsStack.addFirst(ns);
+ }
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String,
+ * org.xml.sax.Attributes)
+ */
+ @Override
+ public void startElement( String uri,
+ String localName,
+ String name,
+ Attributes attributes ) throws SAXException {
+ stopIfCancelled();
+ // Look for the "jcr:name" attribute, and use that if it's there
+ Name type = getDefaultPrimaryType();
+ Name nameObj = nameFactory.create(name);
+ for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
+ String ns = attributes.getURI(ndx);
+ String attrLocalName = attributes.getLocalName(ndx);
+ Object value = attributes.getValue(ndx);
+ String jcrNsUri = context.getNamespaceRegistry().getNamespaceForPrefix("jcr");
+ if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("name")) {
+ nameObj = nameFactory.create(value);
+ break;
+ }
+ }
+ startElement(nameObj);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, type);
+ // Output this element's attributes using the attribute's namespace, if supplied, or the current namespace in scope.
+ String inheritedNs = nsStack.getFirst();
+ for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
+ String ns = attributes.getURI(ndx);
+ String attrLocalName = attributes.getLocalName(ndx);
+ Object value = attributes.getValue(ndx);
+ String jcrNsUri = context.getNamespaceRegistry().getNamespaceForPrefix("jcr");
+ if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("primaryType")) {
+ value = nameFactory.create(value);
+ }
+ if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("name")) {
+ continue;
+ }
+ output.setProperty(path, nameFactory.create(ns.length() == 0 ? inheritedNs : ns, attrLocalName), value);
+ }
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#startEntity(java.lang.String)
+ */
+ @Override
+ public void startEntity( String name ) throws SAXException {
+ stopIfCancelled();
+ entity = name;
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#startPrefixMapping(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void startPrefixMapping( String prefix,
+ String uri ) throws SAXException {
+ stopIfCancelled();
+ // Register any unregistered namespaces
+ NamespaceRegistry registry = context.getNamespaceRegistry();
+ if (!registry.isRegisteredNamespaceUri(uri)) {
+ registry.register(prefix, uri);
+ }
+ updateProgress();
+ }
+
+ private void stopIfCancelled() throws SAXException {
+ if (monitor.isCancelled()) {
+ throw new SAXException(XmlSequencerI18n.canceledSequencingXmlDocument.text());
+ }
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public void unparsedEntityDecl( String name,
+ String publicId,
+ String systemId,
+ String notationName ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ private void updateProgress() {
+ if (progress == 100.0) {
+ progress = 1;
+ } else {
+ progress++;
+ }
+ monitor.worked(progress);
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void warning( SAXParseException warning ) {
+ context.getLogger(XmlSequencer.class).warn(warning, XmlSequencerI18n.warningSequencingXmlDocument);
+ monitor.getProblems().addWarning(warning, XmlSequencerI18n.warningSequencingXmlDocument, warning);
+ }
+ }
+
+ private class IndexedName {
+
+ Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name, List<IndexedName>>();
+
+ IndexedName() {
+ }
+ }
+}
Added: trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencerI18n.java
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencerI18n.java (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/main/java/org/jboss/dna/sequencer/xml/XmlSequencerI18n.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -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.sequencer.xml;
+
+import java.util.Locale;
+import java.util.Set;
+import org.jboss.dna.common.CommonI18n;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public final class XmlSequencerI18n {
+
+ public static I18n errorSequencingXmlDocument;
+ public static I18n fatalErrorSequencingXmlDocument;
+ public static I18n sequencingXmlDocument;
+ public static I18n canceledSequencingXmlDocument;
+ public static I18n warningSequencingXmlDocument;
+
+ static {
+ try {
+ I18n.initialize(XmlSequencerI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(CommonI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(CommonI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(CommonI18n.class, locale);
+ }
+}
Added: trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/XmlSequencerI18n.properties
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/XmlSequencerI18n.properties (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/XmlSequencerI18n.properties 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+errorSequencingXmlDocument = An error was received while sequencing XML: {0}
+fatalErrorSequencingXmlDocument = A fatal error was received while sequencing XML: {0}
+sequencingXmlDocument = Sequencing XML
+canceledSequencingXmlDocument = Canceled sequencing XML
+warningSequencingXmlDocument = A warning was received while sequencing XML: {0}
+
Added: trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/xml.cnd
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/xml.cnd (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/main/resources/org/jboss/dna/sequencer/xml/xml.cnd 2008-10-29 18:23:01 UTC (rev 598)
@@ -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.
+ */
+
+//------------------------------------------------------------------------------
+// N A M E S P A C E S
+//------------------------------------------------------------------------------
+<jcr='http://www.jcp.org/jcr/1.0'>
+<nt='http://www.jcp.org/jcr/nt/1.0'>
+<mix='http://www.jcp.org/jcr/mix/1.0'>
+<dnaxml='http://www.jboss.org/dna/xml/1.0'>
+<dnadtd='http://www.jboss.org/dna/dtd/1.0'>
+
+// ----------------------------------------------------------
+// JCR Pre-defined Mixin Types that are not loaded by default
+// ----------------------------------------------------------
+
+[mix:mimeType] mixin
+ - jcr:mimeType (string)
+ - jcr:encoding (string)
+
+
+//------------------------------------------------------------------------------
+// N O D E T Y P E S
+//------------------------------------------------------------------------------
+
+[dnaxml:document] > nt:unstructured, mix:mimeTyped
+ - dnaxml:cDataContent (string)
+
+[dnaxml:comment] > nt:unstructured, mix:mimeTyped
+ - dnaxml:commentContent (string)
+
+[dnaxml:element] > nt:unstructured, mix:mimeTyped
+ - dnaxml:elementContent (string)
+
+[dnaxml:cData] > nt:unstructured, mix:mimeTyped
+ - dnaxml:cDataContent (string)
+
+[dnaxml:processingInstruction] > nt:unstructured, mix:mimeTyped
+ - dnaxml:processingInstruction (string)
+ - dnaxml:target (string)
+
+
+[dnadtd:entity] > nt:unstructured, mix:mimeTyped
+ - dnaxml:name (string)
+ - dnaxml:value (string)
+ - dnaxml:publicId (string)
+ - dnaxml:systemId (string)
+
+
\ No newline at end of file
Added: trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,222 @@
+/*
+ * 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.sequencer.xml;
+
+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.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.SimpleProgressMonitor;
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.sequencers.MockSequencerContext;
+import org.jboss.dna.graph.sequencers.MockSequencerOutput;
+import org.jboss.dna.graph.sequencers.SequencerContext;
+import org.jboss.dna.sequencer.xml.XmlSequencer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author John Verhaeg
+ */
+public class XmlSequencerTest {
+
+ private static final String CDATA = "dnaxml:cData";
+ private static final String CDATA_CONTENT = "dnaxml:cDataContent";
+ private static final String COMMENT = "dnaxml:comment";
+ private static final String COMMENT_CONTENT = "dnaxml:commentContent";
+ private static final String DOCUMENT = "dnaxml:document";
+ private static final String DTD_NAME = "dnadtd:name";
+ private static final String DTD_PUBLIC_ID = "dnadtd:publicId";
+ private static final String DTD_SYSTEM_ID = "dnadtd:systemId";
+ private static final String DTD_VALUE = "dnadtd:value";
+ private static final String ELEMENT_CONTENT = "dnaxml:elementContent";
+ private static final String ENTITY = "dnadtd:entity";
+ private static final String PI = "dnaxml:processingInstruction";
+ private static final String PI_CONTENT = "dnaxml:processingInstructionContent";
+ private static final String TARGET = "dnaxml:target";
+
+ private XmlSequencer sequencer;
+ private InputStream stream;
+ private MockSequencerOutput output;
+ private ProgressMonitor monitor;
+ private URL xml1;
+ private URL xml2;
+ private URL xml3;
+ private URL xml4;
+ private URL xsd;
+ private SequencerContext context;
+
+ @Before
+ public void beforeEach() {
+ sequencer = new XmlSequencer();
+ context = new MockSequencerContext();
+ output = new MockSequencerOutput(context);
+ monitor = new SimpleProgressMonitor("Test activity");
+ xml1 = this.getClass().getClassLoader().getResource("jackrabbitInMemoryTestRepositoryConfig.xml");
+ assertThat(xml1, is(notNullValue()));
+ xml2 = this.getClass().getClassLoader().getResource("master.xml");
+ assertThat(xml2, is(notNullValue()));
+ xml3 = this.getClass().getClassLoader().getResource("CurrencyFormatterExample.mxml");
+ assertThat(xml3, is(notNullValue()));
+ xml4 = this.getClass().getClassLoader().getResource("plugin.xml");
+ assertThat(xml4, is(notNullValue()));
+ xsd = this.getClass().getClassLoader().getResource("Descriptor.1.0.xsd");
+ assertThat(xsd, is(notNullValue()));
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ if (stream != null) {
+ try {
+ stream.close();
+ } finally {
+ stream = null;
+ }
+ }
+ }
+
+ @Test
+ public void shouldSequenceXml() throws IOException {
+ verifyDocument(xml1);
+ verifyName(COMMENT + "[1]", "jcr:primaryType", COMMENT);
+ String text = verify(COMMENT + "[1]", COMMENT_CONTENT, String.class);
+ assertThat(text.startsWith("\n Licensed to the Apache Software Foundation (ASF)"), is(true));
+ assertThat(text.endsWith(" limitations under the License.\n"), is(true));
+ verifyString("/", DTD_NAME, "Repository");
+ verifyString("/", DTD_PUBLIC_ID, "-//The Apache Software Foundation//DTD Jackrabbit 1.2//EN");
+ verifyString("/", DTD_SYSTEM_ID, "http://jackrabbit.apache.org/dtd/repository-1.2.dtd");
+ verifyName(COMMENT + "[2]", "jcr:primaryType", COMMENT);
+ verifyString(COMMENT + "[2]", COMMENT_CONTENT, " Example Repository Configuration File ");
+ verifyName("Repository[1]", "jcr:primaryType", "nt:unstructured");
+ verifyName("Repository[1]/" + COMMENT + "[1]", "jcr:primaryType", COMMENT);
+ }
+
+ @Test
+ public void shouldHandleNamespaces() throws IOException {
+ verifyDocument(xml2);
+ verifyName("book[1]/bookinfo[1]/xi:include[1]", "jcr:primaryType", "nt:unstructured");
+ verifyString("book[1]/bookinfo[1]/xi:include[1]", "xi:href", "Author_Group.xml");
+ verifyName("book[1]/bookinfo[1]/xi:include[2]", "jcr:primaryType", "nt:unstructured");
+ verifyString("book[1]/bookinfo[1]/xi:include[2]", "xi:href", "Legal_Notice.xml");
+ }
+
+ @Test
+ public void shouldSequenceEntityDeclarations() throws IOException {
+ verifyDocument(xml2);
+ verifyName(ENTITY + "[1]", "jcr:primaryType", ENTITY);
+ verifyString(ENTITY + "[1]", DTD_NAME, "%RH-ENTITIES");
+ verifyString(ENTITY + "[1]", DTD_SYSTEM_ID, "Common_Config/rh-entities.ent");
+ verifyName(ENTITY + "[2]", "jcr:primaryType", ENTITY);
+ verifyString(ENTITY + "[2]", DTD_NAME, "versionNumber");
+ verifyString(ENTITY + "[2]", DTD_VALUE, "0.1");
+ verifyName(ENTITY + "[3]", "jcr:primaryType", ENTITY);
+ verifyString(ENTITY + "[3]", DTD_NAME, "copyrightYear");
+ verifyString(ENTITY + "[3]", DTD_VALUE, "2008");
+ }
+
+ @Test
+ public void shouldSequenceElementContent() throws IOException {
+ verifyDocument(xml2);
+ verifyString("book[1]/chapter[4]/sect1[1]/para[8]/" + ELEMENT_CONTENT + "[1]",
+ ELEMENT_CONTENT,
+ "The path expression is more complicated."
+ + " Sequencer path expressions are used by the sequencing service to determine whether a particular changed node should be sequenced."
+ + " The expressions consist of two parts: a selection criteria and an output expression."
+ + " Here's a simple example:");
+ verifyString("book[1]/chapter[4]/sect1[1]/para[8]/programlisting[1]/" + ELEMENT_CONTENT + "[1]",
+ ELEMENT_CONTENT,
+ "/a/b/c@title => /d/e/f");
+ }
+
+ @Test
+ public void shouldSequenceCData() throws IOException {
+ verifyDocument(xml3);
+ verifyString("mx:Application[1]/mx:Script[1]/" + CDATA + "[1]",
+ CDATA_CONTENT,
+ "\n\n" + " import mx.events.ValidationResultEvent;\t\t\t\n"
+ + " private var vResult:ValidationResultEvent;\n" + "\t\t\t\n"
+ + " // Event handler to validate and format input.\n"
+ + " private function Format():void {\n" + " \n"
+ + " vResult = numVal.validate();\n\n"
+ + " if (vResult.type==ValidationResultEvent.VALID) {\n"
+ + " var temp:Number=Number(priceUS.text); \n"
+ + " formattedUSPrice.text= usdFormatter.format(temp);\n" + " }\n"
+ + " \n" + " else {\n"
+ + " formattedUSPrice.text=\"\";\n" + " }\n" + " }\n"
+ + " ");
+ }
+
+ @Test
+ public void shouldSequenceProcessingInstructions() throws IOException {
+ verifyDocument(xml4);
+ verifyName(PI + "[1]", "jcr:primaryType", PI);
+ verifyString(PI + "[1]", TARGET, "eclipse");
+ verifyString(PI + "[1]", PI_CONTENT, "version=\"3.0\"");
+ }
+
+ @Test
+ public void shouldSequenceXsds() throws IOException {
+ verifyDocument(xsd);
+ verifyName("xs:schema[1]", "jcr:primaryType", "nt:unstructured");
+ verifyString("xs:schema[1]", "xs:targetNamespace", "http://ns.adobe.com/air/application/1.0");
+ verifyString("xs:schema[1]", "xs:elementFormDefault", "qualified");
+ verifyName("xs:schema[1]/xs:element[1]", "jcr:primaryType", "nt:unstructured");
+ verifyString("xs:schema[1]/xs:element[1]", "xs:name", "application");
+ }
+
+ private <T> T verify( String nodePath,
+ String property,
+ Class<T> expectedClass ) {
+ Object[] values = output.getPropertyValues(nodePath.length() == 0 ? "." : nodePath, property);
+ assertThat(values, notNullValue());
+ assertThat(values.length, is(1));
+ Object value = values[0];
+ assertThat(value, instanceOf(expectedClass));
+ return expectedClass.cast(value);
+ }
+
+ private void verifyDocument( URL url ) throws IOException {
+ stream = url.openStream();
+ assertThat(stream, is(notNullValue()));
+ sequencer.sequence(stream, output, context, monitor);
+ verifyName("", "jcr:primaryType", DOCUMENT);
+ }
+
+ private void verifyName( String nodePath,
+ String property,
+ String expectedName ) {
+ Name name = verify(nodePath, property, Name.class);
+ assertThat(name, is(context.getValueFactories().getNameFactory().create(expectedName)));
+ }
+
+ private void verifyString( String nodePath,
+ String property,
+ String expectedString ) {
+ String string = verify(nodePath, property, String.class);
+ assertThat(string, is(expectedString));
+ }
+}
Added: trunk/extensions/dna-sequencer-xml/src/test/resources/CurrencyFormatterExample.mxml
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/resources/CurrencyFormatterExample.mxml (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/test/resources/CurrencyFormatterExample.mxml 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Simple example to demonstrate the CurrencyFormatter. -->
+<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
+
+ <mx:Script>
+ <![CDATA[
+
+ import mx.events.ValidationResultEvent;
+ private var vResult:ValidationResultEvent;
+
+ // Event handler to validate and format input.
+ private function Format():void {
+
+ vResult = numVal.validate();
+
+ if (vResult.type==ValidationResultEvent.VALID) {
+ var temp:Number=Number(priceUS.text);
+ formattedUSPrice.text= usdFormatter.format(temp);
+ }
+
+ else {
+ formattedUSPrice.text="";
+ }
+ }
+ ]]>
+ </mx:Script>
+
+ <mx:CurrencyFormatter id="usdFormatter" precision="2"
+ currencySymbol="$" decimalSeparatorFrom="."
+ decimalSeparatorTo="." useNegativeSign="true"
+ useThousandsSeparator="true" alignSymbol="left"/>
+
+ <mx:NumberValidator id="numVal" source="{priceUS}" property="text"
+ allowNegative="true" domain="real"/>
+
+ <mx:Panel title="CurrencyFormatter Example" width="75%" height="75%"
+ paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
+
+ <mx:Form>
+ <mx:FormItem label="Enter U.S. dollar amount:">
+ <mx:TextInput id="priceUS" text="" width="50%"/>
+ </mx:FormItem>
+
+ <mx:FormItem label="Formatted amount: ">
+ <mx:TextInput id="formattedUSPrice" text="" width="50%" editable="false"/>
+ </mx:FormItem>
+
+ <mx:FormItem>
+ <mx:Button label="Validate and Format" click="Format();"/>
+ </mx:FormItem>
+ </mx:Form>
+
+ </mx:Panel>
+</mx:Application>
Added: trunk/extensions/dna-sequencer-xml/src/test/resources/Descriptor.1.0.xsd
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/resources/Descriptor.1.0.xsd (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/test/resources/Descriptor.1.0.xsd 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,127 @@
+<?xml version="1.0"?>
+<xs:schema
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://ns.adobe.com/air/application/1.0"
+ xmlns="http://ns.adobe.com/air/application/1.0"
+ elementFormDefault="qualified"
+>
+ <xs:element name="application">
+ <xs:complexType>
+ <xs:all>
+ <!-- About this application -->
+ <xs:element name="id">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Za-z0-9\-\.]{1,212}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="name" type="xs:string" minOccurs="0"/>
+ <xs:element name="version" type="xs:string"/>
+ <xs:element name="filename">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <!-- name cannot begin with a ' ' (space), have any of these characters: *"/:<>?\|, and end with a . (dot) or ' ' (space) -->
+ <xs:pattern value='[^\*"/:><\?\\\|\. ]|[^\*"/:><\?\\\| ][^\*"/:><\?\\\|]*[^\*"/:><\?\\\|\. ]'/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="description" type="xs:string" minOccurs="0"/>
+ <xs:element name="copyright" type="xs:string" minOccurs="0"/>
+ <xs:element name="icon" type="IconType" minOccurs="0"/>
+
+ <!-- How to start this application -->
+ <xs:element name="initialWindow">
+ <xs:complexType>
+ <xs:all>
+ <xs:element name="content" type="xs:anyURI" minOccurs="1" />
+ <xs:element name="title" type="xs:string" minOccurs="0" />
+
+ <xs:element name="systemChrome" minOccurs="0" >
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="none"/>
+ <xs:enumeration value="standard"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="transparent" type="xs:boolean" minOccurs="0" />
+ <xs:element name="visible" type="xs:boolean" minOccurs="0" />
+
+ <xs:element name="minimizable" type="xs:boolean" minOccurs="0" />
+ <xs:element name="maximizable" type="xs:boolean" minOccurs="0" />
+ <xs:element name="resizable" type="xs:boolean" minOccurs="0" />
+
+ <xs:element name="x" type="xs:int" minOccurs="0" />
+ <xs:element name="y" type="xs:int" minOccurs="0" />
+ <xs:element name="width" type="xs:unsignedInt" minOccurs="0" />
+ <xs:element name="height" type="xs:unsignedInt" minOccurs="0" />
+ <xs:element name="minSize" type="BoundsSizeType" minOccurs="0" />
+ <xs:element name="maxSize" type="BoundsSizeType" minOccurs="0" />
+ </xs:all>
+ </xs:complexType>
+ </xs:element>
+
+ <!-- About installing this application -->
+ <xs:element name="installFolder" minOccurs="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <!-- installFolder cannot begin with a / (forward-slash) or a ' ' (space), have any of these characters: *":<>?\|, and end with a . (dot) or ' ' (space) -->
+ <xs:pattern value='[^\*"/:><\?\\\|\. ]|[^\*"/:><\?\\\| ][^\*":><\?\\\|]*[^\*":><\?\\\|\. ]'/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="programMenuFolder" minOccurs="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <!-- programMenuFolder cannot begin with a / (forward-slash) or a ' ' (space), have any of these characters: *":<>?\|, and end with a . (dot) or ' ' (space) -->
+ <xs:pattern value='[^\*"/:><\?\\\|\. ]|[^\*"/:><\?\\\| ][^\*":><\?\\\|]*[^\*":><\?\\\|\. ]'/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+
+ <!-- Features this application can opt in to -->
+ <xs:element name="customUpdateUI" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="allowBrowserInvocation" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="fileTypes" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="fileType" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:all>
+ <xs:element name="name" type="xs:string"/>
+ <xs:element name="extension" type="xs:string"/>
+ <xs:element name="description" type="xs:string" minOccurs="0"/>
+ <xs:element name="contentType" type="xs:string" minOccurs="0"/>
+ <xs:element name="icon" type="IconType" minOccurs="0"/>
+ </xs:all>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:all>
+
+ <!-- About the runtime version required -->
+ <xs:attribute name="minimumPatchLevel" type="xs:unsignedInt"/>
+ </xs:complexType>
+ </xs:element>
+
+ <!-- Type definitions -->
+ <xs:complexType name="IconType">
+ <xs:all>
+ <xs:element name="image16x16" type="xs:anyURI" minOccurs="0"/>
+ <xs:element name="image32x32" type="xs:anyURI" minOccurs="0"/>
+ <xs:element name="image48x48" type="xs:anyURI" minOccurs="0"/>
+ <xs:element name="image128x128" type="xs:anyURI" minOccurs="0"/>
+ </xs:all>
+ </xs:complexType>
+ <xs:simpleType name="UnsignedIntListType">
+ <xs:list itemType="xs:unsignedInt"/>
+ </xs:simpleType>
+ <xs:simpleType name="BoundsSizeType">
+ <xs:restriction base="UnsignedIntListType">
+ <xs:length value="2"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
Added: trunk/extensions/dna-sequencer-xml/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.2//EN"
+ "http://jackrabbit.apache.org/dtd/repository-1.2.dtd">
+<!-- Example Repository Configuration File -->
+<Repository>
+ <!--
+ virtual file system where the repository stores global state
+ (e.g. registered namespaces, custom node types, etc.)
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem">
+ <param name="path" value="${rep.home}/repository"/>
+ </FileSystem>
+
+ <!--
+ security configuration
+ -->
+ <Security appName="Jackrabbit">
+ <!--
+ access manager:
+ class: FQN of class implementing the AccessManager interface
+ -->
+ <AccessManager class="org.apache.jackrabbit.core.security.SimpleAccessManager">
+ <!-- <param name="config" value="${rep.home}/access.xml"/> -->
+ </AccessManager>
+
+ <LoginModule class="org.apache.jackrabbit.core.security.SimpleLoginModule">
+ <!-- anonymous user name ('anonymous' is the default value) -->
+ <param name="anonymousId" value="anonymous"/>
+ <!--
+ default user name to be used instead of the anonymous user
+ when no login credentials are provided (unset by default)
+ -->
+ <!-- <param name="defaultUserId" value="superuser"/> -->
+ </LoginModule>
+ </Security>
+
+ <!--
+ location of workspaces root directory and name of default workspace
+ -->
+ <Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default"/>
+ <!--
+ workspace configuration template:
+ used to create the initial workspace if there's no workspace yet
+ -->
+ <Workspace name="Jackrabbit Core">
+ <!--
+ virtual file system of the workspace:
+ class: FQN of class implementing the FileSystem interface
+ -->
+
+ <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem">
+ <param name="path" value="${wsp.home}"/>
+ </FileSystem>
+ <!--
+ persistence manager of the workspace:
+ class: FQN of class implementing the PersistenceManager interface
+ -->
+ <PersistenceManager class="org.apache.jackrabbit.core.persistence.mem.InMemPersistenceManager">
+ <param name="persistent" value="false"/>
+ </PersistenceManager>
+ <!--
+ Search index and the file system it uses.
+ class: FQN of class implementing the QueryHandler interface
+ -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${wsp.home}/index"/>
+ </SearchIndex>
+ </Workspace>
+
+ <!--
+ Configures the versioning
+ -->
+ <Versioning rootPath="${rep.home}/version">
+ <!--
+ Configures the filesystem to use for versioning for the respective
+ persistence manager
+ -->
+ <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem">
+ <param name="path" value="${rep.home}/version" />
+ </FileSystem>
+
+ <!--
+ Configures the persistence manager to be used for persisting version state.
+ Please note that the current versioning implementation is based on
+ a 'normal' persistence manager, but this could change in future
+ implementations.
+ -->
+ <PersistenceManager class="org.apache.jackrabbit.core.persistence.mem.InMemPersistenceManager">
+ <param name="persistent" value="false"/>
+ </PersistenceManager>
+ </Versioning>
+
+ <!--
+ Search index for content that is shared repository wide
+ (/jcr:system tree, contains mainly versions)
+ -->
+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+ <param name="path" value="${rep.home}/repository/index"/>
+ </SearchIndex>
+</Repository>
Added: trunk/extensions/dna-sequencer-xml/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/resources/log4j.properties (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/test/resources/log4j.properties 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,12 @@
+# 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
+
Added: trunk/extensions/dna-sequencer-xml/src/test/resources/master.xml
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/resources/master.xml (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/test/resources/master.xml 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,1890 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program 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 distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+<!ENTITY % RH-ENTITIES SYSTEM "Common_Config/rh-entities.ent">
+<!ENTITY versionNumber "0.1">
+<!ENTITY copyrightYear "2008">
+<!ENTITY copyrightHolder "Red Hat Middleware, LLC.">]>
+<book>
+ <bookinfo>
+ <title>JBoss DNA</title>
+ <subtitle>Getting Started Guide</subtitle>
+ <releaseinfo>&versionNumber;
+ </releaseinfo>
+ <productnumber>&versionNumber;
+ </productnumber>
+ <issuenum>1</issuenum>
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/dna-logo.png" align="center" />
+ </imageobject>
+ <imageobject role="pdf">
+ <imagedata fileref="images/dna-logo.png" scale="75" align="center" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="images/dna-logo.png" depth="3cm" />
+ </imageobject>
+ <imageobject role="xhtml">
+ <imagedata fileref="images/dna-logo.png" depth="3cm" />
+ </imageobject>
+ <imageobject role="xhtml_single">
+ <imagedata fileref="images/dna-logo.png" depth="3cm" />
+ </imageobject>
+ </mediaobject>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Author_Group.xml" />
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="Legal_Notice.xml" />
+ </bookinfo>
+ <preface id="preface" revision="1">
+ <title>What this book covers</title>
+ <para>The goal of this book is to help you learn about JBoss DNA and how you can use it in your own applications to get the
+ most out of your JCR repositories.</para>
+ <para>The first part of the book starts out with an introduction to content repositories and an overview of the JCR API,
+ both of which are important aspects of JBoss DNA. This is followed by an overview of the JBoss DNA project, its
+ architecture, and a basic roadmap for what's coming next.</para>
+ <para>The next part of the book covers how to download and build the examples, how to use JBoss DNA with existing
+ repositories, and how to build and use custom sequencers.</para>
+ <para>
+ If you have any questions or comments, please feel free to contact JBoss DNA's
+ <ulink url="mailto:dna-users@jboss.org">user mailing list</ulink>
+ or use the
+ <ulink url="http://www.jboss.com/index.html?module=bb&op=viewforum&f=272">user forums</ulink>
+ . If you'd like to get involved on the project, join the
+ <ulink url="http://www.jboss.org/dna/lists.html">mailing lists</ulink>
+ ,
+ <ulink url="http://www.jboss.org/dna/subversion.html">download the code</ulink>
+ and get it building, and visit our
+ <ulink url="http://jira.jboss.org/jira/browse/DNA">JIRA issue management system</ulink>
+ . If there's something in particular you're interested in, talk with the community - there may be others interested in the
+ same thing.
+ </para>
+ </preface>
+ <chapter id="introduction">
+ <title>Introduction</title>
+ <para>There are a lot of choices for how applications can store information persistently so that it can be accessed at a
+ later time and by other processes. The challenge developers face is how to use an approach that most closely matches the
+ needs of their application. This choice becomes more important as developers choose to focus their efforts on
+ application-specific logic, delegating much of the responsibilities for persistence to libraries and frameworks.</para>
+ <para>
+ Perhaps one of the easiest techniques is to simply store information in
+ <emphasis>files</emphasis>
+ . The Java language makes working with files relatively easy, but Java really doesn't provide many bells and whistles. So
+ using files is an easy choice when the information is either not complicated (for example property files), or when users may
+ need to read or change the information outside of the application (for example log files or configuration files). But using
+ files to persist information becomes more difficult as the information becomes more complex, as the volume of it increases,
+ or if it needs to be accessed by multiple processes. For these situations, other techniques often offer better choices.
+ </para>
+ <para>
+ Another technique built into the Java language is
+ <emphasis>Java serialization</emphasis>
+ , which is capable of persisting the state of an object graph so that it can be read back in at a later time. However, Java
+ serialization can quickly become tricky if the classes are changed, and so it's beneficial usually when the information is
+ persisted for a very short period of time. For example, serialization is sometimes used to send an object graph from one
+ process to another.
+ </para>
+ <para>
+ One of the more popular persistence technologies is the
+ <emphasis>relational database</emphasis>
+ . Relational database management systems have been around for decades and are very capable. The Java Database Connectivity
+ (JDBC) API provides a standard interface for connecting to and interacting with relational databases. However, it is a
+ low-level API that requires a lot of code to use correctly, and it still doesn't abstract away the DBMS-specific SQL
+ grammar. Also, working with relational data in an object-oriented language can feel somewhat unnatural, so many developers
+ map this data to classes that fit much more cleanly into their application. The problem is that manually creating this
+ mapping layer requires a lot of repetitive and non-trivial JDBC code.
+ </para>
+ <para>
+ <emphasis>Object-relational mapping</emphasis>
+ libraries automate the creation of this mapping layer and result in far less code that is much more maintainable with
+ performance that is often as good as (if not better than) handwritten JDBC code. The new
+ <ulink url="http://java.sun.com/developer/technicalArticles/J2EE/jpa/">Java Persistence API (JPA)</ulink>
+ provide a standard mechanism for defining the mappings (through annotations) and working with these entity objects. Several
+ commercial and open-source libraries implement JPA, and some even offer additional capabilities and features that go beyond
+ JPA. For example,
+ <ulink url="http://www.hibernate.org">Hibernate</ulink>
+ is one of the most feature-rich JPA implementations and offers object caching, statement caching, extra association
+ mappings, and other features that help to improve performance and usefulness.
+ </para>
+ <para>
+ While relational databases and JPA are solutions that work for many applications, they become more limited in cases when the
+ information structure is highly flexible, is not known
+ <emphasis>a priori</emphasis>
+ , or is subject to frequent change and customization. In these situations,
+ <emphasis>content repositories</emphasis>
+ may offer a better choice for persistence. Content repositories are almost a hybrid between relational databases and file
+ systems, and typically provide other capabilities as well, including versioning, indexing, search, access control,
+ transactions, and observation. Because of this, content repositories are used by content management systems (CMS), document
+ management systems (DMS), and other applications that manage electronic files (e.g., documents, images, multi-media, web
+ content, etc.) and metadata associated with them (e.g., author, date, status, security information, etc.). The
+ <ulink url="http://www.jcp.org/en/jsr/detail?id=170">Content Repository for Java technology API</ulink>
+ provides a standard Java API for working with content repositories. Abbreviated "JCR", this API was developed as part of the
+ Java Community Process under
+ <ulink url="http://www.jcp.org/en/jsr/detail?id=170">JSR-170</ulink>
+ and is being revised under
+ <ulink url="http://www.jcp.org/en/jsr/detail?id=283">JSR-283</ulink>
+ .
+ </para>
+ <para>
+ The
+ <emphasis>JBoss DNA project</emphasis>
+ is building the tools and services that surround content repositories. Nearly all of these capabilities are to be hidden
+ below the JCR API and involve automated processing of the information in the repository. Thus, JBoss DNA can add value to
+ existing repository implementations. For example, JCR repositories offer the ability to upload files into the repository and
+ have the file content indexed for search purposes. JBoss DNA also defines a library for "sequencing" content - to extract
+ meaningful information from that content and store it in the repository, where it can then be searched, accessed, and
+ analyzed using the JCR API.
+ </para>
+ <para> JBoss DNA is building other features as well. One goal of JBoss DNA is to create federated repositories that
+ dynamically merge the information from multiple databases, services, applications, and other JCR repositories. Another is to
+ create customized views based upon the type of data and the role of the user that is accessing the data. And yet another is
+ to create a REST-ful API to allow the JCR content to be accessed easily by other applications written in other languages.
+ </para>
+ <para>
+ The
+ <link linkend="jboss_dna">next chapter</link>
+ in this book goes into more detail about JBoss DNA and its architecture, the different components, what's available now, and
+ what's coming in future releases.
+ <link linkend="downloading_and_running">Chapter 3</link>
+ then provides instructions for downloading and running the sequencer examples for the current release.
+ <link linkend="using_dna">Chapter 4</link>
+ walks through how to use JBoss DNA in your applications, while
+ <link linkend="custom_sequencers">Chapter 5</link>
+ goes over how to create custom sequencers. Finally,
+ <link linkend="future_directions">Chapter 6</link>
+ wraps things up with a discussion about the future of JBoss DNA.
+ </para>
+ </chapter>
+ <chapter id="jboss_dna">
+ <title>Understanding JBoss DNA</title>
+ <sect1 id="jboss_dna_overview">
+ <title>Overview</title>
+ <para>JBoss DNA is a repository and set of tools that make it easy to capture, version, analyze, and understand the
+ fundamental building blocks of information. As models, service and process definitions, schemas, source code, and other
+ artifacts are added to the repository, JBoss DNA "sequences" the makeup of these components and extracts their structure
+ and interdependencies. The JBoss DNA web application allows end users to access, visualize, and edit this information in
+ the terminology and structure they are familiar with. Such domain-specific solutions can be easily created with little or
+ no programming.</para>
+ <para> JBoss DNA supports the Java Content Repository (JCR) standard and is able to provide a single integrated view of
+ multiple repositories, external databases, services, and applications, ensuring that JBoss DNA has access to the latest
+ and most reliable master data. For instance, DNA could provide in a single view valuable insight into the business
+ processes and process-level services impacted by a change to in an intermediary web server operation defined via WSDL.
+ Similarly, a user could quickly view and navigate the dependencies between the data source models and transformation
+ information stored within a content repository, the code base stored within a version control system, and the database
+ schemas used by an application.</para>
+ </sect1>
+ <sect1 id="architecture">
+ <title>Architecture</title>
+ <para>The architecture for JBoss DNA consists of several major components that will be built on top of standard APIs,
+ including JCR, JDBC, JNDI and HTTP. The goal is to allow these components to be assembled as needed and add value on top
+ of other DNA components or third-party systems that support these standard APIs.</para>
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata align="center" fileref="images/dna-architecture.png" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata align="center" fileref="images/dna-architecture.png" />
+ </imageobject>
+ </mediaobject>
+ <para>
+ As shown in the diagram above, the major components are (starting at the top):
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Eclipse Plugins</emphasis>
+ enable Eclipse users to access the contents of a JBoss DNA repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA JDBC Driver</emphasis>
+ provides a driver implementation, allowing JDBC-aware applications to connect to and use a JBoss DNA repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Remote JCR</emphasis>
+ is a client-side component for accessing remote JCR repositories.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Web Application</emphasis>
+ is used by end users and domain experts to visualize, search, edit, change and tag the repository content. The web
+ application uses views to define how different types of information are to be presented and edited in
+ domain-specific ways. The goal is that this web application is easily customized and branded for inclusion into
+ other solutions and application systems. The DNA Web Application operates upon any JCR-compliant repository,
+ although it does rely upon the DNA analysis and templating services.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Publishing Server</emphasis>
+ allows content to be downloaded, uploaded, and edited using the Atom Publishing Protocol. With the DNA Publishing
+ Server, the content of the repository can easily be created, read, edited, and deleted using the standard HTTP
+ operations of POST, GET, PUT, and DELETE (respectively). More and more tools are being created that support working
+ with Atom Publishing servers. The DNA Publishing Server operates upon any JCR-compliant repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA WebDAV Server</emphasis>
+ allows clients such as Microsoft Windows and Apple OS X to connect to, read, and edit the content in the repository
+ using the WebDAV standard. Since WebDAV is an extension of HTTP, web browsers are able to read (but not modify) the
+ content served by a WebDAV compliant server. The DNA WebDAV Server operates upon any JCR-compliant repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Sequencers</emphasis>
+ are pluggable components that make it possible for content to be uploaded to the repository and automatically
+ processed to extract meaningful structure and place that structure in the repository. Once this information is in
+ the repository, it can be viewed, edited, analyzed, searched, and related to other content. DNA defines a Java
+ interface that sequencers must implement. DNA sequencers operate upon any JCR-compliant repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Analyses</emphasis>
+ are pluggable components that analyze content and the relationships between content to generate reports or to answer
+ queries. DNA will include some standard analyzers, like dependency analysis and similarity analysis, that are
+ commonly needed by many different solutions. DNA analyzers operate upon any JCR-compliant repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Views</emphasis>
+ are definitions of how types of information are to be presented in a user interface to allow for creation, reading,
+ editing, and deletion of information. DNA view definitions consist of data stored in a JCR repository, and as such
+ views can be easily added, changed or removed entirely by using the DNA Web Application, requiring no programming.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Federation</emphasis>
+ is an implementation of the JCR API that builds the content within the repository by accessing and integrating
+ information from multiple sources. DNA Federation allows the integration of external systems, like other JCR
+ repositories, databases, applications, and services.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Connectors</emphasis>
+ are used to communicate with these external sources of information. In the federation engine, each source is able to
+ contribute node structure and node properties to any part of the federated graph, although typically many connectors
+ will contribute most of their information to isolated subgraphs. The result is that integration from a wide range of
+ systems can be integrated and accessed through the DNA Web Application, DNA Publishing Server, and DNA WebDAV
+ Server. Connectors also may optionally participate in distributed transactions by exposing an XAResource.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Maven</emphasis>
+ is a classloader library compatible with Maven 2 project dependencies. This allows the creation of Java ClassLoader
+ instances using Maven 2 style paths, and all dependencies are transitively managed and included.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Continue reading the rest of this chapter for more detail about the
+ <link linkend="sequencers">sequencing framework</link>
+ available in this release, or the
+ <link linkend="federation">federation engine</link>
+ and
+ <link linkend="federation_connectors">connectors</link>
+ that will be the focus of the next release. Or, skip to the
+ <link linkend="downloading_and_running">examples</link>
+ to see how to start using JBoss DNA &versionNumber;
+ today.
+ </para>
+ </sect1>
+ <sect1 id="sequencers">
+ <title>Sequencing content</title>
+ <para> The current JBoss DNA release contains a sequencing framework that is designed to sequence data (typically files)
+ stored in a JCR repository to automatically extract meaningful and useful information. This additional information is then
+ saved back into the repository, where it can be accessed and used.</para>
+ <para> In other words, you can just upload various kinds of files into a JCR repository, and DNA automatically processes
+ those files to extract meaningful structured information. For example, load DDL files into the repository, and let
+ sequencers extract the structure and metadata for the database schema. Load Hibernate configuration files into the
+ repository, and let sequencers extract the schema and mapping information. Load Java source into the repository, and let
+ sequencers extract the class structure, JavaDoc, and annotations. Load a PNG, JPEG, or other image into the repository,
+ and let sequencers extract the metadata from the image and save it in the repository. The same with XSDs, WSDL, WS
+ policies, UML, MetaMatrix models, etc.</para>
+ <para>
+ JBoss DNA sequencers sit on top of existing JCR repositories (including federated repositories) - they basically extract
+ more useful information from what's already stored in the repository. And they use the existing JCR versioning system. Each
+ sequencer typically processes a single kind of file format or a single kind of content. </para>
+ <para>The following sequencers are included in JBoss DNA:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">Image sequencer</emphasis>
+ - A sequencer that processes the binary content of an image file, extracts the metadata for the image, and then
+ writes that image metadata to the repository. It gets the file format, image resolution, number of bits per pixel
+ (and optionally number of images), comments and physical resolution from JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM,
+ PGM, PPM, and PSD files. (This sequencer may be improved in the future to also extract EXIF metadata from JPEG
+ files; see
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ulink>
+ .)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">MP3 sequencer</emphasis>
+ - A sequencer that processes the contents of an MP3 audio file, extracts the metadata for the file, and then
+ writes that image metadata to the repository. It gets the title, author, album, year, and comment.
+ (This sequencer may be improved in the future to also extract other ID3 metadata from other audio file formats; see
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-66">DNA-26</ulink>
+ .)
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ As the community develops additional sequencers, they will also be included in JBoss DNA. Some of those that have been
+ identified as being useful include:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">XML Schema Document (XSD) Sequencer</emphasis>
+ - Process XSD files and extract the various elements, attributes, complex types, simple types, groups, and other
+ information. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-32">DNA-32</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Web Service Definition Language (WSDL) Sequencer</emphasis>
+ - Process WSDL files and extract the services, bindings, ports, operations, parameters, and other information. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-33">DNA-33</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Hibernate File Sequencer</emphasis>
+ - Process Hibernate configuration (cfg.xml) and mapping (hbm.xml) files to extract the configuration and mapping
+ information. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-61">DNA-61</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">XML Metadata Interchange (XMI) Sequencer</emphasis>
+ - Process XMI documents that contain UML models or models using another metamodel, extracting the model structure
+ into the repository. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-31">DNA-31</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">ZIP Archive Sequencer</emphasis>
+ - Process ZIP archive files to extract (explode) the contents into the repository. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-63">DNA-63</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Java Archive (JAR) Sequencer</emphasis>
+ - Process JAR files to extract (explode) the contents into the classes and file resources. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-64">DNA-64</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Java Class File Sequencer</emphasis>
+ - Process Java class files (bytecode) to extract the class structure (including annotations) into the repository.
+ (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-62">DNA-62</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Java Source File Sequencer</emphasis>
+ - Process Java source files to extract the class structure (including annotations) into the repository. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-51">DNA-51</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">PDF Sequencer</emphasis>
+ - Process PDF files to extract the document metadata, including table of contents. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-50">DNA-50</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Maven 2 POM Sequencer</emphasis>
+ - Process Maven 2 Project Object Model (POM) files to extract the project information, dependencies, plugins, and
+ other content. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-24">DNA-24</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Data Definition Language (DDL) Sequencer</emphasis>
+ - Process various dialects of DDL, including that from Oracle, SQL Server, MySQL, PostgreSQL, and others. May need
+ to be split up into a different sequencer for each dialect. (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ulink>
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">MP3 and MP4 Sequencer</emphasis>
+ - Process MP3 and MP4 audio files to extract the name of the song, artist, album, track number, and other metadata.
+ (See
+ <ulink url="http://jira.jboss.org/jira/browse/DNA-30">DNA-30</ulink>
+ )
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The
+ <link linkend="using_dna">examples</link>
+ in this book go into more detail about how sequencers are managed and used, and
+ <link linkend="custom_sequencers">Chapter 5</link>
+ goes into detail about how to write custom sequencers.
+ </para>
+ </sect1>
+ <sect1 id="federation">
+ <title>Federating content</title>
+ <para>There is a lot of information stored in many of different places: databases, repositories, SCM systems,
+ registries, file systems, services, etc. The purpose of the federation engine is to allow applications to use the JCR API
+ to access that information as if it were all stored in a single JCR repository, but to really leave the information where
+ it is.</para>
+ <para>Why not just move the information into a JCR repository? Most likely there are existing applications that rely upon
+ that information being where it is. If we were to move it, then all those applications would break. Or they'd have to be
+ changed to use JCR. If the information is being used, the most practical thing is to leave it where it is.</para>
+ <para>
+ Then why not just copy the information into a JCR repository? Actually, there are times when it's perfectly reasonable to
+ make a copy of the data. Perhaps the system managing the existing information cannot handle the additional load of more
+ clients. Or, perhaps the information doesn't change, or it does change and we want snapshots that don't change. But more
+ likely, the data
+ <emphasis>does</emphasis>
+ change. So if applications are to use the most current information and we make copies of the data, we have to keep the
+ copies synchronized with the master. That's generally a lot of work.
+ </para>
+ <para>The JBoss DNA federation engine lets us leave the information where it is, yet lets client applications use the JCR
+ API to access all the information without caring where the information really exists. If the underlying information
+ changes, client applications using JCR observation will be notified of the changes. If a JBoss DNA federated repository is
+ configured to allow updates, client applications can change the information in the repository and JBoss DNA will propagate
+ those changes down to the original source.</para>
+ <sect2 id="federation_connectors">
+ <title>Connecting to information sources</title>
+ <para>
+ The JBoss DNA federation engine will use connectors to interact with different information sources to get at the content
+ in those systems. Some ideas for connectors include:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">JCR Repository Connector</emphasis>
+ - Connect to and interact with other JCR repositories.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">File System Connector</emphasis>
+ - Expose the files and directories on a file system through JCR.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Maven 2 Repository Connector</emphasis>
+ - Access and expose the contents of a Maven 2 repository (either on the local file system or via HTTP) through
+ JCR.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">JDBC Metadata Connector</emphasis>
+ - Connect to relational databases via JDBC and expose their schema as content in a repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">UDDI Connector</emphasis>
+ - Interact with UDDI registries to integrate their content into a repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">SVN Connector</emphasis>
+ - Interact with Subversion software configuration management (SCM) repositories to expose the managed resources
+ through JCR. Consider using the
+ <ulink url="http://svnkit.com/">SVNkit</ulink>
+ (dual license) library for an API into Subversion.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">CVS Connector</emphasis>
+ - Interact with CVS software configuration management (SCM) repositories to expose the managed resources through
+ JCR.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">JDBC Storage Connector</emphasis>
+ - Store and access information in a relational database. Also useful for persisting information in the federated
+ repository not stored elsewhere.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Distributed Database Connector</emphasis>
+ - Store and access information in a
+ <ulink url="http://www.hypertable.org/">Hypertable</ulink>
+ or
+ <ulink url="http://hadoop.apache.org/hbase/">HBase</ulink>
+ distributed databases. Also useful for persisting information in the federated repository not stored elsewhere.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ If the connectors allow the information they contribute to be updated, they must provide an
+ <code>XAResource</code>
+ implementation that can be used with a Java Transaction Service. Connectors that provide read-only access need not
+ provide an implementation.
+ </para>
+ <para>
+ Also, connectors talk to
+ <emphasis>sources</emphasis>
+ of information, and it's quite likely that the same connector is used to talk to different sources. Each source contains
+ the configuration details (e.g., connection information, location, properties, options, etc.) for working with that
+ particular source, as well as a reference to the connector that should be used to establish connections to the source.
+ And of course, sources can be added or removed without having to stop and restart the federated repository.
+ </para>
+ </sect2>
+ <sect2 id="federation_graph">
+ <title>Building the unified graph</title>
+ <para> The federation engine works by effectively building up a single graph by querying each source and merging or
+ unifying the responses. This information is cached, which improves performance, reduces the number of (potentially
+ expensive) remote calls, reduces the load on the sources, and helps mitigate problems with source availability. As
+ clients interact with the repository, this cache is consulted first. When the requested portion of the graph (or
+ "subgraph") is contained completely in the cache, it is retuned immediately. However, if any part of the requested
+ subgraph is not in the cache, each source is consulted for their contributions to that subgraph, and any results are
+ cached.</para>
+ <para> This basic flow makes it possible for the federated repository to build up a local cache of the integrated graph
+ (or at least the portions that are used by clients). In fact, the federated repository caches information in a manner
+ that is similar to that of the Domain Name System (DNS). As sources are consulted for their contributions, the source
+ also specifies whether it is the authoritative source for this information (some sources that are themselves federated
+ may not be the information's authority), whether the information may be modified, the time-to-live (TTL) value (the time
+ after which the cached information should be refreshed), and the expiration time (the time after which the cached
+ information is no longer valid). In effect, the source has complete control over how the information it contributes is
+ cached and used.</para>
+ <para>
+ The federated repository also needs to incorporate
+ <emphasis>negative caching</emphasis>
+ , which is storage of the knowledge that something does not exist. Sources can be configured to contribute information
+ only below certain paths (e.g.,
+ <code>/A/B/C</code>
+ ), and the federation engine can take advantage of this by never consulting that source for contributions to information
+ on other paths. However, below that path, any negative responses must also be cached (with appropriate TTL and expiry
+ parameters) to prevent the exclusion of that source (in case the source has information to contribute at a later time)
+ or the frequent checking with the source.
+ </para>
+ </sect2>
+ <sect2 id="federation_queries">
+ <title>Searching and querying</title>
+ <para> The JBoss DNA federated repository will also support queries against the integrated and unified graph. In some
+ situations the query can be determined to apply to a single source, but in most situations the query must be planned
+ (and possibly rewritten) such that it can be pushed down to all the appropriate sources. Also, the cached results must
+ be consulted prior to returning the query results, as the results from one source might have contributions from another
+ source.</para>
+ <note>
+ <para> It is hoped that the MetaMatrix query engine can be used for this purpose after it is open-sourced. This engine
+ implements sophisticated query planning and optimization techniques for working efficiently with multiple sources.
+ </para>
+ </note>
+ <para>Searching the whole federated repository is also important. This allows users to simply supply a handful of
+ search terms, and to get results that are ranked based upon how close each result is to the search terms. (Searching is
+ very different from querying, which involves specifying the exact semantics of what is to be searched and how the
+ information is to be compared.) JBoss DNA will incorporate a search engine (e.g., likely to be Lucene) and will populate
+ the engine's indexes using the federated content and the cached information. Notifications of changing information will
+ be reflected in the indexes, but some sources may want to explicitly allow or disallow periodic crawling of their
+ content.</para>
+ </sect2>
+ <sect2 id="federation_updates">
+ <title>Updating content</title>
+ <para>
+ The JBoss DNA federated repositories also make it possible for client applications to make changes to the unified graph
+ within the context of distributed transactions. According to the JCR API, client applications use the Java Transaction
+ API (JTA) to control the boundaries of their transactions. Meanwhile, the federated repository uses a
+ <ulink url="http://www.jboss.org/jbosstm/">distributed transaction service</ulink>
+ to coordinate the XA resources provided by the connectors.
+ </para>
+ <para> It is quite possible that clients add properties to nodes in the unified graph, and that this information cannot be
+ handled by the same underlying source that contributed to the node. In this case, the federated repository can be
+ configured with a fallback source that will be used used to store this "extra" information.</para>
+ <para>
+ It is a goal that non-XA sources (i.e., sources that use connectors without XA resources) can participate in distributed
+ transactions through the use of
+ <emphasis>compensating transactions</emphasis>
+ . Because the JBoss DNA federation engine implements the JCR observation system, it is capable of recording all of the
+ changes made to the distributed graph (and those changes sent to each updatable source). Therefore, if a non-XA source
+ is involved in a distributed transaction that must be rolled back, any changes made to non-XA sources can be undone. (Of
+ course, this does not make the underlying source transactional: non-transactional sources still may expose the interim
+ changes to other clients.)
+ </para>
+ </sect2>
+ <sect2 id="federation_events">
+ <title>Observing changes</title>
+ <para> The JCR API supports observing a repository to receive notifications of additions, changes and deletions of nodes
+ and properties. The JBoss DNA federated repository will support this API through two primary means.</para>
+ <para> When the changes are made through the federated repository, the JBoss DNA federation engine is well aware of the
+ set of changes that have been (or are being) made to the unified graph. These events are directly propagated to
+ listeners.</para>
+ <para> Sources have the ability to publish events, making it possible for the JBoss DNA federation engine and clients that
+ have registered listeners to be notified of changes in the information managed by that source. These events are first
+ processed by the federation engine and possibly altered based upon contributions from other sources. (The federation
+ engine also uses these events to update or purge information in the cache, which may add to the event set.) The
+ resulting (and possibly altered) event set is then sent to all client listeners.</para>
+ </sect2>
+ </sect1>
+ </chapter>
+ <!-- ====================================================================================================
+ Chapter
+ ==================================================================================================== -->
+ <chapter id="downloading_and_running">
+ <title>Running the example application</title>
+ <para>
+ This chapter provides instructions for downloading and running a sample application that demonstrates how JBoss DNA works
+ with a JCR repository to automatically sequence changing content to extract useful information. So read on to get the simple
+ application running, and then in the
+ <link linkend="using_dna">next chapter</link>
+ we'll dive into the source code for the example and show how to use JBoss DNA in your own applications.
+ </para>
+ <para>JBoss DNA uses Maven 2 for its build system, as is this example. Using Maven 2 has several advantages, including
+ the ability to manage dependencies. If a library is needed, Maven automatically finds and downloads that library, plus
+ everything that library needs. This means that it's very easy to build the examples - or even create a maven project that
+ depends on the JBoss DNA JARs.</para>
+ <note>
+ <para>
+ To use Maven with JBoss DNA, you'll need to have
+ <ulink url="http://java.sun.com/javase/downloads/index_jdk5.jsp">JDK 5 or 6</ulink>
+ and Maven 2.0.7 (or higher).
+ </para>
+ <para>
+ Maven can be downloaded from
+ <ulink url="http://maven.apache.org/">http://maven.apache.org/</ulink>
+ , and is installed by unzipping the
+ <code>maven-2.0.7-bin.zip</code>
+ file to a convenient location on your local disk. Simply add
+ <code>$MAVEN_HOME/bin</code>
+ to your path and add the following profile to your
+ <code>~/.m2/settings.xml</code>
+ file:
+ <programlisting role="XML" language="xml"><settings>
+ <profiles>
+ <profile>
+ <id>jboss.repository</id>
+ <activation>
+ <property>
+ <name>!jboss.repository.off</name>
+ </property>
+ </activation>
+ <repositories>
+ <repository>
+ <id>snapshots.jboss.org</id>
+ <url>http://snapshots.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>repository.jboss.org</id>
+ <url>http://repository.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>repository.jboss.org</id>
+ <url>http://repository.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </pluginRepository>
+ <pluginRepository>
+ <id>snapshots.jboss.org</id>
+ <url>http://snapshots.jboss.org/maven2</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+ </profile>
+ </profiles>
+</settings></programlisting>
+ This profile informs Maven of the two JBoss repositories (snapshots and releases) that contain
+ all of the JARs for JBoss DNA and all dependent libraries.</para>
+ </note>
+ <sect1 id="downloading">
+ <title>Downloading and compiling</title>
+ <para>The next step is to <ulink url="http://www.jboss.org/file-access/default/members/dna/downloads/0.1/jboss-...">download</ulink>
+ the example for this Getting Started guide, and extract the contents to a convenient location on your local disk.
+ You'll find the example contains the following files, which are organized according to the standard Maven directory structure:
+ <programlisting>
+examples/pom.xml
+ sequencers/pom.xml
+ /src/main/assembly
+ /config
+ /java
+ /resources
+ /test/java
+ /resources
+ </programlisting>
+ </para>
+ <para>There are essentially two Maven projects: a <code>sequencers</code> project and a parent project. All of the source
+ for the example is located in the <code>sequencers</code> subdirectory. And you may have noticed that none
+ of the JBoss DNA libraries are there. This is where Maven comes in. The two <code>pom.xml</code> files tell
+ Maven everything it needs to know about what libraries are required and how to build the example.</para>
+ <para>In a terminal, go to the <code>examples</code> directory and run <emphasis role="strong"><code>mvn install</code></emphasis>.
+ This command downloads all of the JARs necessary to compile and build the example, including the JBoss DNA libraries,
+ the libraries they depend on, and any missing Maven components. (These are downloaded from the JBoss repositories
+ only once and saved on your machine. This means that the next time you run Maven, all the libraries will
+ already be available locally, and the build will run much faster.) The command then continues by compiling the example's source
+ code (and unit tests) and running the unit tests. The build is successful if you see the following:
+ <programlisting language="bash">$ mvn install
+...
+[INFO] ------------------------------------------------------------------------
+[INFO] Reactor Summary:
+[INFO] ------------------------------------------------------------------------
+[INFO] Getting Started examples .............................. SUCCESS [2.106s]
+[INFO] Sequencer Examples .................................... SUCCESS [9.768s]
+[INFO] ------------------------------------------------------------------------
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD SUCCESSFUL
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 12 seconds
+[INFO] Finished at: Wed May 07 12:00:06 CDT 2008
+[INFO] Final Memory: 14M/28M
+[INFO] ------------------------------------------------------------------------
+$ </programlisting>
+ If there are errors, check whether you have the correct version of Maven installed and that you've correctly updated
+ your Maven settings as described above.</para>
+ <para>If you've successfully built the examples, there will be a <code>examples/sequencers/target/dna-example-sequencers-basic.dir/</code>
+ directory that contains the following:
+ <itemizedlist>
+ <listitem>
+ <para><emphasis role="strong"><code>run.sh</code></emphasis> is the *nix shell script that will run the example.</para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">
+ <code>log4j.properties</code>
+ </emphasis>
+ is the Log4J configuration file.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">
+ <code>jackrabbitConfig.xml</code>
+ </emphasis>
+ is the Jackrabbit configuration file, which is set up to use a transient in-memory repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">
+ <code>jackrabbitNodeTypes.cnd</code>
+ </emphasis>
+ defines the additional JCR node types used by this example.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">
+ <code>sample1.mp3</code>
+ </emphasis>
+ is a sample MP3 audio file you'll use later to upload into the repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">
+ <code>caution.gif</code>
+ </emphasis>, <emphasis role="strong">
+ <code>caution.png</code>
+ </emphasis>, and <emphasis role="strong">
+ <code>caution.jpg</code>
+ </emphasis>
+ are images that you'll use later and upload into the repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">
+ <code>lib</code>
+ </emphasis>
+ subdirectory contains the JARs for all of the JBoss DNA artifacts as well as those for other libraries required
+ by JBoss DNA and the example.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <note>
+ <para>JBoss DNA 0.1 and the examples are currently tested with <ulink url="http://jackrabbit.apache.org/">Apache Jackrabbit</ulink> version 1.3.3.
+ This version is stable and used by a number of other projects and applications. However, you should be able to use a newer
+ version of Jackrabbit, as long as that version uses the same JCR API. For example, version 1.4.2 was released on March 26, 2008 and
+ should be compatible.
+ </para>
+ <para>Just remember, if the version of Jackrabbit you want to use for these examples is not in the Maven repository,
+ you'll have to either add it or add it locally. For more information, see the <ulink url="http://maven.apache.org/">Maven documentation</ulink>.
+ </para>
+ </note>
+ </para>
+ </sect1>
+ <sect1 id="running">
+ <title>Running the example</title>
+ <para>This example consists of a client application that sets up an in-memory JCR repository and that allows a user to
+ upload files into that repository. The client also sets up the DNA services with two sequencers so that if any of the
+ uploaded files are PNG, JPEG, GIF, BMP or other images, DNA will automatically extract the image's metadata (e.g., image
+ format, physical size, pixel density, etc.) and store that in the repository. Alternatively, if the uploaded file
+ is an MP3 audio file, DNA will extract some of the ID3 metadata (e.g., the author, title, album, year and comment)
+ and store that in the repository.</para>
+ <para>
+ To run the client application, go to the
+ <code>examples/sequencers/target/dna-example-sequencers-basic.dir/
+ </code>
+ directory and type
+ <code>./run.sh</code>
+ . You should see the command-line client and its menus in your terminal:
+ <figure id="xample-sequencer-cli-client">
+ <title>Example Client</title>
+ <graphic align="center" scale="100" fileref="images/example-sequencer-cli-client.png" />
+ </figure>
+ From this menu, you can upload a file into the repository, search for media in the repository, print sequencing statistics,
+ or quit the application.
+ </para>
+ <para>
+ The first step is to upload one of the example images. If you type 'u' and press return, you'll be prompted to supply the
+ path to the file you want to upload. Since the application is running from within the
+ <code>examples/sequencers/target/dna-example-sequencers-basic.dir/
+ </code>
+ directory, you can specify any of the files in that directory without specifying the path:
+ <figure id="example-sequencer-upload">
+ <title>Uploading an image using the Example Client</title>
+ <graphic align="center" scale="100" fileref="images/example-sequencer-upload.png" />
+ </figure>
+ You can specify any fully-qualified or relative path. The application will notify you if it cannot find the file you
+ specified. The example client configures JBoss DNA to sequence and MP3 audio files and image files with one of
+ the following extensions (technically, nodes that have names ending in the following):
+ <code>jpg</code>
+ ,
+ <code>jpeg</code>
+ ,
+ <code>gif</code>
+ ,
+ <code>bmp</code>
+ ,
+ <code>pcx</code>
+ ,
+ <code>png</code>
+ ,
+ <code>iff</code>
+ ,
+ <code>ras</code>
+ ,
+ <code>pbm</code>
+ ,
+ <code>pgm</code>
+ ,
+ <code>ppm</code>
+ , and
+ <code>psd</code>
+ . Files with other extensions in the repository path will be ignored. For your convenience, the example provides several
+ files that will be sequenced (
+ <code>caution.png</code>
+ ,
+ <code>caution.jpg</code>
+ ,
+ <code>caution.gif</code>
+ , and
+ <code>sample1.mp3</code>
+ ) and one image that will not be sequenced (
+ <code>caution.pict</code>
+ ). Feel free to try other files.
+ </para>
+ <para>
+ After you have specified the file you want to upload, the example application asks you where in the repository you'd like to
+ place the file. (If you want to use the suggested location, just press
+ <code>return</code>
+ .) The client application uses the JCR API to upload the file to that location in the repository, creating any nodes (of
+ type
+ <code>nt:folder</code>
+ ) for any directories that don't exist, and creating a node (of type
+ <code>nt:file</code>
+ ) for the file. And, per the JCR specification, the application creates a
+ <code>jcr:content</code>
+ node (of type
+ <code>nt:resource</code>
+ ) under the file node. The file contents are placed on this
+ <code>jcr:content</code>
+ node in the
+ <code>jcr:data</code>
+ property. For example, if you specify
+ <code>/a/b/caution.png</code>
+ , the following structure will be created in the repository:<programlisting>
+ /a (nt:folder)
+ /b (nt:folder)
+ /caution.png (nt:file)
+ /jcr:content (nt:resource)
+ @jcr:data = {contents of the file}
+ @jcr:mimeType = {mime type of the file}
+ @jcr:lastModified = {now}
+ </programlisting>
+ Other kinds of files are treated in a similar way.
+ </para>
+ <para>
+ When the client uploads the file using the JCR API, DNA gets notified of the changes, consults the sequencers to see whether
+ any of them are interested in the new or updated content, and if so runs those sequencers. The image sequencer processes image
+ files for metadata, and any metadata found is stored under the
+ <code>/images</code>
+ branch of the repository. The MP3 sequencer processes MP3 audio files for metadata, and any metadata found is stored under the
+ <code>/mp3s</code>
+ branch of the repository. All of this happens asynchronously, so any DNA activity doesn't impede or slow down the client
+ activities.
+ </para>
+ <para>
+ So, after the file is uploaded, you can search the repository for the image metadata using the "s" menu option:
+ <figure id="example-sequencer-search">
+ <title>Searching for media using the Example Client</title>
+ <graphic align="center" scale="100" fileref="images/example-sequencer-search.png" />
+ </figure>
+ Here are the search results after the <code>sample1.mp3</code> audio file has been uploaded (to the <code>/a/b/sample1.mp3</code> location):
+ <figure id="example-sequencer-search-with-mp3">
+ <title>Searching for media using the Example Client</title>
+ <graphic align="center" scale="100" fileref="images/example-sequencer-search-with-mp3.png" />
+ </figure>
+ You can also display the sequencing statistics using the "d" menu option:
+ <figure id="example-sequencer-statistics">
+ <title>Sequencing statistics using the Example Client</title>
+ <graphic align="center" scale="100" fileref="images/example-sequencer-statistics.png" />
+ </figure>
+ These stats show how many nodes were sequenced, and how many nodes were skipped because they didn't apply to the sequencer's
+ criteria.
+ </para>
+ <note>
+ <para>
+ There will probably be more nodes skipped than sequenced, since there are more
+ <code>nt:folder</code>
+ and
+ <code>nt:resource</code>
+ nodes than there are
+ <code>nt:file</code>
+ nodes with acceptable names.
+ </para>
+ </note>
+ <para>You can repeat this process with other files. Any file that isn't an image or MP3 files (as recognized by the sequencing configurations
+ that we'll describe later) will not be sequenced.</para>
+ </sect1>
+ <sect1 id="downloading_and_running_review">
+ <title>Summarizing what we just did</title>
+ <para>In this chapter you downloaded and installed the example application and used it to upload files into a
+ JCR repository. JBoss DNA automatically sequenced the image and/or MP3 files you uploaded, extracted the metadata from the
+ files, and stored that metadata inside the repository. The application allowed you to see this metadata
+ and the sequencing statistics.</para>
+ <para>This application was very simplistic. In fact, running through the example probably only took you a minute or two.
+ So while this application won't win any awards, it does show the basics of what JBoss DNA can do.</para>
+ <para>In the <link linkend="using_dna">next chapter</link> we'll venture into the code to get an understanding
+ of how JBoss DNA actually works and how you can use it in your own applications.</para>
+ </sect1>
+ </chapter>
+
+ <!-- ====================================================================================================
+ Chapter
+ ==================================================================================================== -->
+<chapter id="using_dna">
+ <title>Using JBoss DNA</title>
+ <para>As we've mentioned before, JBoss DNA is able to work with existing JCR repositories. Your client applications
+ make changes to the information in those repositories, and JBoss DNA automatically uses its sequencers to extract
+ additional information from the uploaded files.</para>
+ <note>
+ <para>Configuring JBoss DNA sequencers is a bit more manual than is ideal. As you'll see, JBoss DNA uses dependency
+ injection to allow a great deal of flexibility in how it can be configured and customized. However, the next release will
+ provide a much easier mechanism for configuring not only the sequencer service but also the upcoming federation engine and
+ JCR implementation.</para>
+ </note>
+ <sect1 id="sequencing_service">
+ <title>Configuring the Sequencing Service</title>
+ <para>
+ The JBoss DNA <emphasis>sequencing service</emphasis> is the component that manages the <emphasis>sequencers</emphasis>
+ , reacting to changes in JCR repositories and then running the appropriate sequencers.
+ This involves processing the changes on a node, determining which (if any) sequencers should be run on that node,
+ and for each sequencer constructing the execution environment, calling the sequencer, and saving the information
+ generated by the sequencer.</para>
+ <para>To set up the sequencing service, an instance is created, and dependent components are injected into
+ the object. This includes among other things:
+ <itemizedlist>
+ <listitem>
+ <para>An <emphasis>execution context</emphasis> that defines the context in which the service runs, including
+ a factory for JCR sessions given names of the repository and workspace. This factory must be configured,
+ and is how JBoss DNA knows about your JCR repositories and how to connect to them. More on this a bit later.</para>
+ </listitem>
+ <listitem>
+ <para>An optional <emphasis>factory for class loaders</emphasis> used to load sequencers. If no factory is supplied,
+ the service uses the current thread's context class loader (or if that is null, the class loader that loaded the
+ sequencing service class).</para>
+ </listitem>
+ <listitem>
+ <para>An <code>java.util.concurrent.ExecutorService</code> used to execute the sequencing activites. If none
+ is supplied, a new single-threaded executor is created by calling <code>Executors.newSingleThreadExecutor()</code>.
+ (This can easily be changed by subclassing and overriding the <code>SequencerService.createDefaultExecutorService()</code> method.)</para>
+ </listitem>
+ <listitem>
+ <para>Filters for sequencers and events. By default, all sequencers are considered for "node added", "property added"
+ and "property changed" events.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>As mentioned above, the <code>ExecutionContext</code> provides access to a <code>SessionFactory</code> that is used
+ by JBoss DNA to establish sessions to your JCR repositories. Two implementations are available:
+ <itemizedlist>
+ <listitem>
+ <para>The <code>JndiSessionFactory</code> looks up JCR <code>Repository</code> instances in JNDI using
+ names that are supplied when creating sessions. This implementation also has methods to set the
+ JCR <code>Credentials</code> for a given workspace name.</para>
+ </listitem>
+ <listitem>
+ <para>The <code>SimpleSessionFactory</code> has methods to register the JCR <code>Repository</code> instances
+ with names, as well as methods to set the JCR <code>Credentials</code> for a given workspace name.</para>
+ </listitem>
+ </itemizedlist>
+ You can use the <code>SimpleExecutionContext</code> implementation of <code>ExecutionContext</code> and supply
+ a <code>SessionFactory</code> instance, or you can provide your own implementation.
+ </para>
+ <para>Here's an example of how to instantiate and configure the SequencingService:
+ <programlisting>
+SimpleSessionFactory sessionFactory = new SimpleSessionFactory();
+sessionFactory.registerRepository("Main Repository", this.repository);
+Credentials credentials = new SimpleCredentials("jsmith", "secret".toCharArray());
+sessionFactory.registerCredentials("Main Repository/Workspace1", credentials);
+ExecutionContext executionContext = new SimpleExecutionContext(sessionFactory);
+
+// Create the sequencing service, passing in the execution context ...
+SequencingService sequencingService = new SequencingService();
+sequencingService.setExecutionContext(executionContext);</programlisting>
+ </para>
+ <para>After the sequencing service is created and configured, it must be started. The SequencingService
+ has an <emphasis>administration object</emphasis> (that is an instance of <code>ServiceAdministrator</code>)
+ with <code>start()</code>, <code>pause()</code>, and <code>shutdown()</code> methods. The latter method will
+ close the queue for sequencing, but will allow sequencing operations already running to complete normally.
+ To wait until all sequencing operations have completed, simply call the <code>awaitTermination</code> method
+ and pass it the maximum amount of time you want to wait.</para>
+ <para>
+ <programlisting>
+sequencingService.getAdministrator().start();</programlisting>
+ </para>
+ <para>The sequencing service must also be configured with the sequencers that it will use. This is done using the
+ <code>addSequencer(SequencerConfig)</code> method and passing a <code>SequencerConfig</code> instance that
+ you create. Here's an example:
+ <programlisting>
+String name = "Image Sequencer";
+String desc = "Sequences image files to extract the characteristics of the image";
+String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
+String[] classpath = null; // Use the current classpath
+String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png))[*]/jcr:content[@jcr:data] => /images/$1"};
+SequencerConfig imageSequencerConfig = new SequencerConfig(name, desc, classname, classpath, pathExpressions);
+sequencingService.addSequencer(imageSequencerConfig);
+
+name = "Mp3 Sequencer";
+desc = "Sequences mp3 files to extract the id3 tags of the audio file";
+classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
+String[] mp3PathExpressions = {"//(*.mp3)[*]/jcr:content[@jcr:data] => /mp3s/$1"};
+SequencerConfig mp3SequencerConfig = new SequencerConfig(name, desc, classname, classpath, mp3PathExpressions);
+sequencingService.addSequencer(mp3SequencerConfig);</programlisting>
+ This is pretty self-explanatory, except for the <code>classpath</code> and <code>pathExpression</code> parameters.
+ The classpath parameter defines the classpath that is passed to the class loader factory mentioned above.
+ Our sequencer is on the classpath, so we can simply use <code>null</code> here.
+ </para>
+ <para>The path expression is more complicated. Sequencer path expressions are used by the sequencing service to
+ determine whether a particular changed node should be sequenced. The expressions consist of two parts: a selection
+ criteria and an output expression. Here's a simple example:
+ <programlisting>
+/a/b/c@title => /d/e/f</programlisting>
+ Here, the <code>/a/b/c@title</code> is the selection criteria that applies when the <code>/a/b/c</code> node has a <code>title</code> property
+ that is added or changed. When the selection criteria matches a change event, the sequencer will be run
+ and any generated output will be inserted into the repository described by the output expression. In this example,
+ the generated output would be placed at the <code>/d/e/f</code> node.
+ </para>
+ <note>
+ <para>Sequencer path expressions can be fairly complex and may use wildcards, specificy same-name sibling indexes,
+ provide optional and choice elements, and may capture parts of the selection criteria for use in the output expression.
+ The path expression used in the image sequencer configuration example above shows a more complex example:
+ <programlisting>
+//(*.(jpg|jpeg|gif|bmp|pcx|png))[*]/jcr:content[@jcr:data] => /images/$1</programlisting>
+ This uses "//" to select any node at any level in the repository whose name ends with "." and one of the extensions (e.g., ".jpg", ".jpeg", etc.)
+ and that has a child node named "jcr:content" that has a "jcr:data" property. It also selects the file name
+ as the first capture group (the first set of parentheses) for use in the output expression.
+ In this example, any sequencer output is placed on a node with that same file name under the "/images" node.
+ </para>
+ <para></para>
+ <para>Other things are possible, too. For example, the name of the repository/workspace (as used by the <code>SessionFactory</code>)
+ may be specified at the beginning of the select criteria and/or the output expression. This means it's possible to place
+ the sequencer output in a different repository than the node being sequenced.</para>
+ <para>For more detail about sequencer path expressions, see the <code>org.jboss.dna.repository.sequencer.SequencerPathExpression</code>
+ class and the corresponding <code>org.jboss.dna.repository.sequencer.SequencerPathExpressionTest</code> test case.</para>
+ </note>
+ <para>After the service is started, it is ready to start reacting to changes in the repository. But it first
+ must be wired to the repositories using a listener. This is accomplished using the <code>ObservationService</code>
+ described in the <link linkend="observation_service">next section</link>.</para>
+ </sect1>
+ <sect1 id="observation_service">
+ <title>Configuring the Observation Service</title>
+ <para>The JBoss DNA <code>ObservationService</code> is responsible for listening to one or more JCR repositories
+ and multiplexing the events to its listeners. Unlike JCR events, this framework embeds in the events the
+ name of the repository and workspace that can be passed to a <code>SessionFactory</code> to obtain a session
+ to the repository in which the change occurred. This simple design makes it very easy for JBoss DNA to
+ concurrently work with multiple JCR repositories.</para>
+ <para>Configuring an observation service is pretty easy, especially if you reuse the same <code>SessionFactory</code>
+ supplied to the sequencing service. Here's an example:
+ <programlisting>
+this.observationService = new ObservationService(sessionFactory);
+this.observationService.getAdministrator().start();</programlisting>
+ </para>
+ <note>
+ <para>Both <code>ObservationService</code> and <code>SequencingService</code> implement
+ <code>AdministeredService</code>, which has a <code>ServiceAdministrator</code> used to start, pause, and shutdown the
+ service. In other words, the lifecycle of the services are managed in the same way.</para>
+ </note>
+ <para>
+ After the observation service is started, listeners can be added. The <code>SequencingService</code> implements the required
+ interface, and so it may be registered directly:
+ <programlisting>
+observationService.addListener(sequencingService);</programlisting>
+ </para>
+ <para>Finally, the observation service must be wired to monitor one of your JCR repositories. This is done with
+ one of the <code>monitor(...)</code> methods:
+ <programlisting>
+int eventTypes = Event.NODE_ADDED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED;
+observationService.monitor("Main Repository/Workspace1", eventTypes);</programlisting>
+ </para>
+ <para>At this point, the observation service is listening to a JCR repository and forwarding the appropriate events
+ to the sequencing service, which will asynchronously process the changes and sequence the information added to or changed in the repository.
+ </para>
+ </sect1>
+ <sect1 id="shutting_down">
+ <title>Shutting down JBoss DNA services</title>
+ <para>The JBoss DNA services are utilizing resources and threads that must be released before your application is ready to shut down.
+ The safe way to do this is to simply obtain the <code>ServiceAdministrator</code> for each service (via the <code>getServiceAdministrator()</code> method)
+ and call <code>shutdown()</code>. As previously mentioned, the shutdown method will simply prevent new work from being processed
+ and will not wait for existing work to be completed. If you want to wait until the service completes all its work, you must wait
+ until the service terminates. Here's an example that shows how this is done:
+ <programlisting>
+// Shut down the service and wait until it's all shut down ...
+sequencingService.getAdministrator().shutdown();
+sequencingService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
+
+// Shut down the observation service ...
+observationService.getAdministrator().shutdown();
+observationService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);</programlisting>
+ </para>
+ <para>At this point, we've covered how to configure and use the JBoss DNA services in your application.
+ The next chapter goes back to the <link linkend="downloading_and_running">sample application</link> to show how all these pieces fit together.</para>
+ </sect1>
+ <sect1 id="example_application_review">
+ <title>Reviewing the example application</title>
+ <para>Recall that the example application consists of a client application that sets up an in-memory JCR repository and
+ that allows a user to upload files into that repository. The client also sets up the DNA services with an image sequencer so
+ that if any of the uploaded files are PNG, JPEG, GIF, BMP or other images, DNA will automatically extract the image's
+ metadata (e.g., image format, physical size, pixel density, etc.) and store that in the repository. Or, if the client uploads
+ MP3 audio files, the title, author, album, year, and comment are extracted from the audio file and stored in the repository.</para>
+ <para>
+ The example is comprised of 3 classes and 1 interface, located in the
+ <code>src/main/java</code>
+ directory:
+ <programlisting>
+ org/jboss/example/dna/sequencers/ConsoleInput.java
+ /MediaInfo.java
+ /SequencingClient.java
+ /UserInterface.java</programlisting>
+ </para>
+ <para>
+ <code>SequencingClient</code>
+ is the class that contains the main application.
+ <code>MediaInfo</code>
+ is a simple Java object that encapsulates metadata about a media file (as generated by the sequencer), and used by the client to
+ pass information to the
+ <code>UserInterface</code>
+ , which is an interface with methods that will be called at runtime to request data from the user.
+ <code>ConsoleInput</code>
+ is an implementation of this that creates a text user interface, allowing the user to operate the client from the command-line.
+ We can easily create a graphical implementation of
+ <code>UserInterface</code>
+ at a later date. We can also create a mock implementation for testing purposes that simulates a user entering data. This
+ allows us to check the behavior of the client automatically using conventional JUnit test cases, as demonstrated by the
+ code in the
+ <code>src/test/java</code>
+ directory:
+ <programlisting>
+ org/jboss/example/dna/sequencers/SequencingClientTest.java
+ /MockUserInterface.java</programlisting>
+ </para>
+ <para>
+ If we look at the
+ <code>SequencingClient</code>
+ code, there are a handful of methods that encapsulate the various activities.
+ </para>
+ <note>
+ <para>To keep the code shown in this book as readable as possible, some of the comments and error handling
+ have been removed.</para>
+ </note>
+ <para>
+ The
+ <code>startRepository()</code>
+ method starts up an in-memory Jackrabbit JCR repository. The bulk of this method is simply gathering and passing the
+ information required by Jackrabbit. Because Jackrabbit's
+ <code>TransientRepository</code>
+ implementation shuts down after the last session is closed, the application maintains a session to ensure that the
+ repository remains open throughout the application's lifetime. And finally, the node type needed by the image sequencer is
+ registered with Jackrabbit.
+ </para>
+ <programlisting>
+public void startRepository() throws Exception {
+ if (this.repository == null) {
+ try {
+
+ // Load the Jackrabbit configuration ...
+ File configFile = new File(this.jackrabbitConfigPath);
+ String pathToConfig = configFile.getAbsolutePath();
+
+ // Find the directory where the Jackrabbit repository data will be stored ...
+ File workingDirectory = new File(this.workingDirectory);
+ String workingDirectoryPath = workingDirectory.getAbsolutePath();
+
+ // Get the Jackrabbit custom node definition (CND) file ...
+ URL cndFile = Thread.currentThread().getContextClassLoader().getResource("jackrabbitNodeTypes.cnd");
+
+ // Create the Jackrabbit repository instance and establish a session to keep the repository alive ...
+ this.repository = new TransientRepository(pathToConfig, workingDirectoryPath);
+ if (this.username != null) {
+ Credentials credentials = new SimpleCredentials(this.username, this.password);
+ this.keepAliveSession = this.repository.login(credentials, this.workspaceName);
+ } else {
+ this.keepAliveSession = this.repository.login();
+ }
+
+ try {
+ // Register the node types (only valid the first time) ...
+ JackrabbitNodeTypeManager mgr = (JackrabbitNodeTypeManager)this.keepAliveSession.getWorkspace().getNodeTypeManager();
+ mgr.registerNodeTypes(cndFile.openStream(), JackrabbitNodeTypeManager.TEXT_X_JCR_CND);
+ } catch (RepositoryException e) {
+ if (!e.getMessage().contains("already exists")) throw e;
+ }
+
+ } catch (Exception e) {
+ this.repository = null;
+ this.keepAliveSession = null;
+ throw e;
+ }
+ }
+}</programlisting>
+ <para>As you can see, this method really has nothing to do with JBoss DNA, other than setting up a JCR repository that JBoss
+ DNA will use.</para>
+ <para>
+ The
+ <code>shutdownRepository()</code>
+ method shuts down the Jackrabbit transient repository by closing the "keep-alive session". Again, this method really does
+ nothing specifically with JBoss DNA, but is needed to manage the JCR repository that JBoss DNA uses.
+ <programlisting>
+public void shutdownRepository() throws Exception {
+ if (this.repository != null) {
+ try {
+ this.keepAliveSession.logout();
+ } finally {
+ this.repository = null;
+ this.keepAliveSession = null;
+ }
+ }
+}</programlisting>
+ </para>
+ <para>
+ The
+ <code>startDnaServices()</code>
+ method first starts the JCR repository (if it was not already started), and proceeds to create and configure the
+ <code>SequencingService</code>
+ as described
+ <link linkend="sequencing_service">earlier</link>
+ . This involes setting up the
+ <code>SessionFactory</code>
+ and
+ <code>ExecutionContext</code>
+ , creating the
+ <code>SequencingService</code>
+ instance, and configuring the image sequencer. The method then continues by setting up the
+ <code>ObservationService</code>
+ as described
+ <link linkend="observation_service">earlier</link>
+ and starting the service.
+ <programlisting>
+public void startDnaServices() throws Exception {
+ if (this.repository == null) this.startRepository();
+ if (this.sequencingService == null) {
+
+ SimpleSessionFactory sessionFactory = new SimpleSessionFactory();
+ sessionFactory.registerRepository(this.repositoryName, this.repository);
+ if (this.username != null) {
+ Credentials credentials = new SimpleCredentials(this.username, this.password);
+ sessionFactory.registerCredentials(this.repositoryName + "/" + this.workspaceName, credentials);
+ }
+ this.executionContext = new SimpleExecutionContext(sessionFactory);
+
+ // Create the sequencing service, passing in the execution context ...
+ this.sequencingService = new SequencingService();
+ this.sequencingService.setExecutionContext(executionContext);
+
+ // Configure the sequencers.
+ String name = "Image Sequencer";
+ String desc = "Sequences image files to extract the characteristics of the image";
+ String classname = "org.jboss.dna.sequencer.images.ImageMetadataSequencer";
+ String[] classpath = null; // Use the current classpath
+ String[] pathExpressions = {"//(*.(jpg|jpeg|gif|bmp|pcx|png|iff|ras|pbm|pgm|ppm|psd))[*]/jcr:content[@jcr:data] => /images/$1"};
+ SequencerConfig imageSequencerConfig = new SequencerConfig(name, desc, classname, classpath, pathExpressions);
+ this.sequencingService.addSequencer(imageSequencerConfig);
+
+ // Set up the MP3 sequencer ...
+ name = "Mp3 Sequencer";
+ desc = "Sequences mp3 files to extract the id3 tags of the audio file";
+ classname = "org.jboss.dna.sequencer.mp3.Mp3MetadataSequencer";
+ String[] mp3PathExpressions = {"//(*.mp3)[*]/jcr:content[@jcr:data] => /mp3s/$1"};
+ SequencerConfig mp3SequencerConfig = new SequencerConfig(name, desc, classname, classpath, mp3PathExpressions);
+ this.sequencingService.addSequencer(mp3SequencerConfig);
+
+ // Use the DNA observation service to listen to the JCR repository (or multiple ones), and
+ // then register the sequencing service as a listener to this observation service...
+ this.observationService = new ObservationService(this.executionContext.getSessionFactory());
+ this.observationService.getAdministrator().start();
+ this.observationService.addListener(this.sequencingService);
+ this.observationService.monitor(this.repositoryName + "/" + this.workspaceName, Event.NODE_ADDED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED);
+ }
+ // Start up the sequencing service ...
+ this.sequencingService.getAdministrator().start();
+}</programlisting>
+ </para>
+ <para>
+ The
+ <code>shutdownDnaServices()</code>
+ method is pretty straightforward: it just calls shutdown on each of the services and waits until they terminate.
+ <programlisting>
+public void shutdownDnaServices() throws Exception {
+ if (this.sequencingService == null) return;
+
+ // Shut down the service and wait until it's all shut down ...
+ this.sequencingService.getAdministrator().shutdown();
+ this.sequencingService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
+
+ // Shut down the observation service ...
+ this.observationService.getAdministrator().shutdown();
+ this.observationService.getAdministrator().awaitTermination(5, TimeUnit.SECONDS);
+}</programlisting>
+ </para>
+ <para>None of the other methods really do anything with JBoss DNA <emphasis>per se</emphasis>. Instead, they merely work with the repository
+ using the JCR API.</para>
+ <para>
+ The <code>main</code> method of the <code>SequencingClient</code> class creates a <code>SequencingClient</code> instance,
+ and passes a new <code>ConsoleInput</code> instance:
+ <programlisting>
+public static void main( String[] args ) throws Exception {
+ SequencingClient client = new SequencingClient();
+ client.setRepositoryInformation("repo", "default", "jsmith", "secret".toCharArray());
+ client.setUserInterface(new ConsoleInput(client));
+}</programlisting>
+ </para>
+ <para>If we look at the
+ <code>ConsoleInput</code>
+ constructor, it starts the repository, the DNA services, and a thread for the user interface. At this point, the constructor
+ returns, but the main application continues under the user interface thread. When the user requests to quit,
+ the user interface thread also shuts down the DNA services and JCR repository.
+ <programlisting>
+public ConsoleInput( SequencerClient client ) {
+ try {
+ client.startRepository();
+ client.startDnaServices();
+
+ System.out.println(getMenu());
+ Thread eventThread = new Thread(new Runnable() {
+ private boolean quit = false;
+ public void run() {
+ try {
+ while (!quit) {
+ // Display the prompt and process the requested operation ...
+ }
+ } finally {
+ try {
+ // Terminate ...
+ client.shutdownDnaServices();
+ client.shutdownRepository();
+ } catch (Exception err) {
+ System.out.println("Error shutting down sequencing service and repository: " + err.getLocalizedMessage());
+ err.printStackTrace(System.err);
+ }
+ }
+ }
+ });
+ eventThread.start();
+ } catch (Exception err) {
+ System.out.println("Error: " + err.getLocalizedMessage());
+ err.printStackTrace(System.err);
+ }
+}</programlisting>
+ </para>
+ <para>At this point, we've reviewed all of the interesting code in the example application. However, feel free
+ to play with the application, trying different things.
+ </para>
+ </sect1>
+ <sect1 id="using_dna_review">
+ <title>Summarizing what we just did</title>
+ <para>In this chapter we covered the different JBoss DNA components and how they can be used in your application.
+ Specifically, we described how the <code>SequencingService</code> and <code>ObservationService</code> can
+ be configured and used. And we ended the chapter by reviewing the example application, which not only uses
+ JBoss DNA, but also the repository via the JCR API.
+ </para>
+ </sect1>
+</chapter>
+
+<!-- ====================================================================================================
+ Chapter
+ ==================================================================================================== -->
+<chapter id="custom_sequencers">
+ <title>Creating custom sequencers</title>
+ <para>The current release of JBoss DNA comes with two sequencers: one that extracts metadata from a variety of image file formats,
+ and another that extracts some of the ID3 metadata from MP3 audio files. However, it's very easy to create your own
+ sequencers and to then configure JBoss DNA to use them in your own application.
+ </para>
+ <para>
+ Creating a custom sequencer involves the following steps:
+ <itemizedlist>
+ <listitem>
+ <para>Create a Maven 2 project for your sequencer;</para>
+ </listitem>
+ <listitem>
+ <para>Implement the <code>org.jboss.dna.graph.sequencers.StreamSequencer</code> interface with your own implementation, and create unit tests to verify
+ the functionality and expected behavior;</para>
+ </listitem>
+ <listitem>
+ <para>Add the sequencer configuration to the JBoss DNA <code>SequencingService</code> in your application
+ as described in the <link linkend="using_dna">previous chapter</link>; and</para>
+ </listitem>
+ <listitem>
+ <para>Deploy the JAR file with your implementation (as well as any dependencies), and make them available to JBoss DNA
+ in your application.</para>
+ </listitem>
+ </itemizedlist>
+ It's that simple.
+ </para>
+ <sect1 id="custom_sequencer_project">
+ <title>Creating the Maven 2 project</title>
+ <para>The first step is to create the Maven 2 project that you can use to compile your code and build the JARs.
+ Maven 2 automates a lot of the work, and since you're already <link linkend="downloading_and_running">set up to use Maven</link>,
+ using Maven for your project will save you a lot of time and effort. Of course, you don't have to use Maven 2, but then you'll
+ have to get the required libraries and manage the compiling and building process yourself.</para>
+ <note>
+ <para>JBoss DNA may provide in the future a Maven archetype for creating sequencer projects. If you'd find this useful
+ and would like to help create it, please <link linkend="preface">join the community</link>.</para>
+ </note>
+ <note>
+ <para>The <code>dna-sequencer-images</code> project is a small, self-contained sequencer implementation that
+ has only the minimal dependencies. Starting with this project's source and modifying it to suit your needs may be the easiest way to get started.
+ See the subversion repository: <ulink url="http://anonsvn.jboss.org/repos/dna/trunk/sequencers/dna-sequencer-images/">http://anonsvn.jboss.org/repos/dna/trunk/sequencers/dna-sequencer-images/</ulink>
+ </para>
+ </note>
+ <para>You can create your Maven project any way you'd like. For examples, see the <ulink url="http://maven.apache.org/guides/getting-started/index.html#How_do_I_make_m...">Maven 2 documentation</ulink>.
+ Once you've done that, just add the dependencies in your project's <code>pom.xml</code> dependencies section:
+ <programlisting>
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>0.1</version>
+</dependency>
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>0.1</version>
+</dependency>
+<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+</dependency>
+</programlisting>
+ These are minimum dependencies required for compiling a sequencer. Of course, you'll have to add
+ other dependencies that your sequencer needs.</para>
+ <para>As for testing, you probably will want to add more dependencies, such as those listed here:
+<programlisting>
+<dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ <version>1.1</version>
+ <scope>test</scope>
+</dependency>
+<!-- Logging with Log4J -->
+<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.4.3</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <scope>test</scope>
+</dependency>
+</programlisting>
+ Testing JBoss DNA sequencers does not require a JCR repository or the JBoss DNA services. (For more detail,
+ see the <link linkend="testing_custom_sequencers">testing section</link>.) However, if you want to do
+ integration testing with a JCR repository and the JBoss DNA services, you'll need additional dependencies for these libraries.
+<programlisting>
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-repository</artifactId>
+ <version>0.1</version>
+ <scope>test</scope>
+</dependency>
+<!-- Java Content Repository API -->
+<dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ <version>1.0.1</version>
+ <scope>test</scope>
+</dependency>
+<!-- Apache Jackrabbit (JCR Implementation) -->
+<dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>jackrabbit-api</artifactId>
+ <version>1.3.3</version>
+ <scope>test</scope>
+ <!-- Exclude these since they are included in JDK 1.5 -->
+ <exclusions>
+ <exclusion>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ </exclusion>
+ </exclusions>
+</dependency>
+<dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>jackrabbit-core</artifactId>
+ <version>1.3.3</version>
+ <scope>test</scope>
+ <!-- Exclude these since they are included in JDK 1.5 -->
+ <exclusions>
+ <exclusion>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ </exclusion>
+ </exclusions>
+</dependency>
+</programlisting>
+ </para>
+ <para>At this point, your project should be set up correctly, and you're ready to move on to
+ <link linkend="custom_sequencer_implementation">writing the Java implementation</link> for your sequencer.
+ </para>
+ </sect1>
+ <sect1 id="custom_sequencer_implementation">
+ <title>Implementing the StreamSequencer interface</title>
+ <para>After creating the project and setting up the dependencies, the next step is to create a Java class that implements
+ the <code>org.jboss.dna.graph.sequencers.StreamSequencer</code> interface. This interface is very straightforward
+ and involves a single method:
+ <programlisting>
+public interface StreamSequencer {
+
+ /**
+ * Sequence the data found in the supplied stream, placing the output
+ * information into the supplied map.
+ *
+ * @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 cancelled.
+ */
+ void sequence( InputStream stream, SequencerOutput output,
+ ProgressMonitor progressMonitor );</programlisting>
+ </para>
+ <para>The job of a stream sequencer is to process the data in the supplied stream, and place into the <code>SequencerOutput</code>
+ any information that is to go into the JCR repository. JBoss DNA figures out when your sequencer should be called
+ (of course, using the sequencing configuration you'll add in a bit), and then makes sure the generated information
+ is saved in the correct place in the repository.
+ </para>
+ <para>The <code>SequencerOutput</code> class is fairly easy to use. There are basically two methods you need to call.
+ One method sets the property values, while the other sets references to other nodes in the repository. Use these
+ methods to describe the properties of the nodes you want to create, using relative paths for the nodes and
+ valid JCR property names for properties and references. JBoss DNA will ensure that nodes are created or updated
+ whenever they're needed.
+ <programlisting>
+public interface SequencerOutput {
+
+ /**
+ * Set the supplied property on the supplied node. The allowable
+ * values are any of the following:
+ * - primitives (which will be autoboxed)
+ * - String instances
+ * - String arrays
+ * - byte arrays
+ * - InputStream instances
+ * - Calendar instances
+ *
+ * @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 );
+}</programlisting>
+ </para>
+ <para>JBoss DNA will create nodes of type <code>nt:unstructured</code> unless you specify the value for the
+ <code>jcr:primaryType</code> property. You can also specify the values for the <code>jcr:mixinTypes</code> property
+ if you want to add mixins to any node.
+ </para>
+ <para>For a complete example of a sequencer, let's look at the <code>org.jboss.dna.sequencers.image.ImageMetadataSequencer</code> implementation:
+ <programlisting>
+public class ImageMetadataSequencer implements StreamSequencer {
+
+ public static final String METADATA_NODE = "image:metadata";
+ public static final String IMAGE_PRIMARY_TYPE = "jcr:primaryType";
+ public static final String IMAGE_MIXINS = "jcr:mixinTypes";
+ public static final String IMAGE_MIME_TYPE = "jcr:mimeType";
+ public static final String IMAGE_ENCODING = "jcr:encoding";
+ public static final String IMAGE_FORMAT_NAME = "image:formatName";
+ public static final String IMAGE_WIDTH = "image:width";
+ public static final String IMAGE_HEIGHT = "image:height";
+ public static final String IMAGE_BITS_PER_PIXEL = "image:bitsPerPixel";
+ public static final String IMAGE_PROGRESSIVE = "image:progressive";
+ public static final String IMAGE_NUMBER_OF_IMAGES = "image:numberOfImages";
+ public static final String IMAGE_PHYSICAL_WIDTH_DPI = "image:physicalWidthDpi";
+ public static final String IMAGE_PHYSICAL_HEIGHT_DPI = "image:physicalHeightDpi";
+ public static final String IMAGE_PHYSICAL_WIDTH_INCHES = "image:physicalWidthInches";
+ public static final String IMAGE_PHYSICAL_HEIGHT_INCHES = "image:physicalHeightInches";
+
+ /**
+ * {@inheritDoc}
+ */
+ public void sequence( InputStream stream, SequencerOutput output,
+ ProgressMonitor progressMonitor ) {
+ progressMonitor.beginTask(10, ImageSequencerI18n.sequencerTaskName);
+
+ ImageMetadata metadata = new ImageMetadata();
+ metadata.setInput(stream);
+ metadata.setDetermineImageNumber(true);
+ metadata.setCollectComments(true);
+
+ // Process the image stream and extract the metadata ...
+ if (!metadata.check()) {
+ metadata = null;
+ }
+ progressMonitor.worked(5);
+ if (progressMonitor.isCancelled()) return;
+
+ // Generate the output graph if we found useful metadata ...
+ if (metadata != null) {
+ // Place the image metadata into the output map ...
+ output.setProperty(METADATA_NODE, IMAGE_PRIMARY_TYPE, "image:metadata");
+ // output.psetProperty(METADATA_NODE, IMAGE_MIXINS, "");
+ output.setProperty(METADATA_NODE, IMAGE_MIME_TYPE, metadata.getMimeType());
+ // output.setProperty(METADATA_NODE, IMAGE_ENCODING, "");
+ output.setProperty(METADATA_NODE, IMAGE_FORMAT_NAME, metadata.getFormatName());
+ output.setProperty(METADATA_NODE, IMAGE_WIDTH, metadata.getWidth());
+ output.setProperty(METADATA_NODE, IMAGE_HEIGHT, metadata.getHeight());
+ output.setProperty(METADATA_NODE, IMAGE_BITS_PER_PIXEL, metadata.getBitsPerPixel());
+ output.setProperty(METADATA_NODE, IMAGE_PROGRESSIVE, metadata.isProgressive());
+ output.setProperty(METADATA_NODE, IMAGE_NUMBER_OF_IMAGES, metadata.getNumberOfImages());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_DPI, metadata.getPhysicalWidthDpi());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_DPI, metadata.getPhysicalHeightDpi());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_INCHES, metadata.getPhysicalWidthInch());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_INCHES, metadata.getPhysicalHeightInch());
+ }
+
+ progressMonitor.done();
+ }
+}</programlisting>
+ </para>
+ <para>
+ Notice how the image metadata is extracted and the output graph is generated. A single node is created with the name <code>image:metadata</code>
+ and with the <code>image:metadata</code> node type. No mixins are defined for the node, but several properties are set on the node
+ using the values obtained from the image metadata. After this method returns, the constructed graph will be saved to the repository
+ in all of the places defined by its configuration. (This is why only relative paths are used in the sequencer.)
+ </para>
+ <para>Also note how the progress monitor is used. Reporting progress through the supplied <code>ProgressMonitor</code> is very easy, and it ensures that JBoss DNA
+ can accurately monitor and report the status of sequencing activities to the users. At the beginning of the operation, call
+ <code>beginTask(...)</code> 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 incremental amount of work with the <code>worked(double)</code> method, or
+ by creating a subtask with the <code>createSubtask(double)</code> method and reporting work against that subtask
+ monitor.
+ </para>
+ <para>Your method should periodically use the ProgressMonitor's <code>isCancelled()</code> method to check whether the operation has been
+ 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.
+ </para>
+ <para>
+ Finally, when your sequencing operation is completed, it should call <code>done()</code> on the progress monitor.
+ </para>
+ </sect1>
+ <sect1 id="testing_custom_sequencers">
+ <title>Testing custom sequencers</title>
+ <para>The sequencing framework was designed to make testing sequencers much easier. In particular, the
+ <code>StreamSequencer</code> interface does not make use of the JCR API. So instead of requiring a fully-configured
+ JCR repository and JBoss DNA system, unit tests for a sequencer can focus on testing that the content is
+ processed correctly and the desired output graph is generated.</para>
+ <note>
+ <para>For a complete example of a sequencer unit test, see the <code>ImageMetadataSequencerTest</code> unit test
+ in the <code>org.jboss.dna.sequencer.images</code> package of the <code>dna-sequencers-image</code> project.
+ </para>
+ </note>
+ <para>The following code fragment shows one way of testing a sequencer, using JUnit 4.4 assertions and
+ some of the classes made available by JBoss DNA. Of course,
+ this example code does not do any error handling and does not make all the assertions a real test would.
+ <programlisting>
+Sequencer sequencer = new ImageMetadataSequencer();
+MockSequencerOutput output = new MockSequencerOutput();
+ProgressMonitor progress = new SimpleProgressMonitor("Test activity");
+InputStream stream = null;
+try {
+ stream = this.getClass().getClassLoader().getResource("caution.gif").openStream();
+ sequencer.sequence(stream,output,progress); // writes to 'output'
+ assertThat(output.getPropertyValues("image:metadata", "jcr:primaryType"),
+ is(new Object[] {"image:metadata"}));
+ assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"),
+ is(new Object[] {"image/gif"}));
+ // ... make more assertions here
+ assertThat(output.hasReferences(), is(false));
+} finally {
+ stream.close();
+}</programlisting>
+ </para>
+ <para>It's also useful to test that a sequencer produces no output for something it should not understand:
+ <programlisting>
+Sequencer sequencer = new ImageMetadataSequencer();
+MockSequencerOutput output = new MockSequencerOutput();
+ProgressMonitor progress = new SimpleProgressMonitor("Test activity");
+InputStream stream = null;
+try {
+ stream = this.getClass().getClassLoader().getResource("caution.pict").openStream();
+ sequencer.sequence(stream,output,progress); // writes to 'output'
+ assertThat(output.hasProperties(), is(false));
+ assertThat(output.hasReferences(), is(false));
+} finally {
+ stream.close();
+}</programlisting>
+ </para>
+ <para>These are just two simple tests that show ways of testing a sequencer. Some tests may get quite involved,
+ especially if a lot of output data is produced.
+ </para>
+ <para>It may also be useful to create some integration tests
+ that <link linkend="using_dna">configure JBoss DNA</link> to use a custom sequencer, and to then upload
+ content using the JCR API, verifying that the custom sequencer did run. However, remember that JBoss DNA
+ runs sequencers asynchronously in the background, and you must sychronize your tests to ensure that the
+ sequencers have a chance to run before checking the results. (One way of doing this (although, granted, not always reliable) is to wait for a second
+ after uploading your content, shutdown the <code>SequencingService</code> and await its termination,
+ and then check that the sequencer output has been saved to the JCR repository. For an example of this technique,
+ see the <code>SequencingClientTest</code> unit test in the example application.)
+ </para>
+ </sect1>
+ <sect1 id="deploying_custom_sequencers">
+ <title>Deploying custom sequencers</title>
+ <para>The first step of deploying a sequencer consists of adding/changing the sequencer configuration (e.g., <code>SequencerConfig</code>)
+ in the <code>SequencingService</code>. This was covered in the <link linkend="sequencing_service">previous chapter</link>.
+ </para>
+ <para>
+ The second step is to make the sequencer implementation available to JBoss DNA. At this time, the JAR containing
+ your new sequencer, as well as any JARs that your sequencer depends on, should be placed on your application classpath.</para>
+ <note>
+ <para>A future goal of JBoss DNA is to allow sequencers, connectors, and other extensions to be easily deployed into
+ a runtime repository. This process will not only be much simpler, but it will also provide JBoss DNA
+ with the information necessary to update configurations and create the appropriate class loaders for each extension.
+ Having separate class loaders for each extension helps prevent the pollution of the common classpath,
+ facilitates an isolated runtime environment to eliminate any dependency conflicts, and may potentially
+ enable hot redeployment of newer extension versions.
+ </para>
+ </note>
+ </sect1>
+</chapter>
+
+<!-- ====================================================================================================
+ Chapter
+ ==================================================================================================== -->
+<chapter id="future_directions">
+ <title>Looking to the future</title>
+ <para>What's next for JBoss DNA? Well, the sequencing system is just the beginning. With this release, the sequencing system
+ is stable enough so that more <link linkend="sequencers">sequencers</link> can be developed and used within your own applications.
+ If you're interested in getting involved with the JBoss DNA project, consider picking up one of the sequencers on our
+ <ulink url="http://jira.jboss.org/jira/browse/DNA?report=com.atlassian.jira.plugin.sy...">roadmap</ulink>.
+ Or, check out <ulink url="http://jira.jboss.org/jira/secure/IssueNavigator.jspa?reset=true&mode...">JIRA</ulink>
+ for the list of sequencers we've thought of. If you think of one that's not there, please add it to JIRA!
+ </para>
+ <para>
+ The next release will focus on creating the <link linkend="federation">federation engine</link> and connectors
+ for several popular and ubiquitous systems. The 0.2 release will likely only federate information in a read-only manner,
+ but updates will soon follow. Also, during the early part of the next release, the JBoss DNA project will switch to use JDK 6.
+ Java 5 is being end-of-lifed, so we want to move to a supported JDK. However, a number of JBoss projects and products continue to
+ require Java 5, so our next release will most likely use JDK 6 with Java 5 compatibility.</para>
+ <para>
+ Other components on our roadmap include a web user interface, a REST-ful server, and a view system that allows domain-specific
+ views of information in the repository. These components are farther out on our roadmap, and at this time have not been
+ targeted to a particular release. If any of these are of interest to you, please <link linkend="preface">get involved</link> in the community.
+ </para>
+</chapter>
+</book>
\ No newline at end of file
Added: trunk/extensions/dna-sequencer-xml/src/test/resources/plugin.xml
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/resources/plugin.xml (rev 0)
+++ trunk/extensions/dna-sequencer-xml/src/test/resources/plugin.xml 2008-10-29 18:23:01 UTC (rev 598)
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<!-- (c) 2007 Varsity Gateway LLC. All rights reserved. -->
+<plugin
+ id="com.metamatrix.metamodels.transformation"
+ name="%pluginName"
+ version="5.5.1"
+ provider-name="%providerName"
+ class="com.metamatrix.metamodels.transformation.TransformationPlugin">
+
+ <runtime>
+ <library name="metamodelsTransformation.jar">
+ <export name="*"/>
+ </library>
+ </runtime>
+ <requires>
+ <import plugin="org.eclipse.emf.mapping" export="true"/>
+ <import plugin="org.eclipse.emf.ecore" export="true"/>
+ <import plugin="org.eclipse.emf.edit" export="true"/>
+ <import plugin="org.eclipse.emf.ecore.edit" export="true"/>
+ <import plugin="org.eclipse.core.runtime" export="true"/>
+ <import plugin="com.metamatrix.core" export="true"/>
+ <import plugin="com.metamatrix.metamodels.core" export="true"/>
+ </requires>
+
+
+<!--
+ Each extension below represents a single metamodel. Each metmodel is
+ registered using under the specified <uri> value which must be the same
+ eNS_URI value defined in the EPackage class for that metamodel.
+ -->
+ <extension
+ id="transformation"
+ name="%metamodelName"
+ point="com.metamatrix.modeler.core.metamodel">
+ <uri>
+ http://www.metamatrix.com/metamodels/Transformation
+ </uri>
+ <alternateUri>
+ mtkplugin:///com.metamatrix.metamodels.Transformation
+ </alternateUri>
+ <packageClass
+ name="com.metamatrix.metamodels.transformation.TransformationPackage">
+ </packageClass>
+ <adapterClass
+ name="com.metamatrix.metamodels.transformation.provider.TransformationItemProviderAdapterFactory">
+ </adapterClass>
+ <properties
+ createAsPhysical="false"
+ requiresProxies="false"
+ participatoryOnly="true"
+ createAsVirtual="false"
+ supportsDiagrams="false"
+ supportsExtension="true">
+ </properties>
+ </extension>
+ <extension
+ point="org.eclipse.emf.ecore.generated_package">
+ <package
+ uri="http://www.metamatrix.com/metamodels/Transformation"
+ class="com.metamatrix.metamodels.transformation.TransformationPackage">
+ </package>
+ </extension>
+
+ <extension
+ id="mapping"
+ name="%mappingMetamodelName"
+ point="com.metamatrix.modeler.core.metamodel">
+ <uri>
+ http://www.eclipse.org/emf/2002/Mapping
+ </uri>
+ <alternateUri>
+ mtkplugin:///www.eclipse.org/emf/2002/Mapping
+ </alternateUri>
+ <packageClass
+ name="org.eclipse.emf.mapping.MappingPackage">
+ </packageClass>
+ <adapterClass
+ name="org.eclipse.emf.mapping.provider.MappingItemProviderAdapterFactory">
+ </adapterClass>
+ <properties
+ createAsPhysical="false"
+ requiresProxies="false"
+ participatoryOnly="true"
+ createAsVirtual="false"
+ supportsDiagrams="false"
+ supportsExtension="false">
+ </properties>
+ </extension>
+
+</plugin>
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2008-10-29 17:48:23 UTC (rev 597)
+++ trunk/pom.xml 2008-10-29 18:23:01 UTC (rev 598)
@@ -123,6 +123,7 @@
<module>extensions/dna-sequencer-cnd</module>
<module>extensions/dna-sequencer-java</module>
<module>extensions/dna-sequencer-msoffice</module>
+ <module>extensions/dna-sequencer-xml</module>
<module>extensions/dna-sequencer-zip</module>
<module>extensions/dna-connector-federation</module>
<module>extensions/dna-connector-inmemory</module>
15 years, 6 months
DNA SVN: r597 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/properties and 7 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-10-29 13:48:23 -0400 (Wed, 29 Oct 2008)
New Revision: 597
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrLexicon.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrNtLexicon.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java
Removed:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/
trunk/dna-graph/src/test/java/org/jboss/dna/graph/util/
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/NameFactory.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlSequencer.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlSequencerTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerOutputMap.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerNodeContextTest.java
trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
Log:
DNA-242 - Change the XML importer code to no longer use XmlSequencer
http://jira.jboss.com/jira/browse/DNA-242
Changed the GraphImporter and Graph.importXmlFrom(...) methods to use the new XmlHandler (rather than the XmlSequencer).
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -61,7 +61,7 @@
import org.jboss.dna.graph.requests.RemovePropertiesRequest;
import org.jboss.dna.graph.requests.Request;
import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
-import org.jboss.dna.graph.util.GraphImporter;
+import org.xml.sax.SAXException;
/**
* A graph representation of the content within a {@link RepositorySource}, including mechanisms to interact and manipulate that
@@ -993,31 +993,38 @@
*/
public ImportInto<Conjunction<Graph>> importXmlFrom( final URI uri ) {
return new ImportInto<Conjunction<Graph>>() {
- public Conjunction<Graph> into( String path ) throws IOException {
+ private boolean skipRootElement = false;
+
+ public ImportInto<Conjunction<Graph>> skippingRootElement( boolean skipRootElement ) {
+ this.skipRootElement = skipRootElement;
+ return this;
+ }
+
+ public Conjunction<Graph> into( String path ) throws IOException, SAXException {
return into(new Location(createPath(path)));
}
- public Conjunction<Graph> into( Path path ) throws IOException {
+ public Conjunction<Graph> into( Path path ) throws IOException, SAXException {
return into(new Location(path));
}
- public Conjunction<Graph> into( Property idProperty ) throws IOException {
+ public Conjunction<Graph> into( Property idProperty ) throws IOException, SAXException {
return into(new Location(idProperty));
}
public Conjunction<Graph> into( Property firstIdProperty,
- Property... additionalIdProperties ) throws IOException {
+ Property... additionalIdProperties ) throws IOException, SAXException {
return into(new Location(firstIdProperty, additionalIdProperties));
}
- public Conjunction<Graph> into( UUID uuid ) throws IOException {
+ public Conjunction<Graph> into( UUID uuid ) throws IOException, SAXException {
return into(new Location(uuid));
}
@SuppressWarnings( "synthetic-access" )
- public Conjunction<Graph> into( Location at ) throws IOException {
+ public Conjunction<Graph> into( Location at ) throws IOException, SAXException {
GraphImporter importer = new GraphImporter(Graph.this);
- importer.importXml(uri, at).execute(); // 'importXml' creates and uses a new batch
+ importer.importXml(uri, at, skipRootElement).execute(); // 'importXml' creates and uses a new batch
return Graph.this.nextGraph;
}
};
@@ -2482,13 +2489,23 @@
*/
public interface ImportInto<Next> {
/**
+ * Specify whether the root element in the XML document should be skipped (that is, not be represented by a node). By
+ * default, the root element is not skipped.
+ *
+ * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
+ * @return the interface used to specify the location where the content should be placed
+ */
+ ImportInto<Next> skippingRootElement( boolean skip );
+
+ /**
* Finish the import by specifying the new location into which the node should be copied/moved.
*
* @param to the location of the new parent
* @return the interface for additional requests or actions
* @throws IOException if there is a problem reading the content being imported
+ * @throws SAXException if there is a problem with the SAX Parser
*/
- Next into( Location to ) throws IOException;
+ Next into( Location to ) throws IOException, SAXException;
/**
* Finish the import by specifying the new location into which the node should be copied/moved.
@@ -2496,8 +2513,9 @@
* @param toPath the path of the new parent
* @return the interface for additional requests or actions
* @throws IOException if there is a problem reading the content being imported
+ * @throws SAXException if there is a problem with the SAX Parser
*/
- Next into( String toPath ) throws IOException;
+ Next into( String toPath ) throws IOException, SAXException;
/**
* Finish the import by specifying the new location into which the node should be copied/moved.
@@ -2505,8 +2523,9 @@
* @param to the path of the new parent
* @return the interface for additional requests or actions
* @throws IOException if there is a problem reading the content being imported
+ * @throws SAXException if there is a problem with the SAX Parser
*/
- Next into( Path to ) throws IOException;
+ Next into( Path to ) throws IOException, SAXException;
/**
* Finish the import by specifying the new location into which the node should be copied/moved.
@@ -2514,8 +2533,9 @@
* @param to the UUID of the new parent
* @return the interface for additional requests or actions
* @throws IOException if there is a problem reading the content being imported
+ * @throws SAXException if there is a problem with the SAX Parser
*/
- Next into( UUID to ) throws IOException;
+ Next into( UUID to ) throws IOException, SAXException;
/**
* Finish the import by specifying the new location into which the node should be copied/moved.
@@ -2523,8 +2543,9 @@
* @param idProperty the property that uniquely identifies the new parent
* @return the interface for additional requests or actions
* @throws IOException if there is a problem reading the content being imported
+ * @throws SAXException if there is a problem with the SAX Parser
*/
- Next into( Property idProperty ) throws IOException;
+ Next into( Property idProperty ) throws IOException, SAXException;
/**
* Finish the import by specifying the new location into which the node should be copied/moved.
@@ -2535,9 +2556,10 @@
* identifies the new parent
* @return the interface for additional requests or actions
* @throws IOException if there is a problem reading the content being imported
+ * @throws SAXException if there is a problem with the SAX Parser
*/
Next into( Property firstIdProperty,
- Property... additionalIdProperties ) throws IOException;
+ Property... additionalIdProperties ) throws IOException, SAXException;
}
public interface BatchConjunction extends Conjunction<Batch>, Executable {
@@ -2616,9 +2638,11 @@
}
public Results execute() {
- // Execute the requests ...
- Request request = CompositeRequest.with(requests);
- Graph.this.execute(request);
+ if (!requests.isEmpty()) {
+ // Execute the requests ...
+ Request request = CompositeRequest.with(requests);
+ Graph.this.execute(request);
+ }
return new BatchResults(requests);
}
}
Copied: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java (from rev 593, trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java)
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -0,0 +1,173 @@
+/*
+ * 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.graph;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.text.TextDecoder;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.connectors.RepositorySource;
+import org.jboss.dna.graph.connectors.RepositorySourceException;
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.NamespaceRegistry;
+import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.properties.Property;
+import org.jboss.dna.graph.xml.XmlHandler;
+import org.jboss.dna.graph.xml.XmlHandler.Destination;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public class GraphImporter {
+
+ private final Graph graph;
+
+ public GraphImporter( Graph graph ) {
+ CheckArg.isNotNull(graph, "graph");
+ this.graph = graph;
+ }
+
+ /**
+ * Get the context in which the importer will be executed.
+ *
+ * @return the execution context; never null
+ */
+ public ExecutionContext getContext() {
+ return this.graph.getContext();
+ }
+
+ /**
+ * The graph that this importer uses.
+ *
+ * @return the graph; never null
+ */
+ public Graph getGraph() {
+ return graph;
+ }
+
+ /**
+ * Read the content from the supplied URI and import into the repository at the supplied location.
+ *
+ * @param uri the URI where the importer can read the content that is to be imported
+ * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+ * be null
+ * @return the batch of requests for creating the graph content that represents the imported content
+ * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
+ * @throws IOException if there is a problem reading the content
+ * @throws SAXException if there is a problem with the SAX Parser
+ * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
+ * source}
+ */
+ public Graph.Batch importXml( URI uri,
+ Location location ) throws IOException, SAXException, RepositorySourceException {
+ return importXml(uri, location, false);
+ }
+
+ /**
+ * Read the content from the supplied URI and import into the repository at the supplied location.
+ *
+ * @param uri the URI where the importer can read the content that is to be imported
+ * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+ * be null
+ * @param skip true if the root element should be skipped, or false if a node should be created for the root XML element
+ * @return the batch of requests for creating the graph content that represents the imported content
+ * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
+ * @throws IOException if there is a problem reading the content
+ * @throws SAXException if there is a problem with the SAX Parser
+ * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
+ * source}
+ */
+ public Graph.Batch importXml( URI uri,
+ Location location,
+ boolean skip ) throws IOException, SAXException, RepositorySourceException {
+ CheckArg.isNotNull(uri, "uri");
+ CheckArg.isNotNull(location, "location");
+ CheckArg.isNotNull(location.getPath(), "location.getPath()");
+
+ // Create the destination for the XmlHandler ...
+ Graph.Batch batch = graph.batch();
+ XmlHandler.Destination destination = new CreateOnGraphInBatch(batch);
+
+ // Determine where the content is to be placed ...
+ Path parentPath = location.getPath();
+ InputStream stream = null;
+ Name nameAttribute = JcrLexicon.NAME;
+ Name typeAttribute = JcrLexicon.PRIMARY_TYPE;
+ Name typeAttributeValue = null;
+ NamespaceRegistry reg = graph.getContext().getNamespaceRegistry();
+ if (reg.isRegisteredNamespaceUri(JcrNtLexicon.Namespace.URI)) {
+ typeAttributeValue = JcrNtLexicon.UNSTRUCTURED;
+ }
+
+ TextDecoder decoder = null;
+ XmlHandler.AttributeScoping scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
+ XmlHandler handler = new XmlHandler(destination, skip, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
+ try {
+ stream = uri.toURL().openStream();
+ XMLReader reader = XMLReaderFactory.createXMLReader();
+ reader.setContentHandler(handler);
+ reader.setErrorHandler(handler);
+ reader.parse(new InputSource(stream));
+ } finally {
+ if (stream != null) stream.close();
+ }
+ return batch;
+ }
+
+ @NotThreadSafe
+ protected final static class CreateOnGraphInBatch implements Destination {
+ private final Graph.Batch batch;
+
+ protected CreateOnGraphInBatch( Graph.Batch batch ) {
+ assert batch != null;
+ this.batch = batch;
+ }
+
+ public ExecutionContext getExecutionContext() {
+ return batch.getGraph().getContext();
+ }
+
+ public void create( Path path,
+ List<Property> properties,
+ Name elementName ) {
+ assert properties != null;
+ if (properties.isEmpty()) {
+ batch.create(path).and();
+ } else {
+ batch.create(path, properties).and();
+ }
+ }
+
+ public void submit() {
+ }
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphImporter.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrLexicon.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrLexicon.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrLexicon.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -0,0 +1,40 @@
+/*
+ * 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.graph;
+
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.basic.BasicName;
+
+/**
+ * @author Randall Hauch
+ */
+public class JcrLexicon {
+
+ public static class Namespace {
+ public static final String URI = "http://www.jcp.org/jcr/1.0";
+ public static final String PREFIX = "jcr";
+ }
+
+ public static final Name UUID = new BasicName(Namespace.URI, "uuid");
+ public static final Name NAME = new BasicName(Namespace.URI, "name");
+ public static final Name PRIMARY_TYPE = new BasicName(Namespace.URI, "primaryType");
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrLexicon.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrNtLexicon.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrNtLexicon.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrNtLexicon.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -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.graph;
+
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.basic.BasicName;
+
+/**
+ * @author Randall Hauch
+ */
+public class JcrNtLexicon {
+
+ public static class Namespace {
+ public static final String URI = "http://www.jcp.org/jcr/nt/1.0";
+ public static final String PREFIX = "nt";
+ }
+
+ public static final Name UNSTRUCTURED = new BasicName(Namespace.URI, "unstructured");
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/JcrNtLexicon.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/NameFactory.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/NameFactory.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/NameFactory.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -30,8 +30,6 @@
*/
public interface NameFactory extends ValueFactory<Name> {
- String JCR_PRIMARY_TYPE = "jcr:primaryType";
-
/**
* Create a name from the given namespace URI and local name.
* <p>
@@ -43,7 +41,8 @@
* @return the new name
* @throws IllegalArgumentException if the local name is <code>null</code> or empty
*/
- Name create( String namespaceUri, String localName );
+ Name create( String namespaceUri,
+ String localName );
/**
* Create a name from the given namespace URI and local name.
@@ -54,7 +53,9 @@
* @return the new name
* @throws IllegalArgumentException if the local name is <code>null</code> or empty
*/
- Name create( String namespaceUri, String localName, TextDecoder decoder );
+ Name create( String namespaceUri,
+ String localName,
+ TextDecoder decoder );
/**
* Get the namespace registry.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlHandler.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -31,7 +31,6 @@
import org.jboss.dna.common.text.XmlNameEncoder;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.properties.Name;
import org.jboss.dna.graph.properties.NameFactory;
import org.jboss.dna.graph.properties.NamespaceRegistry;
@@ -91,6 +90,16 @@
protected final Name nameAttribute;
/**
+ * The name of the property that is to be set with the type of the XML element. For example, "jcr:name".
+ */
+ protected final Name typeAttribute;
+
+ /**
+ * The value of the node type property, if the node's name is set with the {@link #nameAttribute}.
+ */
+ protected final Name typeAttributeValue;
+
+ /**
* The cached reference to the graph's path factory.
*/
protected final PathFactory pathFactory;
@@ -154,8 +163,12 @@
* @param parent the path to the node in the graph under which the content should be placed; if null, the root node is assumed
* @param textDecoder the text decoder that should be used to decode the XML element names and XML attribute names, prior to
* using those values to create names; or null if the default encoder should be used
- * @param nameAttribute the name of the XML attribute whose value should be used for the names of the nodes (typically, this
- * is "jcr:name" or something equivalent); or null if the XML element name should always be used as the node name
+ * @param nameAttribute the name of the property whose value should be used for the names of the nodes (typically, this is
+ * "jcr:name" or something equivalent); or null if the XML element name should always be used as the node name
+ * @param typeAttribute the name of the property that should be set with the type of the XML element, or null if there is no
+ * such property
+ * @param typeAttributeValue the value of the type property that should be used if the node has no <code>nameAttribute</code>,
+ * or null if the value should be set to the type of the XML element
* @param scoping defines how to choose the namespace of attributes that do not have a namespace prefix; if null, the
* {@link #DEFAULT_ATTRIBUTE_SCOPING} value is used
* @throws IllegalArgumentException if the destination reference is null
@@ -165,11 +178,15 @@
Path parent,
TextDecoder textDecoder,
Name nameAttribute,
+ Name typeAttribute,
+ Name typeAttributeValue,
AttributeScoping scoping ) {
CheckArg.isNotNull(destination, "destination");
assert destination != null;
this.destination = destination;
this.nameAttribute = nameAttribute;
+ this.typeAttribute = typeAttribute;
+ this.typeAttributeValue = typeAttributeValue;
this.decoder = textDecoder != null ? textDecoder : DEFAULT_DECODER;
this.skipFirstElement = skipRootElement;
this.attributeScoping = scoping != null ? scoping : DEFAULT_ATTRIBUTE_SCOPING;
@@ -192,39 +209,6 @@
}
/**
- * Create a handler that creates content in the supplied graph
- *
- * @param graph the graph in which the content should be placed
- * @param useBatch true if all of the actions to create the content in the graph should be submitted to the graph in a single
- * batch, or false if they should be submitted immediately after each is identified
- * @param skipRootElement true if the root element of the document should be skipped, or false if the root element should be
- * converted to the top-level node of the content
- * @param parent the path to the node in the graph under which the content should be placed; if null, the root node is assumed
- * @param textDecoder the text decoder that should be used to decode the XML element names and XML attribute names, prior to
- * using those values to create names; or null if the default encoder should be used
- * @param nameAttribute the name of the XML attribute whose value should be used for the names of the nodes (typically, this
- * is "jcr:name" or something equivalent); or null if the XML element name should always be used as the node name
- * @param scoping defines how to choose the namespace of attributes that do not have a namespace prefix; if null, the
- * {@link #DEFAULT_ATTRIBUTE_SCOPING} value is used
- * @throws IllegalArgumentException if the graph reference is null
- */
- public XmlHandler( Graph graph,
- boolean useBatch,
- boolean skipRootElement,
- Path parent,
- TextDecoder textDecoder,
- Name nameAttribute,
- AttributeScoping scoping ) {
- this(createDestination(graph, useBatch), skipRootElement, parent, textDecoder, nameAttribute, scoping);
- }
-
- protected static Destination createDestination( Graph graph,
- boolean useBatch ) {
- CheckArg.isNotNull(graph, "graph");
- return useBatch ? new CreateOnGraphInBatches(graph.batch()) : new CreateOnGraph(graph);
- }
-
- /**
* {@inheritDoc}
* <p>
* This method ensures that the namespace is registered with the {@link NamespaceRegistry registry}, using the supplied prefix
@@ -267,6 +251,7 @@
Name nodeName = null;
properties.clear();
+ Object typePropertyValue = null;
// Convert each of the attributes to a property ...
for (int i = 0; i != attributes.getLength(); ++i) {
String attributeLocalName = attributes.getLocalName(i);
@@ -290,16 +275,34 @@
nodeName = nameFactory.create(attributes.getValue(i)); // don't use a decoder
continue;
}
+ if (attributeName.equals(typeAttribute)) {
+ typePropertyValue = nameFactory.create(attributes.getValue(i)); // don't use a decoder
+ continue;
+ }
// Create a property for this attribute ...
Property property = createProperty(attributeName, attributes.getValue(i));
properties.add(property);
}
// Create the node name if required ...
- if (nodeName == null) nodeName = nameFactory.create(uri, localName, decoder);
+ Name elementName = nameFactory.create(uri, localName, decoder);
+ if (nodeName == null) {
+ // No attribute defines the node name ...
+ nodeName = elementName;
+ } else {
+ // A attribute defines the node name ...
+ typePropertyValue = elementName;
+ }
+ // Set the type property, if required
+ if (typeAttribute != null) {
+ if (typePropertyValue == null) typePropertyValue = typeAttributeValue;
+ propertyValues[0] = typePropertyValue;
+ Property property = propertyFactory.create(typeAttribute, propertyValues);
+ properties.add(property);
+ }
// Update the current path ...
currentPath = pathFactory.create(currentPath, nodeName);
// Create the node, and note that we don't care about same-name siblings (as the graph will correct them) ...
- destination.create(currentPath, properties);
+ destination.create(currentPath, properties, elementName);
}
/**
@@ -363,9 +366,12 @@
*
* @param path the absolute path of the node
* @param properties the properties for the node; never null, but may be empty if there are no properties
+ * @param elementName the name of the XML element from which the node should be created; never null, and may or may not be
+ * the same name as the last segment of the path
*/
public void create( Path path,
- List<Property> properties );
+ List<Property> properties,
+ Name elementName );
/**
* Signal to this destination that any enqueued create requests should be submitted. Usually this happens at the end of
@@ -373,61 +379,4 @@
*/
public void submit();
}
-
- @NotThreadSafe
- protected final static class CreateOnGraph implements Destination {
- private final Graph graph;
-
- protected CreateOnGraph( final Graph graph ) {
- assert graph != null;
- this.graph = graph;
- }
-
- public ExecutionContext getExecutionContext() {
- return graph.getContext();
- }
-
- public final void create( Path path,
- List<Property> properties ) {
- assert properties != null;
- if (properties.isEmpty()) {
- graph.create(path);
- } else {
- graph.create(path, properties);
- }
- }
-
- public void submit() {
- // Nothing to do, since each call to 'create' immediate executes on the graph
- }
- }
-
- @NotThreadSafe
- protected final static class CreateOnGraphInBatches implements Destination {
- private final Graph.Batch batch;
-
- protected CreateOnGraphInBatches( Graph.Batch batch ) {
- assert batch != null;
- this.batch = batch;
- }
-
- public ExecutionContext getExecutionContext() {
- return batch.getGraph().getContext();
- }
-
- public void create( Path path,
- List<Property> properties ) {
- assert properties != null;
- if (properties.isEmpty()) {
- batch.create(path);
- } else {
- batch.create(path, properties);
- }
- }
-
- public void submit() {
- batch.execute();
- }
- }
-
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlSequencer.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlSequencer.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/xml/XmlSequencer.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -30,6 +30,7 @@
import org.jboss.dna.common.monitor.ProgressMonitor;
import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.properties.Name;
import org.jboss.dna.graph.properties.NameFactory;
import org.jboss.dna.graph.properties.NamespaceRegistry;
@@ -128,7 +129,6 @@
// Cached instances of the name factory and commonly referenced names
private final NameFactory nameFactory;
- private Name primaryTypeName;
private Name defaultPrimaryType;
// Recursive map used to track the number of occurrences of names for elements under a particular path
@@ -233,7 +233,7 @@
stopIfCancelled();
// Output separate nodes for each comment since multiple are allowed
startElement(DnaXmlLexicon.COMMENT);
- output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.COMMENT);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.COMMENT);
output.setProperty(path, DnaXmlLexicon.COMMENT_CONTENT, String.valueOf(ch, start, length));
endElement();
updateProgress();
@@ -281,7 +281,7 @@
if (content.length() > 0) {
// Create separate node for each content entry since entries can be interspersed amongst child elements
startElement(DnaXmlLexicon.ELEMENT_CONTENT);
- output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.ELEMENT_CONTENT);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.ELEMENT_CONTENT);
output.setProperty(path, DnaXmlLexicon.ELEMENT_CONTENT, content);
endElement();
}
@@ -380,7 +380,7 @@
// Add "synthetic" entity container to path to help prevent name collisions with XML elements
Name entityName = DnaDtdLexicon.ENTITY;
startElement(entityName);
- output.setProperty(path, getPrimaryTypeName(), entityName);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, entityName);
output.setProperty(path, nameFactory.create(DnaDtdLexicon.NAME), name);
output.setProperty(path, nameFactory.create(DnaDtdLexicon.PUBLIC_ID), publicId);
output.setProperty(path, nameFactory.create(DnaDtdLexicon.SYSTEM_ID), systemId);
@@ -401,13 +401,6 @@
monitor.getProblems().addError(error, GraphI18n.fatalErrorSequencingXmlDocument, error);
}
- private Name getPrimaryTypeName() {
- if (primaryTypeName == null) {
- primaryTypeName = nameFactory.create(NameFactory.JCR_PRIMARY_TYPE);
- }
- return primaryTypeName;
- }
-
private Name getDefaultPrimaryType() {
if (defaultPrimaryType == null) {
defaultPrimaryType = nameFactory.create(DEFAULT_PRIMARY_TYPE);
@@ -443,7 +436,7 @@
// Add "synthetic" entity container to path to help prevent name collisions with XML elements
Name entityName = DnaDtdLexicon.ENTITY;
startElement(entityName);
- output.setProperty(path, getPrimaryTypeName(), entityName);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, entityName);
output.setProperty(path, DnaDtdLexicon.NAME, name);
output.setProperty(path, DnaDtdLexicon.VALUE, value);
endElement();
@@ -478,7 +471,7 @@
// Output separate nodes for each instruction since multiple are allowed
Name name = DnaXmlLexicon.PROCESSING_INSTRUCTION;
startElement(name);
- output.setProperty(path, getPrimaryTypeName(), name);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, name);
output.setProperty(path, DnaXmlLexicon.TARGET, target);
output.setProperty(path, DnaXmlLexicon.PROCESSING_INSTRUCTION_CONTENT, data);
endElement();
@@ -524,7 +517,7 @@
@Override
public void startDocument() throws SAXException {
stopIfCancelled();
- output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.DOCUMENT);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, DnaXmlLexicon.DOCUMENT);
updateProgress();
}
@@ -603,7 +596,7 @@
}
}
startElement(nameObj);
- output.setProperty(path, getPrimaryTypeName(), type);
+ output.setProperty(path, JcrLexicon.PRIMARY_TYPE, type);
// Output this element's attributes using the attribute's namespace, if supplied, or the current namespace in scope.
String inheritedNs = nsStack.getFirst();
for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
Copied: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java (from rev 593, trunk/dna-graph/src/test/java/org/jboss/dna/graph/util/GraphImporterTest.java)
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -0,0 +1,182 @@
+/*
+ * 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.graph;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.stub;
+import java.io.File;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.transaction.xa.XAResource;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.cache.CachePolicy;
+import org.jboss.dna.graph.connectors.BasicExecutionContext;
+import org.jboss.dna.graph.connectors.RepositoryConnection;
+import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connectors.RepositorySourceException;
+import org.jboss.dna.graph.connectors.RepositorySourceListener;
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.properties.Property;
+import org.jboss.dna.graph.requests.CompositeRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
+import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.xml.DnaDtdLexicon;
+import org.jboss.dna.graph.xml.DnaXmlLexicon;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class GraphImporterTest {
+
+ private Graph graph;
+ private GraphImporter importer;
+ private String sourceName;
+ private ExecutionContext context;
+ private URI xmlContent;
+ private MockRepositoryConnection connection;
+ private Request lastExecutedRequest;
+ private Path destinationPath;
+ @Mock
+ private RepositoryConnectionFactory sources;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ xmlContent = new File("src/test/resources/repositoryImporterTestData1.xml").toURI();
+ context = new BasicExecutionContext();
+ context.getNamespaceRegistry().register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
+ context.getNamespaceRegistry().register(DnaXmlLexicon.Namespace.PREFIX, DnaXmlLexicon.Namespace.URI);
+ context.getNamespaceRegistry().register(DnaDtdLexicon.Namespace.PREFIX, DnaDtdLexicon.Namespace.URI);
+ context.getNamespaceRegistry().register("jcr", "http://www.jcp.org/jcr/1.0");
+ context.getNamespaceRegistry().register("nt", "http://www.jcp.org/jcr/nt/1.0");
+ sourceName = "sourceA";
+ destinationPath = context.getValueFactories().getPathFactory().create("/a/b");
+ graph = Graph.create(sourceName, sources, context);
+ importer = new GraphImporter(graph);
+ connection = new MockRepositoryConnection();
+ stub(sources.createConnection(sourceName)).toReturn(connection);
+ }
+
+ @Test
+ public void shouldImportXmlContentAndGenerateTheCorrectCommands() throws Exception {
+ System.out.println(xmlContent);
+ Graph.Batch batch = importer.importXml(xmlContent, new Location(destinationPath));
+ batch.execute();
+ // 'lastExecutedCommand'
+ assertThat(lastExecutedRequest, is(instanceOf(CompositeRequest.class)));
+ Iterator<Request> iter = ((CompositeRequest)lastExecutedRequest).iterator();
+ // assertCreateNode(iter, "/a/b/", "jcr:primaryType={http://www.jboss.org/dna/xml/1.0}document");
+ assertCreateNode(iter, "/a/b/dna:system[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
+ assertCreateNode(iter, "/a/b/dna:system[1]/dna:sources[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
+ assertCreateNode(iter,
+ "/a/b/dna:system[1]/dna:sources[1]/sourceA[1]",
+ "repositoryName=repositoryA",
+ "retryLimit=3",
+ "jcr:primaryType={http://www.jboss.org/dna}xyz",
+ "dna:classname=org.jboss.dna.connector.inmemory.InMemoryRepositorySource");
+ assertCreateNode(iter,
+ "/a/b/dna:system[1]/dna:sources[1]/sourceB[1]",
+ "repositoryName=repositoryB",
+ "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured",
+ "dna:classname=org.jboss.dna.connector.inmemory.InMemoryRepositorySource");
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ public void assertCreateNode( Iterator<Request> iterator,
+ String path,
+ String... properties ) {
+ Request nextCommand = iterator.next();
+ assertThat(nextCommand, is(instanceOf(CreateNodeRequest.class)));
+ CreateNodeRequest createNode = (CreateNodeRequest)nextCommand;
+ Path expectedPath = context.getValueFactories().getPathFactory().create(path);
+ assertThat(createNode.at().getPath(), is(expectedPath));
+ Map<Name, Property> propertiesByName = new HashMap<Name, Property>();
+ for (Property prop : createNode.properties()) {
+ propertiesByName.put(prop.getName(), prop);
+ }
+ for (String propertyStr : properties) {
+ if (propertyStr == "any properties") {
+ propertiesByName.clear();
+ break;
+ }
+ Matcher matcher = Pattern.compile("([^=]+)=(.*)").matcher(propertyStr);
+ if (!matcher.matches()) continue;
+ System.out.println("Property: " + propertyStr + " ==> " + matcher);
+ Name propertyName = context.getValueFactories().getNameFactory().create(matcher.group(1));
+ System.out.println("Property name: " + matcher.group(1));
+ String value = matcher.group(2); // doesn't handle multiple values!!
+ if (value.trim().length() == 0) value = null;
+ Property actual = propertiesByName.remove(propertyName);
+ Property expectedProperty = context.getPropertyFactory().create(propertyName, value);
+ assertThat("missing property " + propertyName, actual, is(expectedProperty));
+ }
+ if (!propertiesByName.isEmpty()) {
+ System.out.println("Properties for " + path + "\n" + StringUtil.readableString(propertiesByName));
+ }
+ assertThat(propertiesByName.isEmpty(), is(true));
+ }
+
+ protected class MockRepositoryConnection implements RepositoryConnection {
+ public void close() {
+ }
+
+ @SuppressWarnings( "synthetic-access" )
+ public void execute( ExecutionContext context,
+ Request request ) throws RepositorySourceException {
+ lastExecutedRequest = request;
+ }
+
+ public CachePolicy getDefaultCachePolicy() {
+ return null;
+ }
+
+ @SuppressWarnings( "synthetic-access" )
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ public XAResource getXAResource() {
+ return null;
+ }
+
+ public boolean ping( long time,
+ TimeUnit unit ) {
+ return true;
+ }
+
+ public void setListener( RepositorySourceListener listener ) {
+ }
+ }
+
+}
Property changes on: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphImporterTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlHandlerTest.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -35,7 +35,7 @@
import org.jboss.dna.common.text.Jsr283Encoder;
import org.jboss.dna.common.text.TextDecoder;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.connectors.BasicExecutionContext;
import org.jboss.dna.graph.properties.Name;
@@ -56,7 +56,7 @@
*/
public class XmlHandlerTest {
- private static final String JCR_NAMESPACE_URI = "http://www.jcp.org/jcr/1.0";
+ private static final String NT_NAMESPACE_URI = "http://www.jcp.org/jcr/nt/1.0";
private XmlHandler handler;
private ExecutionContext context;
@@ -65,37 +65,39 @@
private Path parentPath;
private TextDecoder decoder;
private Name nameAttribute;
+ private Name typeAttribute;
+ private Name typeAttributeValue;
private XmlHandler.AttributeScoping scoping;
private LinkedList<CreateNodeRequest> requests;
@Before
public void beforeEach() {
context = new BasicExecutionContext();
- context.getNamespaceRegistry().register("jcr", JCR_NAMESPACE_URI);
+ context.getNamespaceRegistry().register(JcrLexicon.Namespace.PREFIX, JcrLexicon.Namespace.URI);
+ context.getNamespaceRegistry().register("nt", NT_NAMESPACE_URI);
destination = new RecordingDestination();
parentPath = context.getValueFactories().getPathFactory().create("/a/b");
decoder = null;
- nameAttribute = context.getValueFactories().getNameFactory().create("jcr:name");
+ nameAttribute = JcrLexicon.NAME;
+ typeAttribute = null;
+ typeAttributeValue = null;
scoping = XmlHandler.AttributeScoping.USE_DEFAULT_NAMESPACE;
- handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotConstructInstanceWhenGivenNullDestination() {
destination = null;
- new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute, typeAttributeValue,
+ scoping);
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotConstructInstanceWhenGivenNullGraph() {
- Graph graph = null;
- new XmlHandler(graph, true, skipRootElement, parentPath, decoder, nameAttribute, scoping);
- }
-
@Test
public void shouldUseDefaultDecoderIfNoneIsProvidedInConstructor() {
decoder = null;
- handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
assertThat(handler.destination, is(sameInstance(destination)));
assertThat(handler.currentPath, is(sameInstance(parentPath)));
assertThat(handler.skipFirstElement, is(skipRootElement));
@@ -106,7 +108,8 @@
@Test
public void shouldUseDecoderProvidedInConstructor() {
decoder = new Jsr283Encoder();
- handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
assertThat(handler.destination, is(sameInstance(destination)));
assertThat(handler.currentPath, is(sameInstance(parentPath)));
assertThat(handler.skipFirstElement, is(skipRootElement));
@@ -117,7 +120,8 @@
@Test
public void shouldPlaceContentUnderRootIfNoPathIsProvidedInConstructor() {
parentPath = null;
- handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
assertThat(handler.destination, is(sameInstance(destination)));
assertThat(handler.currentPath.isRoot(), is(true));
assertThat(handler.skipFirstElement, is(skipRootElement));
@@ -128,7 +132,8 @@
@Test
public void shouldNotLookForNameAttributeIfNoneIsProvidedInConstructor() {
nameAttribute = null;
- handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
assertThat(handler.destination, is(sameInstance(destination)));
assertThat(handler.currentPath, is(sameInstance(parentPath)));
assertThat(handler.skipFirstElement, is(skipRootElement));
@@ -199,9 +204,11 @@
@Test
public void shouldParseXmlDocumentWithNamespacesThatAreNotYetInRegistry() throws IOException, SAXException {
NamespaceRegistry reg = context.getNamespaceRegistry();
- reg.unregister(JCR_NAMESPACE_URI);
+ reg.unregister(JcrLexicon.Namespace.URI);
+ reg.unregister(NT_NAMESPACE_URI);
// Verify the prefixes don't exist ...
- assertThat(reg.getPrefixForNamespaceUri(JCR_NAMESPACE_URI, false), is(nullValue()));
+ assertThat(reg.getPrefixForNamespaceUri(JcrLexicon.Namespace.URI, false), is(nullValue()));
+ assertThat(reg.getPrefixForNamespaceUri(NT_NAMESPACE_URI, false), is(nullValue()));
assertThat(reg.getPrefixForNamespaceUri("http://default.namespace.com", false), is(nullValue()));
// Parse the XML file ...
parse("xmlHandler/docWithNestedNamespaces.xml");
@@ -249,7 +256,8 @@
context.getNamespaceRegistry().register("c", "http://default.namespace.com");
parentPath = null;
skipRootElement = true;
- handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
parse("xmlHandler/docWithNamespaces.xml");
// Check the generated content; note that the attribute name DOES match, so the nodes names come from "jcr:name" attribute
assertNode("c:Hybrid");
@@ -264,7 +272,8 @@
@Test
public void shouldParseXmlDocumentAndShouldPlaceContentUnderNonRootNode() throws IOException, SAXException {
parentPath = context.getValueFactories().getPathFactory().create("/a/b");
- handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
context.getNamespaceRegistry().register("c", "http://default.namespace.com");
parse("xmlHandler/docWithNamespaces.xml");
// Check the generated content; note that the attribute name DOES match, so the nodes names come from "jcr:name" attribute
@@ -281,7 +290,8 @@
@Test
public void shouldParseXmlDocumentAndShouldPlaceContentUnderRootNode() throws IOException, SAXException {
parentPath = null;
- handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, scoping);
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
context.getNamespaceRegistry().register("c", "http://default.namespace.com");
parse("xmlHandler/docWithNamespaces.xml");
// Check the generated content; note that the attribute name DOES match, so the nodes names come from "jcr:name" attribute
@@ -309,6 +319,46 @@
assertNode("c:Cars/c:Sports/Infiniti G37", "maker=Infiniti", "model=G37");
}
+ @Test
+ public void shouldParseXmlDocumentWithoutNamespacesUsingTypeAttributeValue() throws IOException, SAXException {
+ typeAttribute = JcrLexicon.PRIMARY_TYPE;
+ typeAttributeValue = context.getValueFactories().getNameFactory().create("nt:unstructured");
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
+ parse("xmlHandler/docWithoutNamespaces.xml");
+ // Check the generated content; note that the attribute name doesn't match, so the nodes don't get special names
+ String unstructPrimaryType = "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured";
+ assertNode("Cars", unstructPrimaryType);
+ assertNode("Cars/Hybrid", unstructPrimaryType);
+ assertNode("Cars/Hybrid/car", unstructPrimaryType, "name=Toyota Prius", "maker=Toyota", "model=Prius");
+ assertNode("Cars/Hybrid/car", unstructPrimaryType, "name=Toyota Highlander", "maker=Toyota", "model=Highlander");
+ assertNode("Cars/Hybrid/car", unstructPrimaryType, "name=Nissan Altima", "maker=Nissan", "model=Altima");
+ assertNode("Cars/Sports", unstructPrimaryType);
+ assertNode("Cars/Sports/car", unstructPrimaryType, "name=Aston Martin DB9", "maker=Aston Martin", "model=DB9");
+ assertNode("Cars/Sports/car", unstructPrimaryType, "name=Infiniti G37", "maker=Infiniti", "model=G37");
+ }
+
+ @Test
+ public void shouldParseXmlDocumentWithNamespacesUsingTypeAttributeValue() throws IOException, SAXException {
+ context.getNamespaceRegistry().register("c", "http://default.namespace.com");
+ typeAttribute = JcrLexicon.PRIMARY_TYPE;
+ typeAttributeValue = context.getValueFactories().getNameFactory().create("nt:unstructured");
+ handler = new XmlHandler(destination, skipRootElement, parentPath, decoder, nameAttribute, typeAttribute,
+ typeAttributeValue, scoping);
+ parse("xmlHandler/docWithNamespaces.xml");
+ // Check the generated content; note that the attribute name doesn't match, so the nodes don't get special names
+ String unstructPrimaryType = "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured";
+ String carPrimaryType = "jcr:primaryType={http://default.namespace.com}car";
+ assertNode("c:Cars", unstructPrimaryType);
+ assertNode("c:Cars/c:Hybrid", unstructPrimaryType);
+ assertNode("c:Cars/c:Hybrid/Toyota Prius", carPrimaryType, "maker=Toyota", "model=Prius");
+ assertNode("c:Cars/c:Hybrid/Toyota Highlander", carPrimaryType, "maker=Toyota", "model=Highlander");
+ assertNode("c:Cars/c:Hybrid/Nissan Altima", carPrimaryType, "maker=Nissan", "model=Altima");
+ assertNode("c:Cars/c:Sports", unstructPrimaryType);
+ assertNode("c:Cars/c:Sports/Aston Martin DB9", carPrimaryType, "maker=Aston Martin", "model=DB9");
+ assertNode("c:Cars/c:Sports/Infiniti G37", carPrimaryType, "maker=Infiniti", "model=G37");
+ }
+
protected void assertNode( String path,
String... properties ) {
// Create the expected path ...
@@ -335,7 +385,16 @@
assertThat(expected, is(notNullValue()));
assertThat(actual, is(expected));
}
- assertThat(expectedProperties.isEmpty(), is(true));
+ if (!expectedProperties.isEmpty()) {
+ StringBuilder msg = new StringBuilder("missing actual properties: ");
+ boolean isFirst = true;
+ for (Property expected : expectedProperties.values()) {
+ if (!isFirst) msg.append(", ");
+ else isFirst = false;
+ msg.append(expected.getName());
+ }
+ assertThat(msg.toString(), expectedProperties.isEmpty(), is(true));
+ }
}
protected void parse( String relativePathToXmlFile ) throws IOException, SAXException {
@@ -354,7 +413,8 @@
private final LinkedList<CreateNodeRequest> requests = new LinkedList<CreateNodeRequest>();
public void create( Path path,
- List<Property> properties ) {
+ List<Property> properties,
+ Name elementName ) {
requests.add(new CreateNodeRequest(new Location(path), properties));
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlSequencerTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlSequencerTest.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/xml/XmlSequencerTest.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -31,7 +31,6 @@
import org.jboss.dna.common.monitor.ProgressMonitor;
import org.jboss.dna.common.monitor.SimpleProgressMonitor;
import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.NameFactory;
import org.jboss.dna.graph.sequencers.MockSequencerContext;
import org.jboss.dna.graph.sequencers.MockSequencerOutput;
import org.jboss.dna.graph.sequencers.SequencerContext;
@@ -102,38 +101,38 @@
@Test
public void shouldSequenceXml() throws IOException {
verifyDocument(xml1);
- verifyName(COMMENT + "[1]", NameFactory.JCR_PRIMARY_TYPE, COMMENT);
+ verifyName(COMMENT + "[1]", "jcr:primaryType", COMMENT);
String text = verify(COMMENT + "[1]", COMMENT_CONTENT, String.class);
assertThat(text.startsWith("\n Licensed to the Apache Software Foundation (ASF)"), is(true));
assertThat(text.endsWith(" limitations under the License.\n"), is(true));
verifyString("/", DTD_NAME, "Repository");
verifyString("/", DTD_PUBLIC_ID, "-//The Apache Software Foundation//DTD Jackrabbit 1.2//EN");
verifyString("/", DTD_SYSTEM_ID, "http://jackrabbit.apache.org/dtd/repository-1.2.dtd");
- verifyName(COMMENT + "[2]", NameFactory.JCR_PRIMARY_TYPE, COMMENT);
+ verifyName(COMMENT + "[2]", "jcr:primaryType", COMMENT);
verifyString(COMMENT + "[2]", COMMENT_CONTENT, " Example Repository Configuration File ");
- verifyName("Repository[1]", NameFactory.JCR_PRIMARY_TYPE, "nt:unstructured");
- verifyName("Repository[1]/" + COMMENT + "[1]", NameFactory.JCR_PRIMARY_TYPE, COMMENT);
+ verifyName("Repository[1]", "jcr:primaryType", "nt:unstructured");
+ verifyName("Repository[1]/" + COMMENT + "[1]", "jcr:primaryType", COMMENT);
}
@Test
public void shouldHandleNamespaces() throws IOException {
verifyDocument(xml2);
- verifyName("book[1]/bookinfo[1]/xi:include[1]", NameFactory.JCR_PRIMARY_TYPE, "nt:unstructured");
+ verifyName("book[1]/bookinfo[1]/xi:include[1]", "jcr:primaryType", "nt:unstructured");
verifyString("book[1]/bookinfo[1]/xi:include[1]", "xi:href", "Author_Group.xml");
- verifyName("book[1]/bookinfo[1]/xi:include[2]", NameFactory.JCR_PRIMARY_TYPE, "nt:unstructured");
+ verifyName("book[1]/bookinfo[1]/xi:include[2]", "jcr:primaryType", "nt:unstructured");
verifyString("book[1]/bookinfo[1]/xi:include[2]", "xi:href", "Legal_Notice.xml");
}
@Test
public void shouldSequenceEntityDeclarations() throws IOException {
verifyDocument(xml2);
- verifyName(ENTITY + "[1]", NameFactory.JCR_PRIMARY_TYPE, ENTITY);
+ verifyName(ENTITY + "[1]", "jcr:primaryType", ENTITY);
verifyString(ENTITY + "[1]", DTD_NAME, "%RH-ENTITIES");
verifyString(ENTITY + "[1]", DTD_SYSTEM_ID, "Common_Config/rh-entities.ent");
- verifyName(ENTITY + "[2]", NameFactory.JCR_PRIMARY_TYPE, ENTITY);
+ verifyName(ENTITY + "[2]", "jcr:primaryType", ENTITY);
verifyString(ENTITY + "[2]", DTD_NAME, "versionNumber");
verifyString(ENTITY + "[2]", DTD_VALUE, "0.1");
- verifyName(ENTITY + "[3]", NameFactory.JCR_PRIMARY_TYPE, ENTITY);
+ verifyName(ENTITY + "[3]", "jcr:primaryType", ENTITY);
verifyString(ENTITY + "[3]", DTD_NAME, "copyrightYear");
verifyString(ENTITY + "[3]", DTD_VALUE, "2008");
}
@@ -173,7 +172,7 @@
@Test
public void shouldSequenceProcessingInstructions() throws IOException {
verifyDocument(xml4);
- verifyName(PI + "[1]", NameFactory.JCR_PRIMARY_TYPE, PI);
+ verifyName(PI + "[1]", "jcr:primaryType", PI);
verifyString(PI + "[1]", TARGET, "eclipse");
verifyString(PI + "[1]", PI_CONTENT, "version=\"3.0\"");
}
@@ -181,10 +180,10 @@
@Test
public void shouldSequenceXsds() throws IOException {
verifyDocument(xsd);
- verifyName("xs:schema[1]", NameFactory.JCR_PRIMARY_TYPE, "nt:unstructured");
+ verifyName("xs:schema[1]", "jcr:primaryType", "nt:unstructured");
verifyString("xs:schema[1]", "xs:targetNamespace", "http://ns.adobe.com/air/application/1.0");
verifyString("xs:schema[1]", "xs:elementFormDefault", "qualified");
- verifyName("xs:schema[1]/xs:element[1]", NameFactory.JCR_PRIMARY_TYPE, "nt:unstructured");
+ verifyName("xs:schema[1]/xs:element[1]", "jcr:primaryType", "nt:unstructured");
verifyString("xs:schema[1]/xs:element[1]", "xs:name", "application");
}
@@ -203,7 +202,7 @@
stream = url.openStream();
assertThat(stream, is(notNullValue()));
sequencer.sequence(stream, output, context, monitor);
- verifyName("", NameFactory.JCR_PRIMARY_TYPE, DOCUMENT);
+ verifyName("", "jcr:primaryType", DOCUMENT);
}
private void verifyName( String nodePath,
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -21,18 +21,10 @@
*/
package org.jboss.dna.jcr;
-import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.basic.BasicName;
/**
* @author Randall Hauch
*/
-class JcrLexicon {
+class JcrLexicon extends org.jboss.dna.graph.JcrLexicon {
- public static class Namespace {
- public static final String URI = "http://www.jcp.org/jcr/1.0";
- public static final String PREFIX = "jcr";
- }
-
- public static final Name UUID = new BasicName(Namespace.URI, "uuid");
}
Modified: 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 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencerOutputMap.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -32,8 +32,8 @@
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.NameFactory;
import org.jboss.dna.graph.properties.Path;
import org.jboss.dna.graph.properties.PathFactory;
import org.jboss.dna.graph.properties.ValueFactories;
@@ -230,8 +230,8 @@
*/
public int compareTo( PropertyValue that ) {
if (this == that) return 0;
- if (this.name.equals(NameFactory.JCR_PRIMARY_TYPE)) return -1;
- if (that.name.equals(NameFactory.JCR_PRIMARY_TYPE)) return 1;
+ if (this.name.equals(JcrLexicon.PRIMARY_TYPE)) return -1;
+ if (that.name.equals(JcrLexicon.PRIMARY_TYPE)) return 1;
return this.name.compareTo(that.name);
}
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerNodeContextTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerNodeContextTest.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencerNodeContextTest.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -30,7 +30,6 @@
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.jboss.dna.common.jcr.AbstractJcrRepositoryTest;
-import org.jboss.dna.graph.properties.NameFactory;
import org.jboss.dna.graph.properties.NamespaceRegistry;
import org.jboss.dna.graph.properties.Property;
import org.jboss.dna.graph.sequencers.SequencerContext;
@@ -160,7 +159,7 @@
assertThat(sequencerContext.getInputProperties().isEmpty(), is(false));
assertThat(sequencerContext.getInputProperties().size(), is(3));
verifyProperty(sequencerContext,
- NameFactory.JCR_PRIMARY_TYPE,
+ "jcr:primaryType",
execContext.getValueFactories().getNameFactory().create("{http://www.jcp.org/jcr/nt/1.0}unstructured"));
verifyProperty(sequencerContext, "x", true);
verifyProperty(sequencerContext, "y", "asdf", "xyzzy");
Modified: trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java 2008-10-29 15:16:23 UTC (rev 596)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java 2008-10-29 17:48:23 UTC (rev 597)
@@ -54,6 +54,7 @@
import org.jboss.dna.jcr.JcrRepository;
import org.jboss.dna.repository.RepositoryLibrary;
import org.jboss.dna.repository.RepositoryService;
+import org.xml.sax.SAXException;
/**
* @author Randall Hauch
@@ -122,9 +123,10 @@
* repositories.
*
* @throws IOException if there is a problem initializing the repositories from the files.
+ * @throws SAXException if there is a problem with the SAX Parser
* @throws NamingException if there is a problem registering or looking up objects in JNDI
*/
- public void startRepositories() throws IOException, NamingException {
+ public void startRepositories() throws IOException, SAXException, NamingException {
if (repositoryService != null) return; // already started
// Create the factory for execution contexts.
15 years, 6 months
DNA SVN: r596 - trunk/dna-common/src/main/java/org/jboss/dna/common/util.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-10-29 11:16:23 -0400 (Wed, 29 Oct 2008)
New Revision: 596
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/util/Logger.java
Log:
Removed (unused) methods to determine if error, info, or warning messages are enabled. The code using the logger should never be concerned with this, as it should just log the messages at the appropriate level.
There still are methods to determine if debug and trace messages are enabled. However, since these methods are intended for developers (note that they do not take I18n but take strings) and because such methods may require doing more work to prepare the messages (e.g., processing and accumulating information that you'd normally not do), it is still useful to know whether debug or trace is enabled.
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-10-28 23:47:02 UTC (rev 595)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/Logger.java 2008-10-29 15:16:23 UTC (rev 596)
@@ -369,7 +369,7 @@
*
* @return true if INFORMATION log messages are currently being logged, or false otherwise.
*/
- public boolean isInfoEnabled() {
+ protected boolean isInfoEnabled() {
return this.delegate.isInfoEnabled();
}
@@ -378,7 +378,7 @@
*
* @return true if WARNING log messages are currently being logged, or false otherwise.
*/
- public boolean isWarnEnabled() {
+ protected boolean isWarnEnabled() {
return this.delegate.isWarnEnabled();
}
@@ -387,7 +387,7 @@
*
* @return true if ERROR log messages are currently being logged, or false otherwise.
*/
- public boolean isErrorEnabled() {
+ protected boolean isErrorEnabled() {
return this.delegate.isErrorEnabled();
}
15 years, 6 months
DNA SVN: r595 - in trunk/dna-graph/src: main/java/org/jboss/dna/graph/properties/basic and 1 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-10-28 19:47:02 -0400 (Tue, 28 Oct 2008)
New Revision: 595
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Name.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Path.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPath.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPathSegment.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicNameTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathSegmentTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathTest.java
Log:
DNA-245 - Add methods to Name, Path.Segment, and Path to allow using custom delimiters
http://jira.jboss.com/jira/browse/DNA-245
Added to Name, Path.Segment, and Path the "getString(NamespaceRegistry, TextEncoder, TextEncoder)" method, which uses the 2nd encoder to preprocess the various delimiters. These methods can be used, for example, to escape (or convert) the delimiters in a Path (for example, to escape the ":" as needed by a file system, or to convert "/" to a different delimiter.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Name.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Name.java 2008-10-28 19:21:10 UTC (rev 594)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Name.java 2008-10-28 23:47:02 UTC (rev 595)
@@ -24,9 +24,11 @@
import java.io.Serializable;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.graph.properties.Path.Segment;
/**
* A qualified name consisting of a namespace and a local name.
+ *
* @author Randall Hauch
*/
@Immutable
@@ -34,12 +36,14 @@
/**
* Get the local name part of this qualified name.
+ *
* @return the local name; never null
*/
String getLocalName();
/**
* Get the URI for the namespace used in this qualified name.
+ *
* @return the URI; never null but possibly empty
*/
String getNamespaceUri();
@@ -47,6 +51,7 @@
/**
* Get the string form of the name. The {@link Path#DEFAULT_ENCODER default encoder} is used to encode characters in the local
* name and namespace.
+ *
* @return the encoded string
* @see #getString(TextEncoder)
*/
@@ -54,6 +59,7 @@
/**
* Get the encoded string form of the name, using the supplied encoder to encode characters in the local name and namespace.
+ *
* @param encoder the encoder to use, or null if the {@link Path#DEFAULT_ENCODER default encoder} should be used
* @return the encoded string
* @see #getString()
@@ -61,11 +67,12 @@
public String getString( TextEncoder encoder );
/**
- * Get the string form of the name, using the supplied namespace registry to convert the
- * {@link #getNamespaceUri() namespace URI} to a prefix. The {@link Path#DEFAULT_ENCODER default encoder} is used to encode
- * characters in each of the path segments.
+ * Get the string form of the name, using the supplied namespace registry to convert the {@link #getNamespaceUri() namespace
+ * URI} to a prefix. The {@link Path#DEFAULT_ENCODER default encoder} is used to encode characters in each of the path
+ * segments.
+ *
* @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
- * {@link Name#getNamespaceUri() namespace URI}
+ * {@link Name#getNamespaceUri() namespace URI}
* @return the encoded string
* @throws IllegalArgumentException if the namespace registry is null
* @see #getString(NamespaceRegistry,TextEncoder)
@@ -73,14 +80,36 @@
public String getString( NamespaceRegistry namespaceRegistry );
/**
- * Get the encoded string form of the name, using the supplied namespace registry to convert the
- * {@link #getNamespaceUri() namespace URI} to a prefix.
+ * Get the encoded string form of the name, using the supplied namespace registry to convert the {@link #getNamespaceUri()
+ * namespace URI} to a prefix.
+ *
* @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
- * {@link Name#getNamespaceUri() namespace URI}
+ * {@link Name#getNamespaceUri() namespace URI}
* @param encoder the encoder to use, or null if the {@link Path#DEFAULT_ENCODER default encoder} should be used
* @return the encoded string
* @throws IllegalArgumentException if the namespace registry is null
* @see #getString(NamespaceRegistry)
*/
- public String getString( NamespaceRegistry namespaceRegistry, TextEncoder encoder );
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder );
+
+ /**
+ * Get the encoded string form of the name, using the supplied namespace registry to convert the names' namespace URIs to
+ * prefixes and the supplied encoder to encode characters in each of the path segments, and using the second delimiter to
+ * encode (or convert) the delimiter used between the namespace prefix and the local part.
+ *
+ * @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
+ * {@link Name#getNamespaceUri() namespace URIs} in the segment {@link Segment#getName() names}
+ * @param encoder the encoder to use for encoding the {@link Name#getLocalName() local part} and
+ * {@link Name#getNamespaceUri() namespace prefix}, or null if the {@link Path#DEFAULT_ENCODER default encoder} should
+ * be used
+ * @param delimiterEncoder the encoder to use for encoding the delimiter between the {@link Name#getLocalName() local part}
+ * and {@link Name#getNamespaceUri() namespace prefix}, or null if the standard delimiter should be used
+ * @return the encoded string
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder );
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Path.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Path.java 2008-10-28 19:21:10 UTC (rev 594)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Path.java 2008-10-28 23:47:02 UTC (rev 595)
@@ -237,6 +237,28 @@
*/
public String getString( NamespaceRegistry namespaceRegistry,
TextEncoder encoder );
+
+ /**
+ * Get the encoded string form of the segment, using the supplied namespace registry to convert the names' namespace URIs
+ * to prefixes and the supplied encoder to encode characters in each of the path segments. The second encoder is used to
+ * encode (or convert) the delimiter between the {@link Name#getNamespaceUri() namespace prefix} and the
+ * {@link Name#getLocalName() local part}.
+ *
+ * @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
+ * {@link Name#getNamespaceUri() namespace URIs} in the segment {@link Segment#getName() names}
+ * @param encoder the encoder to use for encoding the {@link Name#getLocalName() local part} and
+ * {@link Name#getNamespaceUri() namespace prefix} in the segment's {@link #getName() name}, or null if the
+ * {@link #DEFAULT_ENCODER default encoder} should be used
+ * @param delimiterEncoder the encoder to use for encoding the delimiter between the {@link Name#getLocalName() local
+ * part} and {@link Name#getNamespaceUri() namespace prefix} of each {@link Path#getSegmentsList() segment}, or
+ * null if the standard delimiters should be used
+ * @return the encoded string
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder );
}
/**
@@ -503,13 +525,16 @@
/**
* Get the string form of the path, using the supplied namespace registry to convert the names' namespace URIs to prefixes.
- * The {@link #DEFAULT_ENCODER default encoder} is used to encode characters in each of the path segments.
+ * The {@link #DEFAULT_ENCODER default encoder} is used to encode characters in each of the path segments. The second encoder
+ * is used to encode (or convert) the delimiter between the {@link Name#getNamespaceUri() namespace prefix} and the
+ * {@link Name#getLocalName() local part}.
*
* @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
* {@link Name#getNamespaceUri() namespace URIs} in the segment {@link Segment#getName() names}
* @return the encoded string
* @throws IllegalArgumentException if the namespace registry is null
* @see #getString(NamespaceRegistry,TextEncoder)
+ * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
*/
public String getString( NamespaceRegistry namespaceRegistry );
@@ -519,12 +544,35 @@
*
* @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
* {@link Name#getNamespaceUri() namespace URIs} in the segment {@link Segment#getName() names}
- * @param encoder the encoder to use, or null if the {@link #DEFAULT_ENCODER default encoder} should be used
+ * @param encoder the encoder to use for encoding the {@link Name#getLocalName() local part} and
+ * {@link Name#getNamespaceUri() namespace prefix} of each {@link Path#getSegmentsList() segment}, or null if the
+ * {@link #DEFAULT_ENCODER default encoder} should be used
* @return the encoded string
* @throws IllegalArgumentException if the namespace registry is null
* @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
*/
public String getString( NamespaceRegistry namespaceRegistry,
TextEncoder encoder );
+ /**
+ * Get the encoded string form of the path, using the supplied namespace registry to convert the names' namespace URIs to
+ * prefixes and the supplied encoder to encode characters in each of the path segments.
+ *
+ * @param namespaceRegistry the namespace registry that should be used to obtain the prefix for the
+ * {@link Name#getNamespaceUri() namespace URIs} in the segment {@link Segment#getName() names}
+ * @param encoder the encoder to use for encoding the {@link Name#getLocalName() local part} and
+ * {@link Name#getNamespaceUri() namespace prefix} of each {@link Path#getSegmentsList() segment}, or null if the
+ * {@link #DEFAULT_ENCODER default encoder} should be used
+ * @param delimiterEncoder the encoder to use for encoding the delimiter between the {@link Name#getLocalName() local part}
+ * and {@link Name#getNamespaceUri() namespace prefix} of each {@link Path#getSegmentsList() segment}, and for encoding
+ * the path delimiter, or null if the standard delimiters should be used
+ * @return the encoded string
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder );
+
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java 2008-10-28 19:21:10 UTC (rev 594)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java 2008-10-28 23:47:02 UTC (rev 595)
@@ -103,6 +103,7 @@
*/
public String getString( NamespaceRegistry namespaceRegistry,
TextEncoder encoder ) {
+ // This is the most-often used method, so implement it directly
CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
String prefix = namespaceRegistry.getPrefixForNamespaceUri(this.namespaceUri, true);
if (prefix != null && prefix.length() != 0) {
@@ -113,7 +114,37 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.properties.Name#getString(org.jboss.dna.graph.properties.NamespaceRegistry,
+ * org.jboss.dna.common.text.TextEncoder, org.jboss.dna.common.text.TextEncoder)
*/
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder ) {
+ if (namespaceRegistry == null) {
+ if (this.getNamespaceUri().length() == 0) {
+ if (this.getLocalName().equals(Path.SELF)) return Path.SELF;
+ if (this.getLocalName().equals(Path.PARENT)) return Path.PARENT;
+ }
+ if (encoder == null) encoder = Path.DEFAULT_ENCODER;
+ if (delimiterEncoder != null) {
+ return delimiterEncoder.encode("{") + encoder.encode(this.namespaceUri) + delimiterEncoder.encode("}")
+ + encoder.encode(this.localName);
+ }
+ return "{" + encoder.encode(this.namespaceUri) + "}" + encoder.encode(this.localName);
+
+ }
+ String prefix = namespaceRegistry.getPrefixForNamespaceUri(this.namespaceUri, true);
+ if (prefix != null && prefix.length() != 0) {
+ String delim = delimiterEncoder != null ? delimiterEncoder.encode(":") : ":";
+ return encoder.encode(prefix) + delim + encoder.encode(this.localName);
+ }
+ return this.localName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public int compareTo( Name that ) {
if (that == this) return 0;
int diff = this.getNamespaceUri().compareTo(that.getNamespaceUri());
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPath.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPath.java 2008-10-28 19:21:10 UTC (rev 594)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPath.java 2008-10-28 23:47:02 UTC (rev 595)
@@ -199,14 +199,14 @@
* {@inheritDoc}
*/
public String getString() {
- return doGetString(null, DEFAULT_ENCODER);
+ return doGetString(null, DEFAULT_ENCODER, null);
}
/**
* {@inheritDoc}
*/
public String getString( TextEncoder encoder ) {
- return doGetString(null, encoder);
+ return doGetString(null, encoder, null);
}
/**
@@ -214,7 +214,7 @@
*/
public String getString( NamespaceRegistry namespaceRegistry ) {
CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
- return doGetString(namespaceRegistry, null);
+ return doGetString(namespaceRegistry, null, null);
}
/**
@@ -223,44 +223,55 @@
public String getString( NamespaceRegistry namespaceRegistry,
TextEncoder encoder ) {
CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
- return doGetString(namespaceRegistry, encoder);
+ return doGetString(namespaceRegistry, encoder, null);
}
/**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.properties.Path#getString(org.jboss.dna.graph.properties.NamespaceRegistry,
+ * org.jboss.dna.common.text.TextEncoder, org.jboss.dna.common.text.TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder ) {
+ return doGetString(namespaceRegistry, encoder, delimiterEncoder);
+ }
+
+ /**
* Method that creates the string representation. This method works two different ways depending upon whether the namespace
* registry is provided.
*
* @param namespaceRegistry
* @param encoder
+ * @param delimiterEncoder
* @return this path as a string
*/
protected String doGetString( NamespaceRegistry namespaceRegistry,
- TextEncoder encoder ) {
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder ) {
if (encoder == null) encoder = DEFAULT_ENCODER;
- if (encoder == DEFAULT_ENCODER && this.path != null) return this.path;
+ if (encoder == DEFAULT_ENCODER && this.path != null && delimiterEncoder == null) return this.path;
+ final String delimiter = delimiterEncoder != null ? delimiterEncoder.encode(DELIMITER_STR) : DELIMITER_STR;
// Since the segments are immutable, this code need not be synchronized because concurrent threads
// may just compute the same value (with no harm done)
StringBuilder sb = new StringBuilder();
- if (this.isAbsolute()) sb.append(DELIMITER);
+ if (this.isAbsolute()) sb.append(delimiter);
boolean first = true;
for (Segment segment : this.segments) {
if (first) {
first = false;
} else {
- sb.append(DELIMITER);
+ sb.append(delimiter);
}
assert segment != null;
- if (namespaceRegistry != null) {
- sb.append(segment.getString(namespaceRegistry, encoder));
- } else {
- sb.append(segment.getString(encoder));
- }
+ sb.append(segment.getString(namespaceRegistry, encoder, delimiterEncoder));
}
String result = sb.toString();
// Save the result to the internal string if this the default encoder is used.
// This is not synchronized, but it's okay
- if (encoder == DEFAULT_ENCODER && this.path == null) this.path = result;
+ if (encoder == DEFAULT_ENCODER && this.path == null && delimiterEncoder == null) this.path = result;
return result;
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPathSegment.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPathSegment.java 2008-10-28 19:21:10 UTC (rev 594)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPathSegment.java 2008-10-28 23:47:02 UTC (rev 595)
@@ -179,13 +179,23 @@
*/
public String getString( NamespaceRegistry namespaceRegistry,
TextEncoder encoder ) {
- CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
+ return getString(namespaceRegistry, encoder, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.properties.Path.Segment#getString(org.jboss.dna.graph.properties.NamespaceRegistry,
+ * org.jboss.dna.common.text.TextEncoder, org.jboss.dna.common.text.TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder ) {
if (encoder == null) encoder = Path.DEFAULT_ENCODER;
- String encodedName = this.getName().getString(namespaceRegistry, encoder);
+ String encodedName = this.getName().getString(namespaceRegistry, encoder, delimiterEncoder);
if (this.hasIndex()) {
return encodedName + "[" + this.getIndex() + "]";
}
return encodedName;
}
-
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicNameTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicNameTest.java 2008-10-28 19:21:10 UTC (rev 594)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicNameTest.java 2008-10-28 23:47:02 UTC (rev 595)
@@ -24,12 +24,11 @@
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.containsString;
+import org.jboss.dna.common.text.Jsr283Encoder;
import org.jboss.dna.common.text.TextEncoder;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.properties.Name;
import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.basic.BasicName;
-import org.jboss.dna.graph.properties.basic.BasicNamespaceRegistry;
import org.junit.Before;
import org.junit.Test;
@@ -44,6 +43,7 @@
private String validNamespaceUri;
private String validLocalName;
private TextEncoder encoder;
+ private TextEncoder delimiterEncoder;
private String validNamespacePrefix;
@Before
@@ -55,6 +55,14 @@
this.encoder = Path.URL_ENCODER;
this.namespaceRegistry = new BasicNamespaceRegistry();
this.namespaceRegistry.register(validNamespacePrefix, validNamespaceUri);
+ this.delimiterEncoder = new TextEncoder() {
+ public String encode( String text ) {
+ if (":".equals(text)) return "\\:";
+ if ("{".equals(text)) return "\\{";
+ if ("}".equals(text)) return "\\}";
+ return text;
+ }
+ };
}
@Test
@@ -171,4 +179,13 @@
result = name.getString(namespaceRegistry, encoder);
assertThat(result, is("some:name:with:colons"));
}
+
+ @Test
+ public void shouldUseDelimiterEncoderToEncodeDelimiterBetweenPrefixAndLocalPart() {
+ encoder = new Jsr283Encoder();
+ name = new BasicName(DnaLexicon.Namespace.URI, "some:name:with:colons");
+ assertThat(name.getString(namespaceRegistry, encoder, delimiterEncoder), is("dna\\:some\uf03aname\uf03awith\uf03acolons"));
+ assertThat(name.getString(null, encoder, delimiterEncoder), is("\\{" + encoder.encode(DnaLexicon.Namespace.URI)
+ + "\\}some\uf03aname\uf03awith\uf03acolons"));
+ }
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathSegmentTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathSegmentTest.java 2008-10-28 19:21:10 UTC (rev 594)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathSegmentTest.java 2008-10-28 23:47:02 UTC (rev 595)
@@ -24,16 +24,12 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;
+import org.jboss.dna.common.text.Jsr283Encoder;
import org.jboss.dna.common.text.TextEncoder;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.properties.Name;
import org.jboss.dna.graph.properties.Path;
import org.jboss.dna.graph.properties.ValueFactory;
-import org.jboss.dna.graph.properties.basic.BasicNamespaceRegistry;
-import org.jboss.dna.graph.properties.basic.BasicPathSegment;
-import org.jboss.dna.graph.properties.basic.NameValueFactory;
-import org.jboss.dna.graph.properties.basic.PathValueFactory;
-import org.jboss.dna.graph.properties.basic.StringValueFactory;
import org.junit.Before;
import org.junit.Test;
@@ -163,4 +159,21 @@
assertThat(segment, is(not(segment2)));
}
+ @Test
+ public void shouldUseDelimiterEncoderToEncodeDelimiterBetweenPrefixAndLocalPart() {
+ TextEncoder encoder = new Jsr283Encoder();
+ validName = new BasicName(DnaLexicon.Namespace.URI, "some:name:with:colons");
+ segment = new BasicPathSegment(validName, Path.NO_INDEX);
+ TextEncoder delimiterEncoder = new TextEncoder() {
+ public String encode( String text ) {
+ if (":".equals(text)) return "\\:";
+ if ("{".equals(text)) return "\\{";
+ if ("}".equals(text)) return "\\}";
+ return text;
+ }
+ };
+ assertThat(segment.getString(registry, encoder, delimiterEncoder), is("dna\\:some\uf03aname\uf03awith\uf03acolons"));
+ assertThat(segment.getString(null, encoder, delimiterEncoder), is("\\{" + encoder.encode(DnaLexicon.Namespace.URI)
+ + "\\}some\uf03aname\uf03awith\uf03acolons"));
+ }
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathTest.java 2008-10-28 19:21:10 UTC (rev 594)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathTest.java 2008-10-28 23:47:02 UTC (rev 595)
@@ -31,6 +31,7 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import org.jboss.dna.common.text.Jsr283Encoder;
import org.jboss.dna.common.text.TextEncoder;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.properties.InvalidPathException;
@@ -898,4 +899,35 @@
path = pathFactory.create("a/b/c");
assertThat(path, hasSegments(pathFactory, "a", "b", "c"));
}
+
+ @Test
+ public void shouldConvertPathToString() {
+ TextEncoder encoder = new Jsr283Encoder();
+ TextEncoder delimEncoder = new TextEncoder() {
+ public String encode( String text ) {
+ if ("/".equals(text)) return "\\/";
+ if (":".equals(text)) return "\\:";
+ if ("{".equals(text)) return "\\{";
+ if ("}".equals(text)) return "\\}";
+ return text;
+ }
+ };
+ Path path = pathFactory.create("a/b/c");
+ assertThat(path.getString(namespaceRegistry), is("a/b/c"));
+ assertThat(path.getString(namespaceRegistry, encoder), is("a/b/c"));
+ assertThat(path.getString(namespaceRegistry, encoder, delimEncoder), is("a\\/b\\/c"));
+
+ path = pathFactory.create("/a/b/c");
+ assertThat(path.getString(namespaceRegistry), is("/a/b/c"));
+ assertThat(path.getString(namespaceRegistry, encoder), is("/a/b/c"));
+ assertThat(path.getString(namespaceRegistry, encoder, delimEncoder), is("\\/a\\/b\\/c"));
+
+ path = pathFactory.create("/dna:a/b/c");
+ assertThat(path.getString(encoder), is("/{" + encoder.encode(DnaLexicon.Namespace.URI) + "}a/{}b/{}c"));
+ assertThat(path.getString(null, encoder, delimEncoder), is("\\/\\{" + encoder.encode(DnaLexicon.Namespace.URI)
+ + "\\}a\\/\\{\\}b\\/\\{\\}c"));
+ assertThat(path.getString(namespaceRegistry), is("/dna:a/b/c"));
+ assertThat(path.getString(namespaceRegistry, encoder), is("/dna:a/b/c"));
+ assertThat(path.getString(namespaceRegistry, encoder, delimEncoder), is("\\/dna\\:a\\/b\\/c"));
+ }
}
15 years, 6 months
DNA SVN: r594 - in trunk/dna-common/src/main/java/org/jboss/dna/common: util and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-10-28 15:21:10 -0400 (Tue, 28 Oct 2008)
New Revision: 594
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java
Log:
Removed the static constant for an empty string, as Java always interns all string literals such as "". So, there is no performance or efficiency benefit, and its simpler (if not shorter) to use "" rather than a constant.
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-10-28 17:55:47 UTC (rev 593)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java 2008-10-28 19:21:10 UTC (rev 594)
@@ -32,7 +32,6 @@
import org.jboss.dna.common.collection.ThreadSafeProblems;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.StringUtil;
/**
* A basic progress monitor.
@@ -64,8 +63,8 @@
public SimpleProgressMonitor( String activityName,
ProgressMonitor parentProgressMonitor ) {
- this.activityName = activityName == null ? StringUtil.EMPTY_STRING : activityName.trim();
- this.parentActivityName = parentProgressMonitor == null ? StringUtil.EMPTY_STRING : parentProgressMonitor.getActivityName();
+ this.activityName = activityName == null ? "" : activityName.trim();
+ this.parentActivityName = parentProgressMonitor == null ? "" : parentProgressMonitor.getActivityName();
this.taskName = null;
this.taskNameParams = null;
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java 2008-10-28 17:55:47 UTC (rev 593)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java 2008-10-28 19:21:10 UTC (rev 594)
@@ -45,7 +45,6 @@
*/
public class StringUtil {
- public static final String EMPTY_STRING = "";
public static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final Pattern NORMALIZE_PATTERN = Pattern.compile("\\s+");
private static final Pattern PARAMETER_COUNT_PATTERN = Pattern.compile("\\{(\\d+)\\}");
15 years, 6 months
DNA SVN: r593 - in trunk: dna-common/src/test/java/org/jboss/dna/common/monitor and 1 other directories.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-10-28 13:55:47 -0400 (Tue, 28 Oct 2008)
New Revision: 593
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java
trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java
trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java
Log:
DNA-186: Added getParentActivity method to ProgressMonitor that returns the name of the parent activity that spawned the activity for the monitor.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java 2008-10-28 17:53:41 UTC (rev 592)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitor.java 2008-10-28 17:55:47 UTC (rev 593)
@@ -32,14 +32,15 @@
* code that monitors progress as an <strong>Observer</strong>.
* <p>
* The progress of each {@link #getActivityName() activity} is started when the <strong>Updater</strong> calls
- * {@link #beginTask(double, I18n, Object...)}, continues with a mixture of work ({@link #worked(double)}) and subtasks ({@link #createSubtask(double)}),
- * and finishes when the activity is completed ({@link #done()}) or cancelled ({@link #setCancelled(boolean)}).
+ * {@link #beginTask(double, I18n, Object...)}, continues with a mixture of work ({@link #worked(double)}) and subtasks (
+ * {@link #createSubtask(double)}), and finishes when the activity is completed ({@link #done()}) or cancelled (
+ * {@link #setCancelled(boolean)}).
* </p>
* <p>
- * If an activity is interrupted before its normal completion due to a cancellation request by an <strong>Observer</strong>, it
- * is still the responsibility of the <strong>Updater</strong> to mark the activity as completed. Similarly, if an activity
- * cannot be cancelled before its normal completion, the <strong>Updater</strong> must deny any previous cancellation request by
- * calling {@link #setCancelled(boolean) setCancelled(false)}.
+ * If an activity is interrupted before its normal completion due to a cancellation request by an <strong>Observer</strong>, it is
+ * still the responsibility of the <strong>Updater</strong> to mark the activity as completed. Similarly, if an activity cannot be
+ * cancelled before its normal completion, the <strong>Updater</strong> must deny any previous cancellation request by calling
+ * {@link #setCancelled(boolean) setCancelled(false)}.
* </p>
*
* @author Randall Hauch
@@ -48,14 +49,6 @@
public interface ProgressMonitor {
/**
- * Get the name of the activity. This should never change for a progress monitor, and all
- * {@link #createSubtask(double) subtasks} should have the same name.
- *
- * @return the activity's name
- */
- String getActivityName();
-
- /**
* Called by the <strong>Updater</strong> to indicate work has started on the task, specifying the total amount of work that
* this task constitutes.
*
@@ -68,13 +61,6 @@
Object... params );
/**
- * Called by the <strong>Updater</strong> to report work completed for this task.
- *
- * @param work the number of work units that have been worked
- */
- void worked( double work );
-
- /**
* Called by the <strong>Updater</strong> to create a subtask with the given about of work. The resulting progress monitor
* must be started ({@link #beginTask(double, I18n, Object...)}) and finished ({@link #done()}).
*
@@ -90,32 +76,32 @@
void done();
/**
- * Return whether this activity has completed.
+ * Get the name of the activity. This should never change for a progress monitor, and all {@link #createSubtask(double)
+ * subtasks} should have the same name.
*
- * @return <code>true</code> if this activity has completed.
+ * @return the activity's name; never <code>null</code>
*/
- boolean isDone();
+ String getActivityName();
/**
- * Called by an <strong>Observer</strong> to request the cancellation of this activity, or by the <strong>Updater</strong>
- * to deny a prior cancellation request (i.e., when the activity {@link #done() completes} before the <strong>Updater</strong>
- * recognizes a cancellation request by an <strong>Observer</strong>).
+ * Get the name of the activity that spawned this activity. This should never change for a progress monitor.
*
- * @param value <code>true</code> if requesting the activity be cancelled.
+ * @return the parent activity's name; never <code>null</code>
*/
- void setCancelled( boolean value );
+ String getParentActivityName();
/**
- * Return whether a request was made by an <strong>Observer</strong> to {@link #setCancelled(boolean) cancel} this activity.
+ * Return the problems encountered during the {@link #getStatus(Locale) progress} made towards completing the associated
+ * {@link #getActivityName() activity}.
*
- * @return <code>true</code> if this activity has been requested to be cancelled.
+ * @return the list of problems
*/
- boolean isCancelled();
+ Problems getProblems();
/**
* Return the current status of this activity, localized to the specified locale. This method returns an immutable but
- * consistent snapshot of the status for this activity. Note that if this instance is a {@link #createSubtask(double) subtask},
- * this method returns the status of the subtask.
+ * consistent snapshot of the status for this activity. Note that if this instance is a {@link #createSubtask(double) subtask}
+ * , this method returns the status of the subtask.
*
* @param locale the locale in which the status is to be represented; if null, the {@link Locale#getDefault() default locale}
* will be used
@@ -124,10 +110,32 @@
ProgressStatus getStatus( Locale locale );
/**
- * Return the problems encountered during the {@link #getStatus(Locale) progress} made towards completing the associated
- * {@link #getActivityName() activity}.
+ * Return whether a request was made by an <strong>Observer</strong> to {@link #setCancelled(boolean) cancel} this activity.
*
- * @return the list of problems
+ * @return <code>true</code> if this activity has been requested to be cancelled.
*/
- Problems getProblems();
+ boolean isCancelled();
+
+ /**
+ * Return whether this activity has completed.
+ *
+ * @return <code>true</code> if this activity has completed.
+ */
+ boolean isDone();
+
+ /**
+ * Called by an <strong>Observer</strong> to request the cancellation of this activity, or by the <strong>Updater</strong> to
+ * deny a prior cancellation request (i.e., when the activity {@link #done() completes} before the <strong>Updater</strong>
+ * recognizes a cancellation request by an <strong>Observer</strong>).
+ *
+ * @param value <code>true</code> if requesting the activity be cancelled.
+ */
+ void setCancelled( boolean value );
+
+ /**
+ * Called by the <strong>Updater</strong> to report work completed for this task.
+ *
+ * @param work the number of work units that have been worked
+ */
+ void worked( double work );
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java 2008-10-28 17:53:41 UTC (rev 592)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/ProgressMonitorWrapper.java 2008-10-28 17:55:47 UTC (rev 593)
@@ -40,10 +40,6 @@
this.delegate = delegate;
}
- public ProgressMonitor getWrappedMonitor() {
- return this.delegate;
- }
-
public void beginTask( double totalWork,
I18n name,
Object... params ) {
@@ -62,14 +58,17 @@
return this.delegate.getActivityName();
}
- public ProgressStatus getStatus( Locale locale ) {
- return this.delegate.getStatus(locale);
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getParentActivityName()
+ */
+ public String getParentActivityName() {
+ return this.delegate.getParentActivityName();
}
/**
- * <p>
* {@inheritDoc}
- * </p>
*
* @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems()
*/
@@ -77,6 +76,14 @@
return delegate.getProblems();
}
+ public ProgressStatus getStatus( Locale locale ) {
+ return this.delegate.getStatus(locale);
+ }
+
+ public ProgressMonitor getWrappedMonitor() {
+ return this.delegate;
+ }
+
public boolean isCancelled() {
return this.delegate.isCancelled();
}
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-10-28 17:53:41 UTC (rev 592)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SimpleProgressMonitor.java 2008-10-28 17:55:47 UTC (rev 593)
@@ -31,6 +31,8 @@
import org.jboss.dna.common.collection.Problems;
import org.jboss.dna.common.collection.ThreadSafeProblems;
import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.StringUtil;
/**
* A basic progress monitor.
@@ -51,30 +53,32 @@
private double worked;
private final String activityName;
+ private final String parentActivityName;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final AtomicBoolean cancelled = new AtomicBoolean(false);
private final Problems problems = new ThreadSafeProblems();
public SimpleProgressMonitor( String activityName ) {
- this.activityName = activityName != null ? activityName.trim() : "";
+ this(activityName, null);
+ }
+
+ public SimpleProgressMonitor( String activityName,
+ ProgressMonitor parentProgressMonitor ) {
+ this.activityName = activityName == null ? StringUtil.EMPTY_STRING : activityName.trim();
+ this.parentActivityName = parentProgressMonitor == null ? StringUtil.EMPTY_STRING : parentProgressMonitor.getActivityName();
this.taskName = null;
this.taskNameParams = null;
}
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, java.lang.Object[])
*/
- public String getActivityName() {
- return this.activityName;
- }
-
- /**
- * {@inheritDoc}
- */
public void beginTask( double totalWork,
I18n name,
Object... params ) {
- assert totalWork > 0;
+ CheckArg.isGreaterThan(totalWork, 0.0, "totalWork");
try {
this.lock.writeLock().lock();
this.taskName = name;
@@ -88,15 +92,15 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#createSubtask(double)
*/
public ProgressMonitor createSubtask( double subtaskWork ) {
return new SubProgressMonitor(this, subtaskWork);
}
/**
- * <p>
* {@inheritDoc}
- * </p>
*
* @see org.jboss.dna.common.monitor.ProgressMonitor#done()
*/
@@ -117,60 +121,70 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getActivityName()
*/
- public boolean isCancelled() {
- return this.cancelled.get();
+ public String getActivityName() {
+ return this.activityName;
}
/**
* {@inheritDoc}
*
- * @see org.jboss.dna.common.monitor.ProgressMonitor#isDone()
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getParentActivityName()
*/
- public boolean isDone() {
- lock.readLock().lock();
- try {
- return worked >= totalWork;
- } finally {
- lock.readLock().unlock();
- }
+ public String getParentActivityName() {
+ return this.parentActivityName;
}
/**
* {@inheritDoc}
+ * <p>
+ * Problems must only be added by the {@link ProgressMonitor <strong>Updater</strong>}, and accessed by
+ * {@link ProgressMonitor Observers} only after the activity has been {@link #done() completed}.
+ * </p>
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems()
*/
- public void setCancelled( boolean value ) {
- this.cancelled.set(value);
+ public Problems getProblems() {
+ return problems;
}
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getStatus(java.util.Locale)
*/
- public void worked( double work ) {
- if (work > 0) {
- try {
- this.lock.writeLock().lock();
- if (this.worked < this.totalWork) {
- this.worked += work;
- if (this.worked > this.totalWork) this.worked = this.totalWork;
- }
- } finally {
- this.lock.writeLock().unlock();
- }
- notifyProgress();
+ public ProgressStatus getStatus( Locale locale ) {
+ try {
+ this.lock.readLock().lock();
+ String localizedTaskName = this.taskName == null ? "" : this.taskName.text(locale, this.taskNameParams);
+ return new ProgressStatus(this.getActivityName(), localizedTaskName, this.worked, this.totalWork, this.isCancelled());
+ } finally {
+ this.lock.readLock().unlock();
}
}
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#isCancelled()
*/
- public ProgressStatus getStatus( Locale locale ) {
+ public boolean isCancelled() {
+ return this.cancelled.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#isDone()
+ */
+ public boolean isDone() {
+ lock.readLock().lock();
try {
- this.lock.readLock().lock();
- String localizedTaskName = this.taskName == null ? "" : this.taskName.text(locale, this.taskNameParams);
- return new ProgressStatus(this.getActivityName(), localizedTaskName, this.worked, this.totalWork, this.isCancelled());
+ return worked >= totalWork;
} finally {
- this.lock.readLock().unlock();
+ lock.readLock().unlock();
}
}
@@ -188,14 +202,30 @@
/**
* {@inheritDoc}
- * <p>
- * Problems must only be added by the {@link ProgressMonitor <strong>Updater</strong>}, and accessed by
- * {@link ProgressMonitor Observers} only after the activity has been {@link #done() completed}.
- * </p>
*
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems()
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#setCancelled(boolean)
*/
- public Problems getProblems() {
- return problems;
+ public void setCancelled( boolean value ) {
+ this.cancelled.set(value);
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#worked(double)
+ */
+ public void worked( double work ) {
+ if (work > 0) {
+ try {
+ this.lock.writeLock().lock();
+ if (this.worked < this.totalWork) {
+ this.worked += work;
+ if (this.worked > this.totalWork) this.worked = this.totalWork;
+ }
+ } finally {
+ this.lock.writeLock().unlock();
+ }
+ notifyProgress();
+ }
+ }
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java 2008-10-28 17:53:41 UTC (rev 592)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/monitor/SubProgressMonitor.java 2008-10-28 17:55:47 UTC (rev 593)
@@ -31,8 +31,8 @@
/**
* This class is thread-safe except when accessing or adding {@link #getProblems() problems}. Problems must only be added by the
- * {@link ProgressMonitor <strong>Updater</strong>}, and accessed by {@link ProgressMonitor Observers} only after the activity
- * has been {@link #done() completed}.
+ * {@link ProgressMonitor <strong>Updater</strong>}, and accessed by {@link ProgressMonitor Observers} only after the activity has
+ * been {@link #done() completed}.
*
* @author Randall Hauch
*/
@@ -63,21 +63,9 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#beginTask(double, org.jboss.dna.common.i18n.I18n, java.lang.Object[])
*/
- public String getActivityName() {
- return this.parent.getActivityName();
- }
-
- /**
- * @return parent
- */
- public ProgressMonitor getParent() {
- return this.parent;
- }
-
- /**
- * {@inheritDoc}
- */
public void beginTask( double totalWork,
I18n name,
Object... params ) {
@@ -95,6 +83,8 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#createSubtask(double)
*/
public ProgressMonitor createSubtask( double subtaskWork ) {
return new SubProgressMonitor(this, subtaskWork);
@@ -102,6 +92,8 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#done()
*/
public void done() {
// Compute the total work for this task in terms of the parent ...
@@ -119,7 +111,58 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getActivityName()
*/
+ public String getActivityName() {
+ return this.parent.getActivityName();
+ }
+
+ /**
+ * @return parent
+ */
+ public ProgressMonitor getParent() {
+ return this.parent;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getParentActivityName()
+ */
+ public String getParentActivityName() {
+ return parent.getParentActivityName();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems()
+ */
+ public Problems getProblems() {
+ return parent.getProblems();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#getStatus(java.util.Locale)
+ */
+ public ProgressStatus getStatus( Locale locale ) {
+ try {
+ this.lock.readLock().lock();
+ return new ProgressStatus(this.getActivityName(), this.taskName.text(locale, this.params), this.submittedToParent,
+ this.subtaskTotalInParent, this.isCancelled());
+ } finally {
+ this.lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#isCancelled()
+ */
public boolean isCancelled() {
return this.parent.isCancelled();
}
@@ -135,6 +178,8 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#setCancelled(boolean)
*/
public void setCancelled( boolean value ) {
this.parent.setCancelled(value);
@@ -142,6 +187,8 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.common.monitor.ProgressMonitor#worked(double)
*/
public void worked( double work ) {
if (this.isCancelled()) return;
@@ -158,26 +205,4 @@
this.parent.worked(workInParent);
}
}
-
- /**
- * {@inheritDoc}
- */
- public ProgressStatus getStatus( Locale locale ) {
- try {
- this.lock.readLock().lock();
- return new ProgressStatus(this.getActivityName(), this.taskName.text(locale, this.params), this.submittedToParent,
- this.subtaskTotalInParent, this.isCancelled());
- } finally {
- this.lock.readLock().unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems()
- */
- public Problems getProblems() {
- return parent.getProblems();
- }
}
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java 2008-10-28 17:53:41 UTC (rev 592)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/monitor/RecordingProgressMonitor.java 2008-10-28 17:55:47 UTC (rev 593)
@@ -38,14 +38,21 @@
}
public RecordingProgressMonitor( String name ) {
- this(new SimpleProgressMonitor(name));
+ this(name, null);
}
+ public RecordingProgressMonitor( String name,
+ ProgressMonitor parentProgressMonitor ) {
+ this(new SimpleProgressMonitor(name, parentProgressMonitor));
+ }
+
/**
* {@inheritDoc}
*/
@Override
- public void beginTask( double totalWork, I18n name, Object... params ) {
+ public void beginTask( double totalWork,
+ I18n name,
+ Object... params ) {
++beginTaskCount;
super.beginTask(totalWork, name, params);
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java 2008-10-28 17:53:41 UTC (rev 592)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java 2008-10-28 17:55:47 UTC (rev 593)
@@ -154,7 +154,7 @@
// Now run the sequencer ...
String activity = GraphI18n.errorImportingContent.text(location.getPath(), contentUri);
- ProgressMonitor progressMonitor = new SimpleProgressMonitor(activity);
+ ProgressMonitor progressMonitor = new SimpleProgressMonitor(activity, getContext().getProgressMonitor());
Graph.Batch batch = getGraph().batch();
ImporterOutput importedContent = new ImporterOutput(batch, location.getPath());
InputStream stream = null;
15 years, 6 months
DNA SVN: r592 - trunk/dna-common/src/main/java/org/jboss/dna/common/util.
by dna-commits@lists.jboss.org
Author: jverhaeg(a)redhat.com
Date: 2008-10-28 13:53:41 -0400 (Tue, 28 Oct 2008)
New Revision: 592
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/util/CheckArg.java
Log:
Added isGreaterThan method for doubles
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/CheckArg.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/CheckArg.java 2008-10-28 17:53:24 UTC (rev 591)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/CheckArg.java 2008-10-28 17:53:41 UTC (rev 592)
@@ -83,6 +83,22 @@
}
/**
+ * Check that the argument is greater than the supplied value
+ *
+ * @param argument The argument
+ * @param greaterThanValue the value that is to be used to check the value
+ * @param name The name of the argument
+ * @throws IllegalArgumentException If argument is not greater than the supplied value
+ */
+ public static void isGreaterThan( double argument,
+ double greaterThanValue,
+ String name ) {
+ if (argument <= greaterThanValue) {
+ throw new IllegalArgumentException(CommonI18n.argumentMustBeGreaterThan.text(name, argument, greaterThanValue));
+ }
+ }
+
+ /**
* Check that the argument is less than the supplied value
*
* @param argument The argument
15 years, 6 months