Author: rhauch
Date: 2009-06-04 19:36:27 -0400 (Thu, 04 Jun 2009)
New Revision: 978
Removed:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TestUtil.java
trunk/extensions/dna-sequencer-java/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml
trunk/extensions/dna-sequencer-xml/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml
Modified:
trunk/dna-graph/src/test/resources/log4j.properties
trunk/dna-repository/src/test/resources/log4j.properties
trunk/docs/examples/gettingstarted/repositories/src/test/resources/log4j.properties
trunk/docs/examples/gettingstarted/sequencers/src/main/assembly/basic.xml
trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java
trunk/docs/examples/gettingstarted/sequencers/src/test/resources/log4j.properties
trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
trunk/extensions/dna-mimetype-detector-aperture/pom.xml
trunk/extensions/dna-mimetype-detector-aperture/src/test/resources/master.xml
trunk/extensions/dna-sequencer-images/src/test/resources/log4j.properties
trunk/extensions/dna-sequencer-java/src/test/resources/log4j.properties
trunk/extensions/dna-sequencer-mp3/src/test/resources/log4j.properties
trunk/extensions/dna-sequencer-msoffice/src/test/resources/log4j.properties
trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java
trunk/extensions/dna-sequencer-xml/src/test/resources/log4j.properties
trunk/extensions/dna-sequencer-xml/src/test/resources/master.xml
trunk/extensions/dna-sequencer-zip/src/test/resources/log4j.properties
Log:
DNA-405 Continued the removal of most references and use of Jackrabbit, with the exception
of the Jackrabbit API unit tests (aka, the TCK unit tests), the Maven classloader project,
and the 'dna-integration-test' project. Some documentation still needs to be
updated.
Modified: trunk/dna-graph/src/test/resources/log4j.properties
===================================================================
--- trunk/dna-graph/src/test/resources/log4j.properties 2009-06-04 22:31:30 UTC (rev 977)
+++ trunk/dna-graph/src/test/resources/log4j.properties 2009-06-04 23:36:27 UTC (rev 978)
@@ -10,7 +10,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
-log4j.logger.org.apache.derby=INFO, stdout
-
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TestUtil.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TestUtil.java 2009-06-04 22:31:30 UTC
(rev 977)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TestUtil.java 2009-06-04 23:36:27 UTC
(rev 978)
@@ -1,716 +0,0 @@
-/*
- * JBoss DNA (
http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you 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.
- *
- * JBoss DNA 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.jcr;
-
-import javax.security.auth.login.LoginContext;
-import net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.JcrNtLexicon;
-import org.jboss.dna.graph.connector.RepositoryConnection;
-import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
-import org.jboss.dna.graph.connector.RepositorySource;
-import org.jboss.dna.graph.property.NamespaceRegistry;
-import org.mockito.Mockito;
-
-/**
- * @author jverhaeg
- */
-@NotThreadSafe
-public class TestUtil {
-
- public static RepositoryConnectionFactory createJackRabbitConnectionFactory( final
RepositorySource source,
- final
ExecutionContext context ) {
- Graph repository = Graph.create(source, context);
- Graph.Batch batch = repository.batch();
-
batch.set(JcrLexicon.PRIMARY_TYPE).on("/").to(JcrNtLexicon.UNSTRUCTURED).and();
- batch.create("/dna:system").with(JcrLexicon.PRIMARY_TYPE,
JcrNtLexicon.UNSTRUCTURED).and();
-
batch.create("/dna:system/jcr:versionStorage").with(JcrLexicon.PRIMARY_TYPE,
"rep:versionStorage").and();
- batch.create("/dna:system/jcr:nodeTypes").with(JcrLexicon.PRIMARY_TYPE,
"rep:nodeTypes").and();
- batch.execute();
-
- createNodeType(repository, context, "rep:nodeTypes", false, false);
- createChildDefinition(repository, context, "rep:nodeTypes", false,
"nt:nodeType", false, "ABORT", true, false);
- createNodeType(repository, context, "mix:versionable", false, true);
- createPropertyDefinition(repository,
- context,
- "mix:versionable",
- 1,
- false,
- false,
- true,
- "jcr:mergeFailed",
- "ABORT",
- true,
- "REFERENCE");
- createPropertyDefinition(repository,
- context,
- "mix:versionable",
- 2,
- false,
- true,
- true,
- "jcr:predecessors",
- "COPY",
- true,
- "REFERENCE");
- createPropertyDefinition(repository,
- context,
- "mix:versionable",
- 3,
- true,
- true,
- false,
- "jcr:isCheckedOut",
- "IGNORE",
- true,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "mix:versionable",
- 4,
- false,
- true,
- false,
- "jcr:baseVersion",
- "IGNORE",
- true,
- "REFERENCE");
- createPropertyDefinition(repository,
- context,
- "mix:versionable",
- 5,
- false,
- true,
- false,
- "jcr:versionHistory",
- "COPY",
- true,
- "REFERENCE");
- createNodeType(repository, context, "nt:file", false, false);
- createProperty(repository, context, "nt:file",
"jcr:primaryItemName", "jcr:content");
- createChildDefinition(repository, context, "nt:file", false, true,
"jcr:content", "COPY", false, false);
- createNodeType(repository, context, "nt:hierarchyNode", false, false);
- createPropertyDefinition(repository,
- context,
- "nt:hierarchyNode",
- true,
- false,
- false,
- "jcr:created",
- "INITIALIZE",
- true,
- "DATE");
- createNodeType(repository, context, "nt:versionedChild", false,
false);
- createPropertyDefinition(repository,
- context,
- "nt:versionedChild",
- true,
- true,
- false,
- "jcr:childVersionHistory",
- "ABORT",
- true,
- "REFERENCE");
- createNodeType(repository, context, "nt:version", false, false);
- createPropertyDefinition(repository,
- context,
- "nt:version",
- 1,
- false,
- false,
- true,
- "jcr:successors",
- "ABORT",
- true,
- "REFERENCE");
- createPropertyDefinition(repository,
- context,
- "nt:version",
- 2,
- false,
- false,
- true,
- "jcr:predecessors",
- "ABORT",
- true,
- "REFERENCE");
- createPropertyDefinition(repository, context, "nt:version", 3, true,
true, false, "jcr:created", "ABORT", true, "DATE");
- createChildDefinition(repository, context, "nt:version", false, false,
"jcr:frozenNode", "ABORT", true, false);
- /*
- <nt:versionLabels jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="false" jcr:isMixin="false"
jcr:nodeTypeName="nt:versionLabels">
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="false"
jcr:onParentVersion="ABORT" jcr:protected="true"
jcr:requiredType="REFERENCE"/>
- <nt:folder jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="false" jcr:isMixin="false"
jcr:nodeTypeName="nt:folder">
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:onParentVersion="VERSION"
jcr:protected="false" jcr:sameNameSiblings="false"/>
- */
- createNodeType(repository, context, "nt:nodeType", false, false);
- createPropertyDefinition(repository,
- context,
- "nt:nodeType",
- 1,
- false,
- false,
- false,
- "jcr:primaryItemName",
- "COPY",
- false,
- "NAME");
- createPropertyDefinition(repository,
- context,
- "nt:nodeType",
- 2,
- false,
- true,
- false,
- "jcr:hasOrderableChildNodes",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:nodeType",
- 3,
- false,
- true,
- false,
- "jcr:isMixin",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:nodeType",
- 4,
- false,
- false,
- true,
- "jcr:supertypes",
- "COPY",
- false,
- "NAME");
- createPropertyDefinition(repository,
- context,
- "nt:nodeType",
- 5,
- false,
- true,
- false,
- "jcr:nodeTypeName",
- "COPY",
- false,
- "NAME");
- createChildDefinition(repository,
- context,
- "nt:nodeType",
- 1,
- false,
- "nt:childNodeDefinition",
- false,
- "jcr:childNodeDefinition",
- "VERSION",
- false,
- true);
- createChildDefinition(repository,
- context,
- "nt:nodeType",
- 2,
- false,
- "nt:propertyDefinition",
- false,
- "jcr:propertyDefinition",
- "VERSION",
- false,
- true);
- createNodeType(repository, context, "nt:propertyDefinition", false,
false);
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 1,
- false,
- true,
- false,
- "jcr:multiple",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 2,
- false,
- false,
- true,
- "jcr:defaultValues",
- "COPY",
- false,
- "UNDEFINED");
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 3,
- false,
- false,
- true,
- "jcr:valueConstraints",
- "COPY",
- false,
- "STRING");
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 4,
- false,
- true,
- false,
- "jcr:requiredType",
- "COPY",
- false,
- "STRING");
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 5,
- false,
- true,
- false,
- "jcr:protected",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 6,
- false,
- true,
- false,
- "jcr:onParentVersion",
- "COPY",
- false,
- "STRING");
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 7,
- false,
- true,
- false,
- "jcr:mandatory",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 8,
- false,
- true,
- false,
- "jcr:autoCreated",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:propertyDefinition",
- 9,
- false,
- false,
- false,
- "jcr:name",
- "COPY",
- false,
- "NAME");
- /*
- <rep:versionStorage jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="false" jcr:isMixin="false"
jcr:nodeTypeName="rep:versionStorage">
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="false"
jcr:defaultPrimaryType="rep:versionStorage" jcr:mandatory="false"
jcr:onParentVersion="ABORT" jcr:protected="true"
jcr:sameNameSiblings="true"/>
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="false"
jcr:defaultPrimaryType="nt:versionHistory" jcr:mandatory="false"
jcr:onParentVersion="ABORT" jcr:protected="true"
jcr:sameNameSiblings="true"/>
- */
- createNodeType(repository, context, "nt:base", false, false);
- createPropertyDefinition(repository, context, "nt:base", false, false,
true, "jcr:mixinTypes", "COMPUTE", true, "NAME");
- createPropertyDefinition(repository, context, "nt:base", true, true,
false, "jcr:primaryType", "COMPUTE", true, "NAME");
- /*
- <nt:resource jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="false" jcr:isMixin="false"
jcr:nodeTypeName="nt:resource" jcr:primaryItemName="jcr:data">
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="true" jcr:multiple="false"
jcr:name="jcr:lastModified" jcr:onParentVersion="IGNORE"
jcr:protected="false" jcr:requiredType="DATE"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="true" jcr:multiple="false"
jcr:name="jcr:data" jcr:onParentVersion="COPY"
jcr:protected="false" jcr:requiredType="BINARY"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="true" jcr:multiple="false"
jcr:name="jcr:mimeType" jcr:onParentVersion="COPY"
jcr:protected="false" jcr:requiredType="STRING"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="false"
jcr:name="jcr:encoding" jcr:onParentVersion="COPY"
jcr:protected="false" jcr:requiredType="STRING"/>
- */
- createNodeType(repository, context, "nt:childNodeDefinition", false,
false);
- createPropertyDefinition(repository,
- context,
- "nt:childNodeDefinition",
- 1,
- false,
- true,
- false,
- "jcr:sameNameSiblings",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:childNodeDefinition",
- 2,
- false,
- false,
- false,
- "jcr:defaultPrimaryType",
- "COPY",
- false,
- "NAME");
- createPropertyDefinition(repository,
- context,
- "nt:childNodeDefinition",
- 3,
- false,
- true,
- true,
- "jcr:requiredPrimaryTypes",
- "COPY",
- false,
- "NAME");
- createPropertyDefinition(repository,
- context,
- "nt:childNodeDefinition",
- 4,
- false,
- true,
- false,
- "jcr:protected",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:childNodeDefinition",
- 5,
- false,
- true,
- false,
- "jcr:onParentVersion",
- "COPY",
- false,
- "STRING");
- createPropertyDefinition(repository,
- context,
- "nt:childNodeDefinition",
- 6,
- false,
- true,
- false,
- "jcr:mandatory",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:childNodeDefinition",
- 7,
- false,
- true,
- false,
- "jcr:autoCreated",
- "COPY",
- false,
- "BOOLEAN");
- createPropertyDefinition(repository,
- context,
- "nt:childNodeDefinition",
- 8,
- false,
- false,
- false,
- "jcr:name",
- "COPY",
- false,
- "NAME");
- createNodeType(repository, context, "mix:referenceable", false, true);
- createPropertyDefinition(repository,
- context,
- "mix:referenceable",
- true,
- true,
- false,
- "jcr:uuid",
- "INITIALIZE",
- true,
- "STRING");
- createNodeType(repository, context, "nt:unstructured", true, false);
- createPropertyDefinition(repository, context, "nt:unstructured", false,
false, false, "COPY", false, "UNDEFINED");
- createPropertyDefinition(repository, context, "nt:unstructured", false,
false, true, "COPY", false, "UNDEFINED");
- createChildDefinition(repository, context, "nt:unstructured", false,
"nt:unstructured", false, "VERSION", false, true);
- /*
- <nt:versionHistory jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="false" jcr:isMixin="false"
jcr:nodeTypeName="nt:versionHistory">
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="true"
jcr:mandatory="true" jcr:multiple="false"
jcr:name="jcr:versionableUuid" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:requiredType="STRING"/>
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="false"
jcr:defaultPrimaryType="nt:version" jcr:mandatory="false"
jcr:onParentVersion="ABORT" jcr:protected="true"
jcr:sameNameSiblings="false"/>
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="true"
jcr:defaultPrimaryType="nt:versionLabels" jcr:mandatory="true"
jcr:name="jcr:versionLabels" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:sameNameSiblings="false"/>
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="true"
jcr:defaultPrimaryType="nt:version" jcr:mandatory="true"
jcr:name="jcr:rootVersion" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:sameNameSiblings="false"/>
- <mix:lockable jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="false" jcr:isMixin="true"
jcr:nodeTypeName="mix:lockable">
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="false"
jcr:name="jcr:lockIsDeep" jcr:onParentVersion="IGNORE"
jcr:protected="true" jcr:requiredType="BOOLEAN"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="false"
jcr:name="jcr:lockOwner" jcr:onParentVersion="IGNORE"
jcr:protected="true" jcr:requiredType="STRING"/>
- <nt:frozenNode jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="true" jcr:isMixin="false"
jcr:nodeTypeName="nt:frozenNode">
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="true"
jcr:onParentVersion="ABORT" jcr:protected="true"
jcr:requiredType="UNDEFINED"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="false"
jcr:onParentVersion="ABORT" jcr:protected="true"
jcr:requiredType="UNDEFINED"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="true"
jcr:mandatory="true" jcr:multiple="false"
jcr:name="jcr:frozenUuid" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:requiredType="STRING"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="true"
jcr:name="jcr:frozenMixinTypes" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:requiredType="NAME"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="true"
jcr:mandatory="true" jcr:multiple="false"
jcr:name="jcr:frozenPrimaryType" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:requiredType="NAME"/>
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:sameNameSiblings="true"/>
- <rep:system jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="true" jcr:isMixin="false"
jcr:nodeTypeName="rep:system">
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="false"
jcr:defaultPrimaryType="nt:unstructured" jcr:mandatory="false"
jcr:onParentVersion="IGNORE" jcr:protected="false"
jcr:sameNameSiblings="true"/>
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="false"
jcr:defaultPrimaryType="rep:nodeTypes" jcr:mandatory="true"
jcr:name="jcr:nodeTypes" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:sameNameSiblings="false"/>
- <jcr:childNodeDefinition
jcr:primaryType="nt:childNodeDefinition" jcr:autoCreated="false"
jcr:defaultPrimaryType="rep:versionStorage" jcr:mandatory="true"
jcr:name="jcr:versionStorage" jcr:onParentVersion="ABORT"
jcr:protected="true" jcr:sameNameSiblings="false"/>
- */
- createNodeType(repository, context, "rep:root", true, false);
- createChildDefinition(repository, context, "rep:root", false, true,
"jcr:system", false, false);
- /*
- <nt:query jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="false" jcr:isMixin="false"
jcr:nodeTypeName="nt:query">
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="false"
jcr:name="jcr:language" jcr:onParentVersion="COPY"
jcr:protected="false" jcr:requiredType="STRING"/>
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="false" jcr:multiple="false"
jcr:name="jcr:statement" jcr:onParentVersion="COPY"
jcr:protected="false" jcr:requiredType="STRING"/>
- </nt:query>
- <nt:linkedFile jcr:primaryType="nt:nodeType"
jcr:hasOrderableChildNodes="false" jcr:isMixin="false"
jcr:nodeTypeName="nt:linkedFile"
jcr:primaryItemName="jcr:content">
- <jcr:propertyDefinition
jcr:primaryType="nt:propertyDefinition" jcr:autoCreated="false"
jcr:mandatory="true" jcr:multiple="false"
jcr:name="jcr:content" jcr:onParentVersion="COPY"
jcr:protected="false" jcr:requiredType="REFERENCE"/>
- </nt:linkedFile>
- */
-
- return new RepositoryConnectionFactory() {
-
- public RepositoryConnection createConnection( String sourceName ) {
- return source.getConnection();
- }
- };
- }
-
- public static ExecutionContext getExecutionContext() {
- final ExecutionContext context = new
ExecutionContext().create(Mockito.mock(LoginContext.class));
- NamespaceRegistry registry = context.getNamespaceRegistry();
- registry.register("dna", "http://www.jboss.org/dna/1.0");
- registry.register("fn",
"http://www.w3.org/2005/xpath-functions");
- registry.register("fn_old",
"http://www.w3.org/2004/10/xpath-functions");
- registry.register("jcr", "http://www.jcp.org/jcr/1.0");
- registry.register("mix", "http://www.jcp.org/jcr/mix/1.0");
- registry.register("nt", "http://www.jcp.org/jcr/nt/1.0");
- registry.register("rep", "internal");
- registry.register("sv", "http://www.jcp.org/jcr/sv/1.0");
- registry.register("xs", "http://www.w3.org/2001/XMLSchema");
- return context;
- }
-
- private static void createChildDefinition( Graph repository,
- ExecutionContext context,
- String node,
- Boolean autoCreated,
- Boolean mandatory,
- String onParentVersion,
- Boolean isProtected,
- Boolean sameNameSiblings ) {
- createChildDefinition(repository,
- context,
- node,
- 0,
- autoCreated,
- null,
- mandatory,
- null,
- onParentVersion,
- isProtected,
- sameNameSiblings);
- }
-
- private static void createChildDefinition( Graph repository,
- ExecutionContext context,
- String node,
- Boolean autoCreated,
- Boolean mandatory,
- String name,
- String onParentVersion,
- Boolean isProtected,
- Boolean sameNameSiblings ) {
- createChildDefinition(repository,
- context,
- node,
- 0,
- autoCreated,
- null,
- mandatory,
- name,
- onParentVersion,
- isProtected,
- sameNameSiblings);
- }
-
- private static void createChildDefinition( Graph repository,
- ExecutionContext context,
- String node,
- Boolean autoCreated,
- String defaultPrimaryType,
- Boolean mandatory,
- String onParentVersion,
- Boolean isProtected,
- Boolean sameNameSiblings ) {
- createChildDefinition(repository,
- context,
- node,
- 0,
- autoCreated,
- defaultPrimaryType,
- mandatory,
- null,
- onParentVersion,
- isProtected,
- sameNameSiblings);
- }
-
- private static void createChildDefinition( Graph repository,
- ExecutionContext context,
- String node,
- int index,
- Boolean autoCreated,
- String defaultPrimaryType,
- Boolean mandatory,
- String name,
- String onParentVersion,
- Boolean isProtected,
- Boolean sameNameSiblings ) {
- String defNode = "/dna:system/jcr:nodeTypes/" + node +
"/jcr:childNodeDefinition";
- if (index > 0) {
- defNode += '[' + index + ']';
- }
- createProperty(repository, context, defNode, "jcr:primaryType",
"nt:childNodeDefinition");
- createProperty(repository, context, defNode, "jcr:autoCreated",
autoCreated.toString());
- if (defaultPrimaryType != null) {
- createProperty(repository, context, defNode,
"jcr:defaultPrimaryType", defaultPrimaryType);
- }
- createProperty(repository, context, defNode, "jcr:mandatory",
mandatory.toString());
- if (name != null) {
- createProperty(repository, context, defNode, "jcr:name", name);
- }
- createProperty(repository, context, defNode, "jcr:onParentVersion",
onParentVersion);
- createProperty(repository, context, defNode, "jcr:protected",
isProtected.toString());
- createProperty(repository, context, defNode, "jcr:sameNameSiblings",
sameNameSiblings.toString());
- }
-
- //
- // private static void createChildDefinitionProperty( SimpleRepository repository,
- // ExecutionContext context,
- // String node,
- // String property,
- // String value ) {
- // createProperty(repository, context, node + "/jcr:childNodeDefinition",
property, value);
- // }
-
- private static void createNodeType( Graph repository,
- ExecutionContext context,
- String node,
- Boolean hasOrderableChildNodes,
- Boolean isMixin ) {
- node = "/dna:system/jcr:nodeTypes/" + node;
- repository.create(node);
- createProperty(repository, context, node, "jcr:primaryType",
"nt:nodeType");
- createProperty(repository, context, node, "jcr:hasOrderableChildNodes",
hasOrderableChildNodes.toString());
- createProperty(repository, context, node, "jcr:isMixin",
isMixin.toString());
- createProperty(repository, context, node, "jcr:nodeTypeName", node);
- }
-
- private static void createProperty( Graph repository,
- ExecutionContext context,
- String node,
- String property,
- String value ) {
- repository.set(property).on(node).to(value);
- }
-
- private static void createPropertyDefinition( Graph repository,
- ExecutionContext context,
- String node,
- Boolean autoCreated,
- Boolean mandatory,
- Boolean multiple,
- String onParentVersion,
- Boolean isProtected,
- String requiredType ) {
- createPropertyDefinition(repository,
- context,
- node,
- 0,
- autoCreated,
- mandatory,
- multiple,
- null,
- onParentVersion,
- isProtected,
- requiredType);
- }
-
- private static void createPropertyDefinition( Graph repository,
- ExecutionContext context,
- String node,
- Boolean autoCreated,
- Boolean mandatory,
- Boolean multiple,
- String name,
- String onParentVersion,
- Boolean isProtected,
- String requiredType ) {
- createPropertyDefinition(repository,
- context,
- node,
- 0,
- autoCreated,
- mandatory,
- multiple,
- name,
- onParentVersion,
- isProtected,
- requiredType);
- }
-
- private static void createPropertyDefinition( Graph repository,
- ExecutionContext context,
- String node,
- int index,
- Boolean autoCreated,
- Boolean mandatory,
- Boolean multiple,
- String name,
- String onParentVersion,
- Boolean isProtected,
- String requiredType ) {
- String defNode = "/dna:system/jcr:nodeTypes/" + node +
"/nt:propertyDefinition";
- if (index > 0) {
- defNode += '[' + index + ']';
- }
- repository.create(defNode);
- createProperty(repository, context, defNode, "jcr:primaryType",
"nt:propertyDefinition");
- createProperty(repository, context, defNode, "jcr:autoCreated",
autoCreated.toString());
- createProperty(repository, context, defNode, "jcr:mandatory",
mandatory.toString());
- createProperty(repository, context, defNode, "jcr:multiple",
multiple.toString());
- if (name != null) {
- createProperty(repository, context, defNode, "jcr:name", name);
- }
- createProperty(repository, context, defNode, "jcr:onParentVersion",
onParentVersion);
- createProperty(repository, context, defNode, "jcr:protected",
isProtected.toString());
- createProperty(repository, context, defNode, "jcr:requiredType",
requiredType);
- }
-}
Modified: trunk/dna-repository/src/test/resources/log4j.properties
===================================================================
--- trunk/dna-repository/src/test/resources/log4j.properties 2009-06-04 22:31:30 UTC (rev
977)
+++ trunk/dna-repository/src/test/resources/log4j.properties 2009-06-04 23:36:27 UTC (rev
978)
@@ -13,7 +13,3 @@
#log4j.logger.org.jboss.dna.repository.federation=DEBUG
#log4j.logger.org.jboss.dna.spi=DEBUG
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
-log4j.logger.org.apache.derby=INFO, stdout
-
Modified:
trunk/docs/examples/gettingstarted/repositories/src/test/resources/log4j.properties
===================================================================
---
trunk/docs/examples/gettingstarted/repositories/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++
trunk/docs/examples/gettingstarted/repositories/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -17,6 +17,3 @@
#log4j.logger.org.jboss.dna.spi=DEBUG
#log4j.logger.org.jboss.example.dna=TRACE
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
-
Modified: trunk/docs/examples/gettingstarted/sequencers/src/main/assembly/basic.xml
===================================================================
--- trunk/docs/examples/gettingstarted/sequencers/src/main/assembly/basic.xml 2009-06-04
22:31:30 UTC (rev 977)
+++ trunk/docs/examples/gettingstarted/sequencers/src/main/assembly/basic.xml 2009-06-04
23:36:27 UTC (rev 978)
@@ -21,6 +21,8 @@
<include>*.jpg</include>
<include>*.pict</include>
<include>*.mp3</include>
+ <include>*.cnd</include>
+ <include>*.xml</include>
</includes>
</fileSet>
<fileSet>
@@ -39,14 +41,6 @@
<fileMode>0744</fileMode>
</file>
<file>
- <source>src/main/resources/jackrabbitConfig.xml</source>
- <fileMode>0644</fileMode>
- </file>
- <file>
- <source>src/main/resources/jackrabbitNodeTypes.cnd</source>
- <fileMode>0644</fileMode>
- </file>
- <file>
<source>src/main/resources/log4j.properties</source>
<fileMode>0644</fileMode>
</file>
Modified:
trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java
===================================================================
---
trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java 2009-06-04
22:31:30 UTC (rev 977)
+++
trunk/docs/examples/gettingstarted/sequencers/src/main/java/org/jboss/example/dna/sequencer/SequencingClient.java 2009-06-04
23:36:27 UTC (rev 978)
@@ -137,7 +137,7 @@
}
/**
- * Start up the JCR repository. This method only operates using the JCR API and
Jackrabbit-specific API.
+ * Start up the JCR repository, using an implementation-specific API.
*
* @throws Exception
*/
Modified:
trunk/docs/examples/gettingstarted/sequencers/src/test/resources/log4j.properties
===================================================================
---
trunk/docs/examples/gettingstarted/sequencers/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++
trunk/docs/examples/gettingstarted/sequencers/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -9,6 +9,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=WARNING
-
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
Modified: trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml 2009-06-04
22:31:30 UTC (rev 977)
+++ trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml 2009-06-04
23:36:27 UTC (rev 978)
@@ -306,7 +306,7 @@
<listitem>
<para>
<emphasis role="strong">dna-jcr-tck</emphasis>
- provides a separate testing project that executes all JackRabbit JCR TCK
tests on a nightly basis to track implementation
+ provides a separate testing project that executes all Jackrabbit JCR TCK
tests on a nightly basis to track implementation
progress against the JCR 1.0 specification. This module will likely be
retired when the <code>dna-jcr</code> implementation
is complete.
</para>
Modified: trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++
trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -10,8 +10,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
log4j.logger.org.jboss.dna.connector.federation=TRACE
-
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
-log4j.logger.org.apache.derby=INFO, stdout
-
Modified: trunk/extensions/dna-mimetype-detector-aperture/pom.xml
===================================================================
--- trunk/extensions/dna-mimetype-detector-aperture/pom.xml 2009-06-04 22:31:30 UTC (rev
977)
+++ trunk/extensions/dna-mimetype-detector-aperture/pom.xml 2009-06-04 23:36:27 UTC (rev
978)
@@ -236,9 +236,6 @@
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
</dependency>
- <!--
- Java Content Repository API and Apache Jackrabbit for the JCR unit test
infrastructure
- -->
</dependencies>
<reporting>
<plugins>
Modified: trunk/extensions/dna-mimetype-detector-aperture/src/test/resources/master.xml
===================================================================
---
trunk/extensions/dna-mimetype-detector-aperture/src/test/resources/master.xml 2009-06-04
22:31:30 UTC (rev 977)
+++
trunk/extensions/dna-mimetype-detector-aperture/src/test/resources/master.xml 2009-06-04
23:36:27 UTC (rev 978)
@@ -675,1218 +675,4 @@
</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/</...
- , 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/...
- 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.sequencer.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-sequenc...
- </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_d...
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.sequencer.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...;.
- Or, check out <ulink
url="http://jira.jboss.org/jira/secure/IssueNavigator.jspa?reset=tru...
- 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
Modified: trunk/extensions/dna-sequencer-images/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-sequencer-images/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++ trunk/extensions/dna-sequencer-images/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -10,6 +10,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
-
Deleted:
trunk/extensions/dna-sequencer-java/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml
===================================================================
---
trunk/extensions/dna-sequencer-java/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml 2009-06-04
22:31:30 UTC (rev 977)
+++
trunk/extensions/dna-sequencer-java/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml 2009-06-04
23:36:27 UTC (rev 978)
@@ -1,115 +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.local.LocalFileSystem">
- <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.local.LocalFileSystem">
- <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.local.LocalFileSystem">
- <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>
Modified: trunk/extensions/dna-sequencer-java/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-sequencer-java/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++ trunk/extensions/dna-sequencer-java/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -9,6 +9,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
Modified: trunk/extensions/dna-sequencer-mp3/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-sequencer-mp3/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++ trunk/extensions/dna-sequencer-mp3/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -9,6 +9,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
Modified: trunk/extensions/dna-sequencer-msoffice/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-sequencer-msoffice/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++ trunk/extensions/dna-sequencer-msoffice/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -10,6 +10,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
-
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 2009-06-04
22:31:30 UTC (rev 977)
+++
trunk/extensions/dna-sequencer-xml/src/test/java/org/jboss/dna/sequencer/xml/XmlSequencerTest.java 2009-06-04
23:36:27 UTC (rev 978)
@@ -45,11 +45,8 @@
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";
@@ -61,7 +58,6 @@
private XmlSequencer sequencer;
private InputStream stream;
private MockSequencerOutput output;
- private URL xml1;
private URL xml2;
private URL xml3;
private URL xml4;
@@ -73,8 +69,6 @@
sequencer = new XmlSequencer();
context = new MockSequencerContext();
output = new MockSequencerOutput(context);
- 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");
@@ -97,23 +91,6 @@
}
@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("Licensed to the Apache Software Foundation
(ASF)"), is(true));
- assertThat(text.indexOf('\n') > 0, is(true));
- assertThat(text.endsWith(" limitations under the License."),
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");
@@ -139,15 +116,12 @@
@Test
public void shouldSequenceElementContent() throws IOException {
verifyDocument(xml2);
- verifyString("book[1]/chapter[4]/sect1[1]/para[8]/" + ELEMENT_CONTENT +
"[1]",
+ verifyString("book[1]/chapter[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");
+ "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.");
}
@Test
Deleted:
trunk/extensions/dna-sequencer-xml/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml
===================================================================
---
trunk/extensions/dna-sequencer-xml/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml 2009-06-04
22:31:30 UTC (rev 977)
+++
trunk/extensions/dna-sequencer-xml/src/test/resources/jackrabbitInMemoryTestRepositoryConfig.xml 2009-06-04
23:36:27 UTC (rev 978)
@@ -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>
Modified: trunk/extensions/dna-sequencer-xml/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++ trunk/extensions/dna-sequencer-xml/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -9,6 +9,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
Modified: trunk/extensions/dna-sequencer-xml/src/test/resources/master.xml
===================================================================
--- trunk/extensions/dna-sequencer-xml/src/test/resources/master.xml 2009-06-04 22:31:30
UTC (rev 977)
+++ trunk/extensions/dna-sequencer-xml/src/test/resources/master.xml 2009-06-04 23:36:27
UTC (rev 978)
@@ -675,1178 +675,4 @@
</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/</...
- , 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/...
- 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.sequencer.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-sequenc...
- </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_d...
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-graph</artifactId>
- <version>0.5</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-jcr</artifactId>
- <version>0.5</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>
-</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.sequencer.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...;.
- Or, check out <ulink
url="http://jira.jboss.org/jira/secure/IssueNavigator.jspa?reset=tru...
- 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
Modified: trunk/extensions/dna-sequencer-zip/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-sequencer-zip/src/test/resources/log4j.properties 2009-06-04
22:31:30 UTC (rev 977)
+++ trunk/extensions/dna-sequencer-zip/src/test/resources/log4j.properties 2009-06-04
23:36:27 UTC (rev 978)
@@ -10,6 +10,3 @@
# Set up the default logging to be INFO level, then override specific units
log4j.logger.org.jboss.dna=INFO
-# Jackrabbit logging
-log4j.logger.org.apache.jackrabbit=WARN, stdout
-