Author: maeste
Date: 2008-06-07 08:28:47 -0400 (Sat, 07 Jun 2008)
New Revision: 246
Added:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositorySource.java
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationException.java
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java
branches/maeste/dna-repository/src/test/resources/CurrencyFormatterExample.mxml
branches/maeste/dna-repository/src/test/resources/Descriptor.1.0.xsd
branches/maeste/dna-repository/src/test/resources/master.xml
branches/maeste/dna-repository/src/test/resources/plugin.xml
branches/maeste/eclipse-code-formatter-profile.xml
branches/maeste/eclipse-preferences.epf
Removed:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java
Modified:
branches/maeste/
branches/maeste/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java
branches/maeste/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
branches/maeste/dna-common/.classpath
branches/maeste/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java
branches/maeste/dna-common/src/test/java/org/jboss/dna/common/util/StringUtilTest.java
branches/maeste/dna-integration-tests/.classpath
branches/maeste/dna-maven-classloader/.classpath
branches/maeste/dna-repository/.classpath
branches/maeste/dna-repository/pom.xml
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java
branches/maeste/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/InvalidPathException.java
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/NamespaceException.java
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathNotFoundException.java
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/ValueFormatException.java
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnection.java
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositorySource.java
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositorySourceException.java
branches/maeste/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java
branches/maeste/dna-spi/src/test/java/org/jboss/dna/spi/sequencers/MockSequencerOutput.java
branches/maeste/docs/examples/gettingstarted/sequencers/.classpath
Log:
Merged revisions 236-245 via svnmerge from
https://svn.jboss.org/repos/dna/trunk
........
r238 | jverhaeg(a)redhat.com | 2008-06-06 01:50:49 +0200 (Fri, 06 Jun 2008) | 1 line
DNA-112: Setup each project to allow for different output folders, with the folder for
src/main/java and src/main/resources set to target/classes, and with the folder for
src/test/java and src/test/resources set to target/test-classes.
........
r239 | jverhaeg(a)redhat.com | 2008-06-06 02:37:18 +0200 (Fri, 06 Jun 2008) | 1 line
DNA-72: Create XML sequencer and associated tests in dna-repository project, and added a
utility method used by the sequencer to StringUtil, normalize(String), that removes
leading and trailing whitespace and reduces consecutive internal whitespace characters to
a single space.
........
r240 | rhauch | 2008-06-06 17:24:18 +0200 (Fri, 06 Jun 2008) | 4 lines
DNA-112: Most of the project .classpath files are inconsistent with the Maven structure
http://jira.jboss.org/jira/browse/DNA-112
Corrected the Eclipse .classpath files that were just changed. They incorrectly had an
'excluding="**"' attribute on several of the src elements. By removing
these, command-line maven works, as do the different versions of the Maven 2 Eclipse
plugin.
........
r241 | jverhaeg(a)redhat.com | 2008-06-06 20:15:20 +0200 (Fri, 06 Jun 2008) | 1 line
DNA-99: Added 2 files to trunk: eclipse-code-formatter-profile.xml, which contains the
code formatter profile XML that can be imported via the Formatter preference page in
Eclipse, and eclipse-preferences.epf, which can be imported via the Eclipse Preferences
importer. The latter file does NOT contain formatter preferences since its encoding
within this file would make it very difficult to maintain.
........
r242 | jverhaeg(a)redhat.com | 2008-06-06 21:31:59 +0200 (Fri, 06 Jun 2008) | 1 line
DNA-99: Oops. Removed the formatter profile XML, but forgot to remove the individual
formatter preferences from the .epf file.
........
r243 | rhauch | 2008-06-06 23:18:50 +0200 (Fri, 06 Jun 2008) | 4 lines
DNA-67: Create graph API for federation engine
http://jira.jboss.org/jira/browse/DNA-67
Added toString() methods on the exceptions.
........
r244 | rhauch | 2008-06-06 23:19:46 +0200 (Fri, 06 Jun 2008) | 4 lines
DNA-67: Create graph API for federation engine
http://jira.jboss.org/jira/browse/DNA-67
Moved the "getDefaultCachePolicy" from RepositorySource to
RepositoryConnection.
........
r245 | rhauch | 2008-06-06 23:21:35 +0200 (Fri, 06 Jun 2008) | 1 line
Created initial implementations of RepositorySource, RepositoryConnection for the
federation engine, along with test cases. Also created a FederatedRepository class that
represents the state associated a federated repository, the instances of which are managed
by the FederationService.
........
Property changes on: branches/maeste
___________________________________________________________________
Name: svnmerge-integrated
- /trunk:1-235
+ /trunk:1-245
Modified:
branches/maeste/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java
===================================================================
---
branches/maeste/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -30,6 +30,7 @@
import org.jboss.cache.Cache;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
+import org.jboss.dna.spi.cache.CachePolicy;
import org.jboss.dna.spi.graph.Name;
import org.jboss.dna.spi.graph.Path;
import org.jboss.dna.spi.graph.Property;
@@ -97,6 +98,13 @@
/**
* {@inheritDoc}
*/
+ public CachePolicy getDefaultCachePolicy() {
+ return source.getDefaultCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public XAResource getXAResource() {
return null;
}
Modified:
branches/maeste/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
===================================================================
---
branches/maeste/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -113,7 +113,9 @@
}
/**
- * {@inheritDoc}
+ * Get the default cache policy for this source, or null if the global default cache
policy should be used
+ *
+ * @return the default cache policy, or null if this source has no explicit default
cache policy
*/
public CachePolicy getDefaultCachePolicy() {
return defaultCachePolicy;
Modified: branches/maeste/dna-common/.classpath
===================================================================
--- branches/maeste/dna-common/.classpath 2008-06-06 21:21:35 UTC (rev 245)
+++ branches/maeste/dna-common/.classpath 2008-06-07 12:28:47 UTC (rev 246)
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
- <classpathentry kind="src" path="src/test/java"/>
- <classpathentry excluding="**" kind="src"
output="src/main/resources" path="src/main/resources"/>
- <classpathentry excluding="**" kind="src"
output="src/test/resources" path="src/test/resources"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/resources"/>
<classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
Modified:
branches/maeste/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java
===================================================================
---
branches/maeste/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -46,6 +46,7 @@
public class StringUtil {
public static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final Pattern NORMALIZE_PATTERN = Pattern.compile("\\s+");
private static final Pattern PARAMETER_COUNT_PATTERN =
Pattern.compile("\\{(\\d+)\\}");
/**
@@ -623,18 +624,31 @@
/**
* Get the stack trace of the supplied exception.
*
- * @param t the exception for which the stack trace is to be returned
+ * @param throwable the exception for which the stack trace is to be returned
* @return the stack trace, or null if the supplied exception is null
*/
- public static String getStackTrace( Throwable t ) {
- if (t == null) return null;
+ public static String getStackTrace( Throwable throwable ) {
+ if (throwable == null) return null;
final ByteArrayOutputStream bas = new ByteArrayOutputStream();
final PrintWriter pw = new PrintWriter(bas);
- t.printStackTrace(pw);
+ throwable.printStackTrace(pw);
pw.close();
return bas.toString();
}
+ /**
+ * Removes leading and trailing whitespace from the supplied text, and reduces other
consecutive whitespace characters to a
+ * single space. Whitespace includes line-feeds.
+ *
+ * @param text the text to be normalized
+ * @return the normalized text
+ */
+ public static String normalize( String text ) {
+ ArgCheck.isNotNull(text, "text");
+ // This could be much more efficient.
+ return NORMALIZE_PATTERN.matcher(text).replaceAll(" ").trim();
+ }
+
private StringUtil() {
// Prevent construction
}
Modified:
branches/maeste/dna-common/src/test/java/org/jboss/dna/common/util/StringUtilTest.java
===================================================================
---
branches/maeste/dna-common/src/test/java/org/jboss/dna/common/util/StringUtilTest.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-common/src/test/java/org/jboss/dna/common/util/StringUtilTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -415,6 +415,26 @@
assertThat(StringUtil.readableString(list3), is("[ [ \"a1\",
\"a2\" ], [ \"b1\", \"b2\" ] ]"));
}
+ @Test( expected = IllegalArgumentException.class )
+ public void normalizeShouldFailIfTextNull() {
+ StringUtil.normalize(null);
+ }
+
+ @Test
+ public void normalizeShouldRemoveLeadingTrailingWhitespace() {
+ assertThat(StringUtil.normalize(" \t\n test this \t"), is("test
this"));
+ }
+
+ @Test
+ public void normalizeShouldReduceInternalWhitespace() {
+ assertThat(StringUtil.normalize("test \t\n\r this"), is("test
this"));
+ }
+
+ @Test
+ public void normalizeShouldReturnEqualStringIfNothingToNormalize() {
+ assertThat(StringUtil.normalize("test this"), is("test this"));
+ }
+
protected class InputStreamWrapper extends InputStream {
private boolean closed = false;
Modified: branches/maeste/dna-integration-tests/.classpath
===================================================================
--- branches/maeste/dna-integration-tests/.classpath 2008-06-06 21:21:35 UTC (rev 245)
+++ branches/maeste/dna-integration-tests/.classpath 2008-06-07 12:28:47 UTC (rev 246)
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
- <classpathentry kind="src" path="src/test/java"/>
- <classpathentry excluding="**" kind="src"
output="src/main/resources" path="src/main/resources"/>
- <classpathentry excluding="**" kind="src"
output="src/test/resources" path="src/test/resources"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/resources"/>
<classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
Modified: branches/maeste/dna-maven-classloader/.classpath
===================================================================
--- branches/maeste/dna-maven-classloader/.classpath 2008-06-06 21:21:35 UTC (rev 245)
+++ branches/maeste/dna-maven-classloader/.classpath 2008-06-07 12:28:47 UTC (rev 246)
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
- <classpathentry kind="src" path="src/test/java"/>
- <classpathentry excluding="**" kind="src"
output="src/main/resources" path="src/main/resources"/>
- <classpathentry excluding="**" kind="src"
output="src/test/resources" path="src/test/resources"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/resources"/>
<classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
Modified: branches/maeste/dna-repository/.classpath
===================================================================
--- branches/maeste/dna-repository/.classpath 2008-06-06 21:21:35 UTC (rev 245)
+++ branches/maeste/dna-repository/.classpath 2008-06-07 12:28:47 UTC (rev 246)
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
- <classpathentry kind="src" path="src/test/java"/>
- <classpathentry excluding="**" kind="src"
output="src/main/resources" path="src/main/resources"/>
- <classpathentry excluding="**" kind="src"
output="src/test/resources" path="src/test/resources"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/resources"/>
<classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
Modified: branches/maeste/dna-repository/pom.xml
===================================================================
--- branches/maeste/dna-repository/pom.xml 2008-06-06 21:21:35 UTC (rev 245)
+++ branches/maeste/dna-repository/pom.xml 2008-06-07 12:28:47 UTC (rev 246)
@@ -35,6 +35,13 @@
<groupId>org.jboss.dna</groupId>
<artifactId>dna-spi</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<!--
Rules
-->
@@ -70,6 +77,11 @@
<artifactId>jmock-junit4</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
<!--
Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for
testing)
-->
Modified:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
===================================================================
---
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -27,6 +27,7 @@
/**
* @author Randall Hauch
+ * @author John Verhaeg
*/
public final class RepositoryI18n {
@@ -102,6 +103,17 @@
public static I18n invalidRepositoryNodePath;
+ // XML Sequencer
+ public static I18n errorSequencingXmlDocument;
+ public static I18n sequencingXmlDocument;
+ public static I18n canceledSequencingXmlDocument;
+
+ public static I18n interruptedWhileConnectingToFederationConfigurationRepository;
+ public static I18n
interruptedWhileClosingConnectionToFederationConfigurationRepository;
+ public static I18n unableToCreateConnectionToFederatedRepository;
+ public static I18n unableToAuthenticateConnectionToFederatedRepository;
+ public static I18n repositoryHasBeenShutDown;
+
static {
try {
I18n.initialize(RepositoryI18n.class);
Copied:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java
(from rev 245,
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java)
===================================================================
---
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java
(rev 0)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,343 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.repository.services.AbstractServiceAdministrator;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * The component in the {@link FederationService} that represents a single federated
repository. The federated repository manages
+ * a set of {@link FederatedSource federated sources}, and provides the logic of
interacting with those sources and presenting a
+ * single unified graph.
+ *
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class FederatedRepository {
+
+ /**
+ * The administrative component for this service.
+ *
+ * @author Randall Hauch
+ */
+ protected class Administrator extends AbstractServiceAdministrator {
+
+ protected Administrator() {
+ super(RepositoryI18n.federationServiceName, State.STARTED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doStart( State fromState ) {
+ super.doStart(fromState);
+ FederatedRepository.this.startRepository();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doShutdown( State fromState ) {
+ super.doShutdown(fromState);
+ FederatedRepository.this.shutdownRepository();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean awaitTermination( long timeout, TimeUnit unit ) throws
InterruptedException {
+ return FederatedRepository.this.awaitTermination(timeout, unit);
+ }
+
+ }
+
+ private final ServiceAdministrator administrator = new Administrator();
+ private final String name;
+ private final FederationService service;
+ private final Lock sourcesWriteLock = new ReentrantLock();
+ private final List<FederatedSource> sources = new
CopyOnWriteArrayList<FederatedSource>();
+ private final CopyOnWriteArrayList<RepositorySourceListener> listeners = new
CopyOnWriteArrayList<RepositorySourceListener>();
+ private CachePolicy defaultCachePolicy;
+
+ /**
+ * Create a federated repository instance, as managed by the supplied {@link
FederationService}.
+ *
+ * @param service the federation service that is managing this instance
+ * @param name the name of the repository
+ * @throws IllegalArgumentException if the service is null or the name is null or
blank
+ */
+ public FederatedRepository( FederationService service, String name ) {
+ ArgCheck.isNotNull(service, "service");
+ ArgCheck.isNotEmpty(name, "name");
+ this.name = name;
+ this.service = service;
+ }
+
+ /**
+ * Get the name of this repository
+ *
+ * @return name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * @return administrator
+ */
+ public ServiceAdministrator getAdministrator() {
+ return this.administrator;
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ protected void startRepository() {
+ // Do not establish connections to the sources; these will be established as
needed
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ protected void shutdownRepository() {
+ // Close all connections to the sources. This is done inside the sources write
lock.
+ try {
+ this.sourcesWriteLock.lock();
+ for (FederatedSource source : this.sources) {
+ source.getConnectionPool().shutdown();
+ }
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ // Connections to this repository check before doing anything with this, so just
remove it from the service ...
+ this.service.removeRepository(this);
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ protected boolean awaitTermination( long timeout, TimeUnit unit ) throws
InterruptedException {
+ // Check whether all source pools are shut down. This is done inside the sources
write lock.
+ try {
+ this.sourcesWriteLock.lock();
+ for (FederatedSource source : this.sources) {
+ if (!source.getConnectionPool().awaitTermination(timeout, unit)) {
+ return false;
+ }
+ }
+ return true;
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ }
+
+ /**
+ * Get an unmodifiable collection of {@link FederatedSource federated sources}.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @return the sources
+ */
+ public List<FederatedSource> getSources() {
+ return Collections.unmodifiableList(this.sources);
+ }
+
+ /**
+ * Add the supplied federated source. This method returns false if the source is
null.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param source the source to add
+ * @return true if the source is added, or false if the reference is null or if there
is already an existing source with the
+ * supplied name.
+ */
+ public boolean addSource( FederatedSource source ) {
+ if (source == null) return false;
+ try {
+ this.sourcesWriteLock.lock();
+ for (FederatedSource existingSource : this.sources) {
+ if (existingSource.getName().equals(source.getName())) return false;
+ }
+ this.sources.add(source);
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ return true;
+ }
+
+ /**
+ * Add the supplied federated source. This method returns false if the source is
null.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param source the source to add
+ * @param index the index at which the source should be added
+ * @return true if the source is added, or false if the reference is null or if there
is already an existing source with the
+ * supplied name.
+ * @throws IndexOutOfBoundsException if the index is out of bounds
+ */
+ public boolean addSource( FederatedSource source, int index ) {
+ if (source == null) return false;
+ try {
+ this.sourcesWriteLock.lock();
+ for (FederatedSource existingSource : this.sources) {
+ if (existingSource.getName().equals(source.getName())) return false;
+ }
+ this.sources.add(index, source);
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ return true;
+ }
+
+ /**
+ * Remove from this federated repository the supplied source (or a source with the
same name as that supplied). This call
+ * shuts down the connections in the source in an orderly fashion, allowing those
connection currently in use to be used and
+ * closed normally, but preventing further connections from being used.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param source the source to be removed
+ * @param timeToAwait the amount of time to wait while all of the source's
connections are closed, or non-positive if the call
+ * should not wait at all
+ * @param unit the time unit to be used for <code>timeToAwait</code>
+ * @return true if the source was removed, or false if the source was not a source
for this repository.
+ * @throws InterruptedException if the thread is interrupted while awaiting closing
of the connections
+ */
+ public boolean removeSource( FederatedSource source, long timeToAwait, TimeUnit unit
) throws InterruptedException {
+ // Use the name; don't use the object equality ...
+ return removeSource(source.getName(), timeToAwait, unit) != null;
+ }
+
+ /**
+ * Remove from this federated repository the source with the supplied name. This call
shuts down the connections in the source
+ * in an orderly fashion, allowing those connection currently in use to be used and
closed normally, but preventing further
+ * connections from being used.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param name the name of the source to be removed
+ * @param timeToAwait the amount of time to wait while all of the source's
connections are closed, or non-positive if the call
+ * should not wait at all
+ * @param unit the time unit to be used for <code>timeToAwait</code>
+ * @return the source with the supplied name that was removed, or null if no existing
source matching the supplied name could
+ * be found
+ * @throws InterruptedException if the thread is interrupted while awaiting closing
of the connections
+ */
+ public FederatedSource removeSource( String name, long timeToAwait, TimeUnit unit )
throws InterruptedException {
+ try {
+ this.sourcesWriteLock.lock();
+ for (FederatedSource existingSource : this.sources) {
+ if (existingSource.getName().equals(name)) {
+ boolean removed = this.sources.remove(existingSource);
+ assert removed;
+ // Shut down the connection pool for the source ...
+ RepositoryConnectionPool pool = existingSource.getConnectionPool();
+ pool.shutdown();
+ if (timeToAwait > 0l) pool.awaitTermination(timeToAwait, unit);
+ return existingSource;
+ }
+ }
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ return null;
+ }
+
+ /**
+ * Add a listener that is to receive notifications to changes to content within this
repository. This method does nothing if
+ * the supplied listener is null.
+ *
+ * @param listener the new listener
+ */
+ public void addListener( RepositorySourceListener listener ) {
+ if (listener == null) return;
+ this.listeners.addIfAbsent(listener);
+ }
+
+ /**
+ * Remove the supplied listener. This method does nothing if the supplied listener is
null.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param listener the listener to remove
+ * @return true if the listener was removed, or false if the listener was not
registered
+ */
+ public boolean removeListener( RepositorySourceListener listener ) {
+ if (listener == null) return false;
+ return this.listeners.remove(listener);
+ }
+
+ /**
+ * Authenticate the supplied username with the supplied credentials, and return
whether authentication was successful.
+ *
+ * @param username the username
+ * @param credentials the credentials
+ * @return true if authentication succeeded, or false otherwise
+ */
+ public boolean authenticate( String username, Object credentials ) {
+ return true;
+ }
+
+ /**
+ * Get the default cache policy for the repository with the supplied name
+ *
+ * @return the default cache policy
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return defaultCachePolicy;
+ }
+
+ /**
+ * Set the default cache policy for the federated repository.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param defaultCachePolicy Sets defaultCachePolicy to the specified value.
+ */
+ public void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
+ ArgCheck.isNotNull(defaultCachePolicy, "defaultCachePolicy");
+ this.defaultCachePolicy = defaultCachePolicy;
+ }
+
+}
Copied:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java
(from rev 245,
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java)
===================================================================
---
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java
(rev 0)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,129 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import java.util.concurrent.TimeUnit;
+import javax.transaction.xa.XAResource;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class FederatedRepositoryConnection implements RepositoryConnection {
+
+ protected static final RepositorySourceListener NO_OP_LISTENER = new
RepositorySourceListener() {
+
+ public void notify( String sourceName, Object... events ) {
+ // do nothing
+ }
+ };
+
+ private final FederatedRepository repository;
+ private final FederatedRepositorySource source;
+ private RepositorySourceListener listener = NO_OP_LISTENER;
+
+ protected FederatedRepositoryConnection( FederatedRepository repository,
FederatedRepositorySource source ) {
+ assert source != null;
+ assert repository != null;
+ this.source = source;
+ this.repository = repository;
+ }
+
+ /**
+ * @return repository
+ */
+ protected FederatedRepository getRepository() {
+ return this.repository;
+ }
+
+ /**
+ * @return source
+ */
+ protected FederatedRepositorySource getRepositorySource() {
+ return this.source;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSourceName() {
+ return this.source.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return this.repository.getDefaultCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public XAResource getXAResource() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setListener( RepositorySourceListener listener ) {
+ RepositorySourceListener oldListener = this.listener;
+ this.listener = listener != null ? listener : NO_OP_LISTENER;
+ this.repository.addListener(this.listener);
+ if (oldListener != NO_OP_LISTENER) {
+ this.repository.removeListener(oldListener);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean ping( long time, TimeUnit unit ) {
+ return this.repository.getAdministrator().isStarted();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void execute( ExecutionEnvironment env, GraphCommand... commands ) throws
RepositorySourceException {
+ if (!this.repository.getAdministrator().isStarted()) {
+ throw new
RepositorySourceException(RepositoryI18n.repositoryHasBeenShutDown.text(this.repository.getName()));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() {
+ this.repository.removeListener(this.listener);
+ }
+
+}
Copied:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositorySource.java
(from rev 245,
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositorySource.java)
===================================================================
---
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositorySource.java
(rev 0)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositorySource.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,246 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import javax.naming.Context;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class FederatedRepositorySource implements RepositorySource {
+
+ public static final int DEFAULT_RETRY_LIMIT = 0;
+
+ protected static final String USERNAME = "username";
+ protected static final String CREDENTIALS = "credentials";
+ protected static final String SOURCE_NAME = "sourceName";
+ protected static final String REPOSITORY_NAME = "repositoryName";
+ protected static final String RETRY_LIMIT = "retryLimit";
+ protected static final String FEDERATION_SERVICE_JNDI_NAME =
"fedServiceJndiName";
+
+ private final String repositoryName;
+ private final FederationService federationService;
+ private String sourceName;
+ private int retryLimit;
+ private String username;
+ private String credentials;
+
+ /**
+ *
+ */
+ protected FederatedRepositorySource( FederationService federationService, String
repositoryName ) {
+ ArgCheck.isNotNull(federationService, "federationService");
+ ArgCheck.isNotNull(repositoryName, "repositoryName");
+ this.federationService = federationService;
+ this.repositoryName = repositoryName;
+ this.retryLimit = DEFAULT_RETRY_LIMIT;
+ }
+
+ /**
+ * @return federationService
+ */
+ public FederationService getFederationService() {
+ return this.federationService;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getRetryLimit() {
+ return this.retryLimit;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setRetryLimit( int limit ) {
+ this.retryLimit = limit > 0 ? limit : 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RepositoryConnection getConnection() throws RepositorySourceException {
+ // Find the repository ...
+ FederatedRepository repository =
federationService.getRepository(this.repositoryName);
+ if (repository == null) {
+ throw new
RepositorySourceException(RepositoryI18n.unableToCreateConnectionToFederatedRepository.text(this.repositoryName));
+ }
+ // Authenticate the user ...
+ String username = this.username;
+ Object credentials = this.credentials;
+ if (!repository.authenticate(username, credentials)) {
+ throw new
RepositorySourceException(RepositoryI18n.unableToAuthenticateConnectionToFederatedRepository.text(this.repositoryName,
username));
+ }
+ // Return the new connection ...
+ return new FederatedRepositoryConnection(repository, this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return sourceName;
+ }
+
+ /**
+ * @param sourceName the name of this repository source
+ */
+ public void setName( String sourceName ) {
+ this.sourceName = sourceName;
+ }
+
+ /**
+ * @return username
+ */
+ public String getUsername() {
+ return this.username;
+ }
+
+ /**
+ * @param username Sets username to the specified value.
+ */
+ public void setUsername( String username ) {
+ this.username = username;
+ }
+
+ /**
+ * @return credentials
+ */
+ public String getCredentials() {
+ return this.credentials;
+ }
+
+ /**
+ * @param credentials Sets credentials to the specified value.
+ */
+ public void setCredentials( String credentials ) {
+ this.credentials = credentials;
+ }
+
+ /**
+ * @return repositoryName
+ */
+ public String getRepositoryName() {
+ return this.repositoryName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Reference getReference() {
+ String className = getClass().getName();
+ String factoryClassName = NamingContextObjectFactory.class.getName();
+ Reference ref = new Reference(className, factoryClassName, null);
+
+ ref.add(new StringRefAddr(USERNAME, this.getUsername()));
+ ref.add(new StringRefAddr(CREDENTIALS, this.getCredentials()));
+ ref.add(new StringRefAddr(SOURCE_NAME, this.sourceName));
+ ref.add(new StringRefAddr(REPOSITORY_NAME, this.repositoryName));
+ ref.add(new StringRefAddr(FEDERATION_SERVICE_JNDI_NAME,
this.federationService.getJndiName()));
+ ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
+ return ref;
+ }
+
+ public static class NamingContextObjectFactory implements ObjectFactory {
+
+ public NamingContextObjectFactory() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getObjectInstance( Object obj, javax.naming.Name name, Context
nameCtx, Hashtable<?, ?> environment ) throws Exception {
+ if (obj instanceof Reference) {
+ Map<String, String> values = new HashMap<String, String>();
+ Reference ref = (Reference)obj;
+ Enumeration<?> en = ref.getAll();
+ while (en.hasMoreElements()) {
+ RefAddr subref = (RefAddr)en.nextElement();
+ String key = subref.getType();
+ Object value = subref.getContent();
+ values.put(key, (String)value);
+ }
+ String repositoryName =
values.get(FederatedRepositorySource.REPOSITORY_NAME);
+ String username = values.get(FederatedRepositorySource.USERNAME);
+ String credentials = values.get(FederatedRepositorySource.CREDENTIALS);
+ String retryLimit = values.get(FederatedRepositorySource.RETRY_LIMIT);
+ String sourceName = values.get(FederatedRepositorySource.SOURCE_NAME);
+ String federationSourceJndiName =
values.get(FederatedRepositorySource.FEDERATION_SERVICE_JNDI_NAME);
+
+ // Look for the federation service ...
+ FederationService federationService =
(FederationService)nameCtx.lookup(federationSourceJndiName);
+ FederatedRepositorySource source = new
FederatedRepositorySource(federationService, repositoryName);
+ if (retryLimit != null)
source.setRetryLimit(Integer.parseInt(retryLimit));
+ if (sourceName != null) source.setName(sourceName);
+ if (username != null) source.setUsername(username);
+ if (credentials != null) source.setCredentials(credentials);
+ return source;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return repositoryName.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof FederatedRepositorySource) {
+ FederatedRepositorySource that = (FederatedRepositorySource)obj;
+ // The repository name, source name, and federation service must all match
+ if (!this.getRepositoryName().equals(that.getRepositoryName())) return
false;
+ if (!this.getFederationService().equals(that.getFederationService())) return
false;
+ if (this.getName() == null) {
+ if (that.getName() != null) return false;
+ } else {
+ if (!this.getName().equals(that.getName())) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+}
Copied:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java
(from rev 245,
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java)
===================================================================
---
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java
(rev 0)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,131 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import java.util.concurrent.TimeUnit;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * A component that represents a {@link RepositorySource repository source} (with its
state) being federated in a
+ * {@link FederatedRepository}.
+ *
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class FederatedSource {
+
+ private final RepositorySource source;
+ private final RepositoryConnectionPool connectionPool;
+
+ public FederatedSource( RepositorySource source ) {
+ ArgCheck.isNotNull(source, "source");
+ this.source = source;
+ this.connectionPool = new RepositoryConnectionPool(source);
+ }
+
+ /**
+ * Get the name for this federated repository source.
+ *
+ * @return the name; never null or empty
+ */
+ public String getName() {
+ return this.source.getName();
+ }
+
+ /**
+ * Get the RepositorySource repository source information for this federated source.
+ *
+ * @return the repository source; never null
+ */
+ public RepositorySource getRepositorySource() {
+ return this.source;
+ }
+
+ /**
+ * Get the connection pool used by this federated source.
+ *
+ * @return the connection pool; never null
+ */
+ protected RepositoryConnectionPool getConnectionPool() {
+ return this.connectionPool;
+ }
+
+ /**
+ * Determine whether the federated source is available by attempting to connect to
the source and
+ * {@link RepositoryConnection#ping(long, TimeUnit) pinging} the source.
+ *
+ * @param timeToWait the time the caller is willing to wait to establish a
connection
+ * @param unit the time unit for the <code>timeToWait</code> parameter;
may not be null
+ * @return true if the federated source is available, or false if the source is not
available in the allotted time period
+ */
+ public boolean isAvailable( long timeToWait, TimeUnit unit ) {
+ RepositoryConnection connection = null;
+ try {
+ connection = this.connectionPool.getConnection();
+ return connection.ping(timeToWait, unit);
+ } catch (IllegalStateException e) {
+ // The connection pool is not running, so return false ..
+ return false;
+ } catch (InterruptedException e) {
+ // Consider an attempt to get a connection and being interrupted as NOT being
connected
+ return false;
+ } catch (Throwable e) {
+ // Consider any other failure, including RepositorySourceException, as
meaning not available
+ return false;
+ } finally {
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (InterruptedException e) {
+ // Consider an attempt to get a connection and being interrupted as
NOT being connected
+ return false;
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return source.getName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj instanceof FederatedSource) {
+ FederatedSource that = (FederatedSource)obj;
+ if (!this.source.getName().equals(that.source.getName())) return false;
+ return true;
+ }
+ return false;
+ }
+
+}
Copied:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationException.java
(from rev 245,
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationException.java)
===================================================================
---
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationException.java
(rev 0)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationException.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,62 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+
+/**
+ *
+ * @author Randall Hauch
+ */
+public class FederationException extends RuntimeException {
+
+ /**
+ *
+ */
+ public FederationException() {
+ }
+
+ /**
+ * @param message
+ */
+ public FederationException( String message ) {
+ super(message);
+
+ }
+
+ /**
+ * @param cause
+ */
+ public FederationException( Throwable cause ) {
+ super(cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public FederationException( String message, Throwable cause ) {
+ super(message, cause);
+
+ }
+
+}
Modified:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java
===================================================================
---
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -21,21 +21,29 @@
*/
package org.jboss.dna.repository.federation;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
+import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.util.ArgCheck;
import org.jboss.dna.repository.RepositoryI18n;
import org.jboss.dna.repository.services.AbstractServiceAdministrator;
import org.jboss.dna.repository.services.AdministeredService;
import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
import org.jboss.dna.spi.graph.connection.RepositorySource;
/**
* @author Randall Hauch
*/
+@ThreadSafe
public class FederationService implements AdministeredService {
/**
* The administrative component for this service.
+ *
* @author Randall Hauch
*/
protected class Administrator extends AbstractServiceAdministrator {
@@ -47,22 +55,44 @@
/**
* {@inheritDoc}
*/
+ @Override
+ protected void doStart( State fromState ) {
+ super.doStart(fromState);
+ startService();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doShutdown( State fromState ) {
+ super.doShutdown(fromState);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public boolean awaitTermination( long timeout, TimeUnit unit ) {
return true;
}
}
- private RepositorySource bootstrapSource;
+ private final RepositorySource configurationSource;
private final Administrator administrator = new Administrator();
+ private final ConcurrentMap<String, FederatedRepository> repositories = new
ConcurrentHashMap<String, FederatedRepository>();
+ private RepositoryConnection configurationConnection;
/**
* Create a federation service instance
- * @param bootstrapSource the repository source that should be used to bootstrap the
federation service
+ *
+ * @param configurationSource the repository source that contains the configuration
for this federation service (including the
+ * respositories and the sources used by the federated repositories)
* @throws IllegalArgumentException if the bootstrap source is null
*/
- public FederationService( RepositorySource bootstrapSource ) {
- ArgCheck.isNotNull(bootstrapSource, "bootstrapSource");
+ public FederationService( RepositorySource configurationSource ) {
+ ArgCheck.isNotNull(configurationSource, "configurationSource");
+ this.configurationSource = configurationSource;
}
/**
@@ -73,12 +103,98 @@
}
/**
- * Get the repository source used to obtain connections to the repository containing
the configuration information for this
- * federation service.
- * @return bootstrapSource
+ * Get the source for the repository containing the configuration for this federation
service.
+ *
+ * @return the configuration repository source; never null
*/
- public RepositorySource getBootstrapSource() {
- return this.bootstrapSource;
+ public RepositorySource getConfigurationSource() {
+ return this.configurationSource;
}
+ public String getJndiName() {
+ // TODO
+ return null;
+ }
+
+ protected void startService() {
+ if (this.configurationConnection == null) {
+ try {
+ this.configurationConnection = this.configurationSource.getConnection();
+ } catch (InterruptedException err) {
+ throw new
FederationException(RepositoryI18n.interruptedWhileConnectingToFederationConfigurationRepository.text(this.configurationSource.getName()));
+ }
+ }
+ }
+
+ /**
+ * Get the federated repository object with the given name. The resulting repository
will be started and ready to use.
+ *
+ * @param name the name of the repository
+ * @return the repository instance
+ */
+ protected FederatedRepository getRepository( String name ) {
+ // Look for an existing repository ...
+ FederatedRepository repository = this.repositories.get(name);
+ if (repository == null) {
+ // Look up the node representing the repository in the configuration ...
+
+ // New up a repository and configure it ...
+ repository = new FederatedRepository(this, name);
+ // Now register it, being careful to not overwrite any added since previous
call ..
+ FederatedRepository existingRepository = this.repositories.putIfAbsent(name,
repository);
+ if (existingRepository != null) repository = existingRepository;
+ }
+ // Make sure it's started. By doing this here, whoever finds it in the map
will start it.
+ repository.getAdministrator().start();
+ return repository;
+ }
+
+ protected void shutdownService() {
+ if (this.configurationConnection != null) {
+ try {
+ this.configurationConnection.close();
+ } catch (InterruptedException err) {
+ throw new
FederationException(RepositoryI18n.interruptedWhileClosingConnectionToFederationConfigurationRepository.text(this.configurationSource.getName()));
+ }
+ // Now shut down all repositories ...
+ for (String repositoryName : this.repositories.keySet()) {
+ FederatedRepository repository = this.repositories.get(repositoryName);
+ repository.getAdministrator().shutdown();
+ }
+ }
+ }
+
+ /**
+ * Create a {@link RepositorySource} that can be used to establish connections to the
federated repository with the supplied
+ * name.
+ *
+ * @param repositoryName the name of the federated repository
+ * @return the source that can be configured and used to establish connection to the
repository
+ */
+ public RepositorySource createRepositorySource( String repositoryName ) {
+ FederatedRepositorySource source = new FederatedRepositorySource(this,
repositoryName);
+ return source;
+ }
+
+ /**
+ * Get the current set of repository names.
+ *
+ * @return the unmodifiable names of the repository.
+ */
+ public Set<String> getRepositoryNames() {
+ return Collections.unmodifiableSet(this.repositories.keySet());
+ }
+
+ protected void removeRepository( FederatedRepository repository ) {
+ this.repositories.remove(repository.getName(), repository);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ return false;
+ }
}
Copied:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml (from
rev 245, trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml)
Deleted:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java
===================================================================
---
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -1,681 +0,0 @@
-/*
- *
- */
-package org.jboss.dna.repository.sequencers.xml;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.common.util.Logger;
-import org.jboss.dna.common.util.StringUtil;
-import org.jboss.dna.repository.RepositoryI18n;
-import org.jboss.dna.spi.graph.Name;
-import org.jboss.dna.spi.graph.NameFactory;
-import org.jboss.dna.spi.graph.NamespaceRegistry;
-import org.jboss.dna.spi.graph.Path;
-import org.jboss.dna.spi.sequencers.SequencerOutput;
-import org.jboss.dna.spi.sequencers.StreamSequencer;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXNotRecognizedException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.DefaultHandler2;
-import org.xml.sax.helpers.XMLReaderFactory;
-
-/**
- * @author John Verhaeg
- */
-public class XmlSequencer implements StreamSequencer {
-
- static final Logger LOGGER = Logger.getLogger(XmlSequencer.class);
-
- static final String CDATA = "dnaxml:cData";
- static final String CDATA_CONTENT = "dnaxml:cDataContent";
- static final String COMMENT = "dnaxml:comment";
- static final String COMMENT_CONTENT = "dnaxml:commentContent";
- static final String DOCUMENT = "dnaxml:document";
- static final String DTD_NAME = "dnadtd:name";
- static final String DTD_PUBLIC_ID = "dnadtd:publicId";
- static final String DTD_SYSTEM_ID = "dnadtd:systemId";
- static final String DTD_VALUE = "dnadtd:value";
- static final String ELEMENT_CONTENT = "dnaxml:elementContent";
- static final String ENTITY = "dnadtd:entity";
- static final String PI = "dnaxml:processingInstruction";
- static final String PI_CONTENT = "dnaxml:processingInstructionContent";
- static final String TARGET = "dnaxml:target";
-
- private static final String DECL_HANDLER_FEATURE =
"http://xml.org/sax/properties/declaration-handler";
- private static final String ENTITY_RESOLVER_2_FEATURE =
"http://xml.org/sax/features/use-entity-resolver2";
- private static final String LEXICAL_HANDLER_FEATURE =
"http://xml.org/sax/properties/lexical-handler";
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.jboss.dna.spi.sequencers.StreamSequencer#sequence(java.io.InputStream,
- * org.jboss.dna.spi.sequencers.SequencerOutput,
org.jboss.dna.common.monitor.ProgressMonitor)
- */
- public void sequence( InputStream stream,
- SequencerOutput output,
- ProgressMonitor monitor ) {
- monitor.beginTask(100.0, RepositoryI18n.sequencingXmlDocument);
- XMLReader reader;
- try {
- reader = XMLReaderFactory.createXMLReader();
- Handler handler = new Handler(output, monitor);
- reader.setContentHandler(handler);
- reader.setErrorHandler(handler);
- // Ensure handler acting as entity resolver 2
- reader.setProperty(DECL_HANDLER_FEATURE, handler);
- // Ensure handler acting as lexical handler
- reader.setProperty(LEXICAL_HANDLER_FEATURE, handler);
- // Ensure handler acting as entity resolver 2
- try {
- if (!reader.getFeature(ENTITY_RESOLVER_2_FEATURE)) {
- reader.setFeature(ENTITY_RESOLVER_2_FEATURE, true);
- }
- } catch (SAXNotRecognizedException meansFeatureNotSupported) {
- }
- // Prevent loading of external DTDs
-
reader.setFeature("http://apache.org/xml/features/nonvalidating/load...;,
false);
- // Parse XML document
- reader.parse(new InputSource(stream));
- } catch (Exception err) {
- LOGGER.error(err, RepositoryI18n.errorSequencingXmlDocument);
- } finally {
- monitor.done();
- }
- }
-
- private class Handler extends DefaultHandler2 {
-
- private ProgressMonitor monitor;
- private SequencerOutput output;
- private double progress;
-
- private Path path; // The DNA path of the node representing the current XML element
-
- // Cached instances of the name factory and commonly referenced names
- private NameFactory nameFactory;
- private Name commentContentName;
- private Name commentName;
- private Name elementContentName;
- private Name primaryTypeName;
- private Name targetName;
-
- // Recursive map used to track the number of occurrences of names for elements under a
particular path
- private Map<Name, List<IndexedName>> nameToIndexedNamesMap = new
HashMap<Name, List<IndexedName>>();
-
- // The stack of recursive maps being processed, with the head entry being the map for
the current path
- private LinkedList<Map<Name, List<IndexedName>>>
nameToIndexedNamesMapStack = new LinkedList<Map<Name,
List<IndexedName>>>();
-
- // The stack of XML namespace in scope, with the head entry being namespace of the
closest ancestor element declaring a
- // namespace.
- private LinkedList<String> nsStack = new LinkedList<String>();
-
- // Builder used to concatenate concurrent lines of CDATA into a single value.
- private StringBuilder cDataBuilder;
-
- // Builder used to concatenate concurrent lines of element content and entity
evaluations into a single value.
- private StringBuilder contentBuilder;
-
- // The entity being processed
- private String entity;
-
- Handler( SequencerOutput output,
- ProgressMonitor monitor ) {
- this.output = output;
- this.monitor = monitor;
- // Initialize path to a an empty path relative to the SequencerOutput's target
path.
- path = output.getFactories().getPathFactory().createRelativePath();
- // Cache name factory since it is frequently used
- nameFactory = output.getFactories().getNameFactory();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#attributeDecl(java.lang.String,
java.lang.String, java.lang.String,
- * java.lang.String, java.lang.String)
- */
- @Override
- public void attributeDecl( String name,
- String name2,
- String type,
- String mode,
- String value ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
- */
- @Override
- public void characters( char[] ch,
- int start,
- int length ) throws SAXException {
- stopIfCancelled();
- String content = String.valueOf(ch, start, length);
- // Check if data should be appended to previously parsed CDATA
- if (cDataBuilder == null) {
- // If content is for an entity, replace with entity reference
- if (entity != null) {
- content = '&' + entity + ';';
- }
- // Check if first line of content
- if (contentBuilder == null) {
- contentBuilder = new StringBuilder(content);
- } else {
- // Append additional lines or entity evaluations to previous content, separated by a
space
- if (entity == null) {
- contentBuilder.append(' ');
- }
- contentBuilder.append(content);
- // Text within builder will be output when another element or CDATA is encountered
- }
- } else {
- cDataBuilder.append(ch, start, length);
- // Text within builder will be output at the end of CDATA
- }
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#comment(char[], int, int)
- */
- @Override
- public void comment( char[] ch,
- int start,
- int length ) throws SAXException {
- stopIfCancelled();
- // Output separate nodes for each comment since multiple are allowed
- startElement(getCommentName());
- output.setProperty(path, getPrimaryTypeName(), getCommentName());
- output.setProperty(path, getCommentContentName(), String.valueOf(ch, start, length));
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#elementDecl(java.lang.String,
java.lang.String)
- */
- @Override
- public void elementDecl( String name,
- String model ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#endCDATA()
- */
- @Override
- public void endCDATA() throws SAXException {
- stopIfCancelled();
- // Output CDATA built in characters() method
- output.setProperty(path, nameFactory.create(CDATA_CONTENT), cDataBuilder.toString());
- endElement();
- // Null-out builder to free memory
- cDataBuilder = null;
- updateProgress();
- }
-
- private void endContent() {
- if (contentBuilder != null) {
- // Normalize content
- String content = StringUtil.normalize(contentBuilder.toString());
- // Null-out builder to setup for subsequent content.
- // Must be done before call to startElement below to prevent infinite loop.
- contentBuilder = null;
- // Skip if nothing in content but whitespace
- if (content.length() > 0) {
- // Create separate node for each content entry since entries can be interspersed
amongst child elements
- startElement(getElementContentName());
- output.setProperty(path, getPrimaryTypeName(), getElementContentName());
- output.setProperty(path, getElementContentName(), content);
- endElement();
- }
- }
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#endDocument()
- */
- @Override
- public void endDocument() throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#endDTD()
- */
- @Override
- public void endDTD() throws SAXException {
- stopIfCancelled();
- }
-
- private void endElement() {
- // Recover parent's path, namespace, and indexedName map, clearing the ended
element's map to free memory
- path = path.getAncestor();
- nameToIndexedNamesMap.clear();
- nameToIndexedNamesMap = nameToIndexedNamesMapStack.removeFirst();
- nsStack.removeFirst();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
java.lang.String, java.lang.String)
- */
- @Override
- public void endElement( String uri,
- String localName,
- String name ) throws SAXException {
- stopIfCancelled();
- // Check if content still needs to be output
- endContent();
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#endEntity(java.lang.String)
- */
- @Override
- public void endEntity( String name ) throws SAXException {
- stopIfCancelled();
- entity = null;
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
- */
- @Override
- public void error( SAXParseException error ) throws SAXException {
- LOGGER.error(error, RepositoryI18n.errorSequencingXmlDocument);
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#externalEntityDecl(java.lang.String,
java.lang.String, java.lang.String)
- */
- @Override
- public void externalEntityDecl( String name,
- String publicId,
- String systemId ) throws SAXException {
- stopIfCancelled();
- // Add "synthetic" entity container to path to help prevent name collisions
with XML elements
- Name entityName = nameFactory.create(ENTITY);
- startElement(entityName);
- output.setProperty(path, getPrimaryTypeName(), entityName);
- output.setProperty(path, nameFactory.create(DTD_NAME), name);
- output.setProperty(path, nameFactory.create(DTD_PUBLIC_ID), publicId);
- output.setProperty(path, nameFactory.create(DTD_SYSTEM_ID), systemId);
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
- */
- @Override
- public void fatalError( SAXParseException error ) throws SAXException {
- LOGGER.error(error, RepositoryI18n.errorSequencingXmlDocument);
- }
-
- private Name getCommentContentName() {
- if (commentContentName == null) {
- commentContentName = nameFactory.create(COMMENT_CONTENT);
- }
- return commentContentName;
- }
-
- private Name getCommentName() {
- if (commentName == null) {
- commentName = nameFactory.create(COMMENT);
- }
- return commentName;
- }
-
- private Name getElementContentName() {
- if (elementContentName == null) {
- elementContentName = nameFactory.create(ELEMENT_CONTENT);
- }
- return elementContentName;
- }
-
- private Name getPrimaryTypeName() {
- if (primaryTypeName == null) {
- primaryTypeName = nameFactory.create(NameFactory.JCR_PRIMARY_TYPE);
- }
- return primaryTypeName;
- }
-
- private Name getTargetName() {
- if (targetName == null) {
- targetName = nameFactory.create(TARGET);
- }
- return targetName;
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#ignorableWhitespace(char[], int, int)
- */
- @Override
- public void ignorableWhitespace( char[] ch,
- int start,
- int length ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#internalEntityDecl(java.lang.String,
java.lang.String)
- */
- @Override
- public void internalEntityDecl( String name,
- String value ) throws SAXException {
- stopIfCancelled();
- // Add "synthetic" entity container to path to help prevent name collisions
with XML elements
- Name entityName = nameFactory.create(ENTITY);
- startElement(entityName);
- output.setProperty(path, getPrimaryTypeName(), entityName);
- output.setProperty(path, nameFactory.create(DTD_NAME), name);
- output.setProperty(path, nameFactory.create(DTD_VALUE), value);
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#notationDecl(java.lang.String,
java.lang.String, java.lang.String)
- */
- @Override
- public void notationDecl( String name,
- String publicId,
- String systemId ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#processingInstruction(java.lang.String,
java.lang.String)
- */
- @Override
- public void processingInstruction( String target,
- String data ) throws SAXException {
- stopIfCancelled();
- // Output separate nodes for each instruction since multiple are allowed
- Name name = nameFactory.create(PI);
- startElement(name);
- output.setProperty(path, getPrimaryTypeName(), name);
- output.setProperty(path, getTargetName(), target);
- output.setProperty(path, nameFactory.create(PI_CONTENT), data);
- endElement();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#skippedEntity(java.lang.String)
- */
- @Override
- public void skippedEntity( String name ) throws SAXException {
- stopIfCancelled();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#startCDATA()
- */
- @Override
- public void startCDATA() throws SAXException {
- stopIfCancelled();
- // Output separate nodes for each CDATA since multiple are allowed
- startElement(nameFactory.create(CDATA));
- // Prepare builder for concatenating consecutive lines of CDATA
- cDataBuilder = new StringBuilder();
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#startDocument()
- */
- @Override
- public void startDocument() throws SAXException {
- stopIfCancelled();
- output.setProperty(path, getPrimaryTypeName(), nameFactory.create(DOCUMENT));
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#startDTD(java.lang.String, java.lang.String,
java.lang.String)
- */
- @Override
- public void startDTD( String name,
- String publicId,
- String systemId ) throws SAXException {
- stopIfCancelled();
- output.setProperty(path, nameFactory.create(DTD_NAME), name);
- output.setProperty(path, nameFactory.create(DTD_PUBLIC_ID), publicId);
- output.setProperty(path, nameFactory.create(DTD_SYSTEM_ID), systemId);
- updateProgress();
- }
-
- private void startElement( Name name ) {
- // Check if content still needs to be output
- endContent();
- // Add name to list of indexed names for this element to ensure we use the correct
index (which is the size of the
- // list)
- List<IndexedName> indexedNames = nameToIndexedNamesMap.get(name);
- if (indexedNames == null) {
- indexedNames = new ArrayList<IndexedName>();
- nameToIndexedNamesMap.put(name, indexedNames);
- }
- IndexedName indexedName = new IndexedName();
- indexedNames.add(indexedName);
- // Add element name and the appropriate index to the path.
- // Per the JCR spec, the index must be relative to same-name sibling nodes
- path = output.getFactories().getPathFactory().create(path, name,
indexedNames.size());
- // Add the indexed name map to the stack and set the current map to the new
element's map
- nameToIndexedNamesMapStack.addFirst(nameToIndexedNamesMap);
- nameToIndexedNamesMap = indexedName.nameToIndexedNamesMap;
- // Set the current namespace to whatever is declared by this element, or if not
declared, to its nearest ancestor that
- // does declare a namespace.
- String ns = name.getNamespaceUri();
- if (ns.length() == 0) {
- nsStack.addFirst(nsStack.isEmpty() ? "" : nsStack.getFirst());
- } else {
- nsStack.addFirst(ns);
- }
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
java.lang.String, java.lang.String,
- * org.xml.sax.Attributes)
- */
- @Override
- public void startElement( String uri,
- String localName,
- String name,
- Attributes attributes ) throws SAXException {
- stopIfCancelled();
- startElement(nameFactory.create(name));
- output.setProperty(path, getPrimaryTypeName(), nameFactory.create(uri, localName));
- // Output this element's attributes using the attribute's namespace, if
supplied, or the current namespace in scope.
- String inheritedNs = nsStack.getFirst();
- for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
- String ns = attributes.getURI(ndx);
- output.setProperty(path,
- nameFactory.create(ns.length() == 0 ? inheritedNs : ns,
attributes.getLocalName(ndx)),
- attributes.getValue(ndx));
- }
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.ext.DefaultHandler2#startEntity(java.lang.String)
- */
- @Override
- public void startEntity( String name ) throws SAXException {
- stopIfCancelled();
- entity = name;
- updateProgress();
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#startPrefixMapping(java.lang.String,
java.lang.String)
- */
- @Override
- public void startPrefixMapping( String prefix,
- String uri ) throws SAXException {
- stopIfCancelled();
- // Register any unregistered namespaces
- NamespaceRegistry registry = output.getNamespaceRegistry();
- if (!registry.isRegisteredNamespaceUri(uri)) {
- registry.register(prefix, uri);
- }
- updateProgress();
- }
-
- private void stopIfCancelled() throws SAXException {
- if (monitor.isCancelled()) {
- throw new SAXException(RepositoryI18n.canceledSequencingXmlDocument.text());
- }
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#unparsedEntityDecl(java.lang.String,
java.lang.String, java.lang.String,
- * java.lang.String)
- */
- @Override
- public void unparsedEntityDecl( String name,
- String publicId,
- String systemId,
- String notationName ) throws SAXException {
- stopIfCancelled();
- }
-
- private void updateProgress() {
- if (progress == 100.0) {
- progress = 1;
- } else {
- progress++;
- }
- monitor.worked(progress);
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
- */
- @Override
- public void warning( SAXParseException error ) throws SAXException {
- LOGGER.warn(error, RepositoryI18n.errorSequencingXmlDocument);
- }
- }
-
- private class IndexedName {
-
- Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name,
List<IndexedName>>();
-
- IndexedName() {
- }
- }
-}
Copied:
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java
(from rev 245,
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java)
===================================================================
---
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java
(rev 0)
+++
branches/maeste/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/xml/XmlSequencer.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,681 @@
+/*
+ *
+ */
+package org.jboss.dna.repository.sequencers.xml;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.NamespaceRegistry;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.sequencers.SequencerOutput;
+import org.jboss.dna.spi.sequencers.StreamSequencer;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.DefaultHandler2;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * @author John Verhaeg
+ */
+public class XmlSequencer implements StreamSequencer {
+
+ static final Logger LOGGER = Logger.getLogger(XmlSequencer.class);
+
+ static final String CDATA = "dnaxml:cData";
+ static final String CDATA_CONTENT = "dnaxml:cDataContent";
+ static final String COMMENT = "dnaxml:comment";
+ static final String COMMENT_CONTENT = "dnaxml:commentContent";
+ static final String DOCUMENT = "dnaxml:document";
+ static final String DTD_NAME = "dnadtd:name";
+ static final String DTD_PUBLIC_ID = "dnadtd:publicId";
+ static final String DTD_SYSTEM_ID = "dnadtd:systemId";
+ static final String DTD_VALUE = "dnadtd:value";
+ static final String ELEMENT_CONTENT = "dnaxml:elementContent";
+ static final String ENTITY = "dnadtd:entity";
+ static final String PI = "dnaxml:processingInstruction";
+ static final String PI_CONTENT = "dnaxml:processingInstructionContent";
+ static final String TARGET = "dnaxml:target";
+
+ private static final String DECL_HANDLER_FEATURE =
"http://xml.org/sax/properties/declaration-handler";
+ private static final String ENTITY_RESOLVER_2_FEATURE =
"http://xml.org/sax/features/use-entity-resolver2";
+ private static final String LEXICAL_HANDLER_FEATURE =
"http://xml.org/sax/properties/lexical-handler";
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.jboss.dna.spi.sequencers.StreamSequencer#sequence(java.io.InputStream,
+ * org.jboss.dna.spi.sequencers.SequencerOutput,
org.jboss.dna.common.monitor.ProgressMonitor)
+ */
+ public void sequence( InputStream stream,
+ SequencerOutput output,
+ ProgressMonitor monitor ) {
+ monitor.beginTask(100.0, RepositoryI18n.sequencingXmlDocument);
+ XMLReader reader;
+ try {
+ reader = XMLReaderFactory.createXMLReader();
+ Handler handler = new Handler(output, monitor);
+ reader.setContentHandler(handler);
+ reader.setErrorHandler(handler);
+ // Ensure handler acting as entity resolver 2
+ reader.setProperty(DECL_HANDLER_FEATURE, handler);
+ // Ensure handler acting as lexical handler
+ reader.setProperty(LEXICAL_HANDLER_FEATURE, handler);
+ // Ensure handler acting as entity resolver 2
+ try {
+ if (!reader.getFeature(ENTITY_RESOLVER_2_FEATURE)) {
+ reader.setFeature(ENTITY_RESOLVER_2_FEATURE, true);
+ }
+ } catch (SAXNotRecognizedException meansFeatureNotSupported) {
+ }
+ // Prevent loading of external DTDs
+
reader.setFeature("http://apache.org/xml/features/nonvalidating/load...;,
false);
+ // Parse XML document
+ reader.parse(new InputSource(stream));
+ } catch (Exception err) {
+ LOGGER.error(err, RepositoryI18n.errorSequencingXmlDocument);
+ } finally {
+ monitor.done();
+ }
+ }
+
+ private class Handler extends DefaultHandler2 {
+
+ private ProgressMonitor monitor;
+ private SequencerOutput output;
+ private double progress;
+
+ private Path path; // The DNA path of the node representing the current XML element
+
+ // Cached instances of the name factory and commonly referenced names
+ private NameFactory nameFactory;
+ private Name commentContentName;
+ private Name commentName;
+ private Name elementContentName;
+ private Name primaryTypeName;
+ private Name targetName;
+
+ // Recursive map used to track the number of occurrences of names for elements under a
particular path
+ private Map<Name, List<IndexedName>> nameToIndexedNamesMap = new
HashMap<Name, List<IndexedName>>();
+
+ // The stack of recursive maps being processed, with the head entry being the map for
the current path
+ private LinkedList<Map<Name, List<IndexedName>>>
nameToIndexedNamesMapStack = new LinkedList<Map<Name,
List<IndexedName>>>();
+
+ // The stack of XML namespace in scope, with the head entry being namespace of the
closest ancestor element declaring a
+ // namespace.
+ private LinkedList<String> nsStack = new LinkedList<String>();
+
+ // Builder used to concatenate concurrent lines of CDATA into a single value.
+ private StringBuilder cDataBuilder;
+
+ // Builder used to concatenate concurrent lines of element content and entity
evaluations into a single value.
+ private StringBuilder contentBuilder;
+
+ // The entity being processed
+ private String entity;
+
+ Handler( SequencerOutput output,
+ ProgressMonitor monitor ) {
+ this.output = output;
+ this.monitor = monitor;
+ // Initialize path to a an empty path relative to the SequencerOutput's target
path.
+ path = output.getFactories().getPathFactory().createRelativePath();
+ // Cache name factory since it is frequently used
+ nameFactory = output.getFactories().getNameFactory();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#attributeDecl(java.lang.String,
java.lang.String, java.lang.String,
+ * java.lang.String, java.lang.String)
+ */
+ @Override
+ public void attributeDecl( String name,
+ String name2,
+ String type,
+ String mode,
+ String value ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
+ */
+ @Override
+ public void characters( char[] ch,
+ int start,
+ int length ) throws SAXException {
+ stopIfCancelled();
+ String content = String.valueOf(ch, start, length);
+ // Check if data should be appended to previously parsed CDATA
+ if (cDataBuilder == null) {
+ // If content is for an entity, replace with entity reference
+ if (entity != null) {
+ content = '&' + entity + ';';
+ }
+ // Check if first line of content
+ if (contentBuilder == null) {
+ contentBuilder = new StringBuilder(content);
+ } else {
+ // Append additional lines or entity evaluations to previous content, separated by a
space
+ if (entity == null) {
+ contentBuilder.append(' ');
+ }
+ contentBuilder.append(content);
+ // Text within builder will be output when another element or CDATA is encountered
+ }
+ } else {
+ cDataBuilder.append(ch, start, length);
+ // Text within builder will be output at the end of CDATA
+ }
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#comment(char[], int, int)
+ */
+ @Override
+ public void comment( char[] ch,
+ int start,
+ int length ) throws SAXException {
+ stopIfCancelled();
+ // Output separate nodes for each comment since multiple are allowed
+ startElement(getCommentName());
+ output.setProperty(path, getPrimaryTypeName(), getCommentName());
+ output.setProperty(path, getCommentContentName(), String.valueOf(ch, start, length));
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#elementDecl(java.lang.String,
java.lang.String)
+ */
+ @Override
+ public void elementDecl( String name,
+ String model ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#endCDATA()
+ */
+ @Override
+ public void endCDATA() throws SAXException {
+ stopIfCancelled();
+ // Output CDATA built in characters() method
+ output.setProperty(path, nameFactory.create(CDATA_CONTENT), cDataBuilder.toString());
+ endElement();
+ // Null-out builder to free memory
+ cDataBuilder = null;
+ updateProgress();
+ }
+
+ private void endContent() {
+ if (contentBuilder != null) {
+ // Normalize content
+ String content = StringUtil.normalize(contentBuilder.toString());
+ // Null-out builder to setup for subsequent content.
+ // Must be done before call to startElement below to prevent infinite loop.
+ contentBuilder = null;
+ // Skip if nothing in content but whitespace
+ if (content.length() > 0) {
+ // Create separate node for each content entry since entries can be interspersed
amongst child elements
+ startElement(getElementContentName());
+ output.setProperty(path, getPrimaryTypeName(), getElementContentName());
+ output.setProperty(path, getElementContentName(), content);
+ endElement();
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#endDocument()
+ */
+ @Override
+ public void endDocument() throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#endDTD()
+ */
+ @Override
+ public void endDTD() throws SAXException {
+ stopIfCancelled();
+ }
+
+ private void endElement() {
+ // Recover parent's path, namespace, and indexedName map, clearing the ended
element's map to free memory
+ path = path.getAncestor();
+ nameToIndexedNamesMap.clear();
+ nameToIndexedNamesMap = nameToIndexedNamesMapStack.removeFirst();
+ nsStack.removeFirst();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
java.lang.String, java.lang.String)
+ */
+ @Override
+ public void endElement( String uri,
+ String localName,
+ String name ) throws SAXException {
+ stopIfCancelled();
+ // Check if content still needs to be output
+ endContent();
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#endEntity(java.lang.String)
+ */
+ @Override
+ public void endEntity( String name ) throws SAXException {
+ stopIfCancelled();
+ entity = null;
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void error( SAXParseException error ) throws SAXException {
+ LOGGER.error(error, RepositoryI18n.errorSequencingXmlDocument);
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#externalEntityDecl(java.lang.String,
java.lang.String, java.lang.String)
+ */
+ @Override
+ public void externalEntityDecl( String name,
+ String publicId,
+ String systemId ) throws SAXException {
+ stopIfCancelled();
+ // Add "synthetic" entity container to path to help prevent name collisions
with XML elements
+ Name entityName = nameFactory.create(ENTITY);
+ startElement(entityName);
+ output.setProperty(path, getPrimaryTypeName(), entityName);
+ output.setProperty(path, nameFactory.create(DTD_NAME), name);
+ output.setProperty(path, nameFactory.create(DTD_PUBLIC_ID), publicId);
+ output.setProperty(path, nameFactory.create(DTD_SYSTEM_ID), systemId);
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void fatalError( SAXParseException error ) throws SAXException {
+ LOGGER.error(error, RepositoryI18n.errorSequencingXmlDocument);
+ }
+
+ private Name getCommentContentName() {
+ if (commentContentName == null) {
+ commentContentName = nameFactory.create(COMMENT_CONTENT);
+ }
+ return commentContentName;
+ }
+
+ private Name getCommentName() {
+ if (commentName == null) {
+ commentName = nameFactory.create(COMMENT);
+ }
+ return commentName;
+ }
+
+ private Name getElementContentName() {
+ if (elementContentName == null) {
+ elementContentName = nameFactory.create(ELEMENT_CONTENT);
+ }
+ return elementContentName;
+ }
+
+ private Name getPrimaryTypeName() {
+ if (primaryTypeName == null) {
+ primaryTypeName = nameFactory.create(NameFactory.JCR_PRIMARY_TYPE);
+ }
+ return primaryTypeName;
+ }
+
+ private Name getTargetName() {
+ if (targetName == null) {
+ targetName = nameFactory.create(TARGET);
+ }
+ return targetName;
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#ignorableWhitespace(char[], int, int)
+ */
+ @Override
+ public void ignorableWhitespace( char[] ch,
+ int start,
+ int length ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#internalEntityDecl(java.lang.String,
java.lang.String)
+ */
+ @Override
+ public void internalEntityDecl( String name,
+ String value ) throws SAXException {
+ stopIfCancelled();
+ // Add "synthetic" entity container to path to help prevent name collisions
with XML elements
+ Name entityName = nameFactory.create(ENTITY);
+ startElement(entityName);
+ output.setProperty(path, getPrimaryTypeName(), entityName);
+ output.setProperty(path, nameFactory.create(DTD_NAME), name);
+ output.setProperty(path, nameFactory.create(DTD_VALUE), value);
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#notationDecl(java.lang.String,
java.lang.String, java.lang.String)
+ */
+ @Override
+ public void notationDecl( String name,
+ String publicId,
+ String systemId ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#processingInstruction(java.lang.String,
java.lang.String)
+ */
+ @Override
+ public void processingInstruction( String target,
+ String data ) throws SAXException {
+ stopIfCancelled();
+ // Output separate nodes for each instruction since multiple are allowed
+ Name name = nameFactory.create(PI);
+ startElement(name);
+ output.setProperty(path, getPrimaryTypeName(), name);
+ output.setProperty(path, getTargetName(), target);
+ output.setProperty(path, nameFactory.create(PI_CONTENT), data);
+ endElement();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#skippedEntity(java.lang.String)
+ */
+ @Override
+ public void skippedEntity( String name ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#startCDATA()
+ */
+ @Override
+ public void startCDATA() throws SAXException {
+ stopIfCancelled();
+ // Output separate nodes for each CDATA since multiple are allowed
+ startElement(nameFactory.create(CDATA));
+ // Prepare builder for concatenating consecutive lines of CDATA
+ cDataBuilder = new StringBuilder();
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#startDocument()
+ */
+ @Override
+ public void startDocument() throws SAXException {
+ stopIfCancelled();
+ output.setProperty(path, getPrimaryTypeName(), nameFactory.create(DOCUMENT));
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#startDTD(java.lang.String, java.lang.String,
java.lang.String)
+ */
+ @Override
+ public void startDTD( String name,
+ String publicId,
+ String systemId ) throws SAXException {
+ stopIfCancelled();
+ output.setProperty(path, nameFactory.create(DTD_NAME), name);
+ output.setProperty(path, nameFactory.create(DTD_PUBLIC_ID), publicId);
+ output.setProperty(path, nameFactory.create(DTD_SYSTEM_ID), systemId);
+ updateProgress();
+ }
+
+ private void startElement( Name name ) {
+ // Check if content still needs to be output
+ endContent();
+ // Add name to list of indexed names for this element to ensure we use the correct
index (which is the size of the
+ // list)
+ List<IndexedName> indexedNames = nameToIndexedNamesMap.get(name);
+ if (indexedNames == null) {
+ indexedNames = new ArrayList<IndexedName>();
+ nameToIndexedNamesMap.put(name, indexedNames);
+ }
+ IndexedName indexedName = new IndexedName();
+ indexedNames.add(indexedName);
+ // Add element name and the appropriate index to the path.
+ // Per the JCR spec, the index must be relative to same-name sibling nodes
+ path = output.getFactories().getPathFactory().create(path, name,
indexedNames.size());
+ // Add the indexed name map to the stack and set the current map to the new
element's map
+ nameToIndexedNamesMapStack.addFirst(nameToIndexedNamesMap);
+ nameToIndexedNamesMap = indexedName.nameToIndexedNamesMap;
+ // Set the current namespace to whatever is declared by this element, or if not
declared, to its nearest ancestor that
+ // does declare a namespace.
+ String ns = name.getNamespaceUri();
+ if (ns.length() == 0) {
+ nsStack.addFirst(nsStack.isEmpty() ? "" : nsStack.getFirst());
+ } else {
+ nsStack.addFirst(ns);
+ }
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
java.lang.String, java.lang.String,
+ * org.xml.sax.Attributes)
+ */
+ @Override
+ public void startElement( String uri,
+ String localName,
+ String name,
+ Attributes attributes ) throws SAXException {
+ stopIfCancelled();
+ startElement(nameFactory.create(name));
+ output.setProperty(path, getPrimaryTypeName(), nameFactory.create(uri, localName));
+ // Output this element's attributes using the attribute's namespace, if
supplied, or the current namespace in scope.
+ String inheritedNs = nsStack.getFirst();
+ for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) {
+ String ns = attributes.getURI(ndx);
+ output.setProperty(path,
+ nameFactory.create(ns.length() == 0 ? inheritedNs : ns,
attributes.getLocalName(ndx)),
+ attributes.getValue(ndx));
+ }
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.ext.DefaultHandler2#startEntity(java.lang.String)
+ */
+ @Override
+ public void startEntity( String name ) throws SAXException {
+ stopIfCancelled();
+ entity = name;
+ updateProgress();
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#startPrefixMapping(java.lang.String,
java.lang.String)
+ */
+ @Override
+ public void startPrefixMapping( String prefix,
+ String uri ) throws SAXException {
+ stopIfCancelled();
+ // Register any unregistered namespaces
+ NamespaceRegistry registry = output.getNamespaceRegistry();
+ if (!registry.isRegisteredNamespaceUri(uri)) {
+ registry.register(prefix, uri);
+ }
+ updateProgress();
+ }
+
+ private void stopIfCancelled() throws SAXException {
+ if (monitor.isCancelled()) {
+ throw new SAXException(RepositoryI18n.canceledSequencingXmlDocument.text());
+ }
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#unparsedEntityDecl(java.lang.String,
java.lang.String, java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public void unparsedEntityDecl( String name,
+ String publicId,
+ String systemId,
+ String notationName ) throws SAXException {
+ stopIfCancelled();
+ }
+
+ private void updateProgress() {
+ if (progress == 100.0) {
+ progress = 1;
+ } else {
+ progress++;
+ }
+ monitor.worked(progress);
+ }
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ *
+ * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
+ */
+ @Override
+ public void warning( SAXParseException error ) throws SAXException {
+ LOGGER.warn(error, RepositoryI18n.errorSequencingXmlDocument);
+ }
+ }
+
+ private class IndexedName {
+
+ Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name,
List<IndexedName>>();
+
+ IndexedName() {
+ }
+ }
+}
Modified:
branches/maeste/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
===================================================================
---
branches/maeste/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2008-06-07
12:28:47 UTC (rev 246)
@@ -90,3 +90,13 @@
errorUnregisteringWorkspaceListenerWhileShuttingDownObservationService = Error
unregistering workspace listener while shutting down observation service
invalidRepositoryNodePath = The repository node path "{0}" is not valid: {1}
+
+errorSequencingXmlDocument = An error occurred while sequencing XML:
+sequencingXmlDocument = Sequencing XML
+canceledSequencingXmlDocument = Canceled sequencing XML
+
+interruptedWhileConnectingToFederationConfigurationRepository = Interrupted while
connecting to federation configuration repository for "{0}" repository
+interruptedWhileClosingConnectionToFederationConfigurationRepository = Interrupted while
closing connection to federation configuration repository for "{0}" repository
+unableToCreateConnectionToFederatedRepository = Unable to create a connection to the
repository "{0}". Check the Federation Service configuration.
+unableToAuthenticateConnectionToFederatedRepository = Unable to authenticate
"{1}" for repository "{0}"
+repositoryHasBeenShutDown = The "{0}" repository has been shut down and may no
longer be used.
Copied: branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation
(from rev 245, trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation)
Deleted:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java
===================================================================
---
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -1,133 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.dna.repository.federation;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import java.util.concurrent.TimeUnit;
-import org.jboss.dna.repository.services.ServiceAdministrator;
-import org.jboss.dna.spi.cache.CachePolicy;
-import org.jboss.dna.spi.graph.commands.GraphCommand;
-import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
-import org.jboss.dna.spi.graph.connection.RepositorySourceException;
-import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- */
-public class FederatedRepositoryConnectionTest {
-
- private FederatedRepositoryConnection connection;
- private FederatedRepositorySource source;
- private FederatedRepository repository;
- private String sourceName;
- private CachePolicy defaultCachePolicy;
- private ServiceAdministrator repositoryAdmin;
-
- @Before
- public void beforeEach() throws Exception {
- sourceName = "Source X";
- source = mock(FederatedRepositorySource.class);
- stub(source.getName()).toReturn(sourceName);
- repository = mock(FederatedRepository.class);
- defaultCachePolicy = mock(CachePolicy.class);
- stub(repository.getDefaultCachePolicy()).toReturn(defaultCachePolicy);
- repositoryAdmin = mock(ServiceAdministrator.class);
- stub(repository.getAdministrator()).toReturn(repositoryAdmin);
- connection = new FederatedRepositoryConnection(repository, source);
- }
-
- @Test
- public void shouldHaveSourceAndRepository() {
- assertThat(connection.getRepository(), is(repository));
- assertThat(connection.getRepositorySource(), is(source));
- }
-
- @Test
- public void shouldGetSourceNameFromSource() {
- for (int i = 0; i != 10; ++i) {
- assertThat(connection.getSourceName(), is(sourceName));
- }
- verify(source, times(10)).getName();
- }
-
- @Test
- public void shouldGetDefaultCachePolicyFromRepository() {
- assertThat(connection.getDefaultCachePolicy(),
is(sameInstance(defaultCachePolicy)));
- verify(repository, times(1)).getDefaultCachePolicy();
- }
-
- @Test
- public void shouldHaveNoXaResource() {
- assertThat(connection.getXAResource(), is(nullValue()));
- }
-
- @Test
- public void shouldCheckRepositoryAdminsStartedStateForPingResult() {
- stub(repositoryAdmin.isStarted()).toReturn(true);
- assertThat(connection.ping(1, TimeUnit.SECONDS), is(true));
- verify(repositoryAdmin, times(1)).isStarted();
- }
-
- @Test( expected = RepositorySourceException.class )
- public void shouldFailExecutionIfRepositoryAdminsIsNotStarted() {
- stub(repositoryAdmin.isStarted()).toReturn(false);
- ExecutionEnvironment env = mock(ExecutionEnvironment.class);
- GraphCommand command = mock(GraphCommand.class);
- connection.execute(env, command);
- }
-
- @Test
- public void shouldAddListenerToRepositoryWhenSetOnConnection() {
- // Old listener is no-op, so it is not removed from repository ...
- RepositorySourceListener listener = mock(RepositorySourceListener.class);
- connection.setListener(listener);
- verify(repository, times(1)).addListener(listener);
-
- // Old listener is NOT no-op, so it is removed from repository ...
- RepositorySourceListener listener2 = mock(RepositorySourceListener.class);
- connection.setListener(listener2);
- verify(repository, times(1)).removeListener(listener);
- verify(repository, times(1)).addListener(listener2);
- }
-
- @Test
- public void shouldRemoveListenerFromRepositoryWhenConnectionIsClosed() {
- // Old listener is NOT no-op, so it is removed from repository ...
- RepositorySourceListener listener2 = mock(RepositorySourceListener.class);
- connection.setListener(listener2);
- verify(repository, times(1)).addListener(listener2);
-
- // Closing connection will remove listener ...
- connection.close();
- verify(repository, times(1)).removeListener(listener2);
- }
-
-}
Copied:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java
(from rev 245,
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java)
===================================================================
---
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java
(rev 0)
+++
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,133 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import java.util.concurrent.TimeUnit;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedRepositoryConnectionTest {
+
+ private FederatedRepositoryConnection connection;
+ private FederatedRepositorySource source;
+ private FederatedRepository repository;
+ private String sourceName;
+ private CachePolicy defaultCachePolicy;
+ private ServiceAdministrator repositoryAdmin;
+
+ @Before
+ public void beforeEach() throws Exception {
+ sourceName = "Source X";
+ source = mock(FederatedRepositorySource.class);
+ stub(source.getName()).toReturn(sourceName);
+ repository = mock(FederatedRepository.class);
+ defaultCachePolicy = mock(CachePolicy.class);
+ stub(repository.getDefaultCachePolicy()).toReturn(defaultCachePolicy);
+ repositoryAdmin = mock(ServiceAdministrator.class);
+ stub(repository.getAdministrator()).toReturn(repositoryAdmin);
+ connection = new FederatedRepositoryConnection(repository, source);
+ }
+
+ @Test
+ public void shouldHaveSourceAndRepository() {
+ assertThat(connection.getRepository(), is(repository));
+ assertThat(connection.getRepositorySource(), is(source));
+ }
+
+ @Test
+ public void shouldGetSourceNameFromSource() {
+ for (int i = 0; i != 10; ++i) {
+ assertThat(connection.getSourceName(), is(sourceName));
+ }
+ verify(source, times(10)).getName();
+ }
+
+ @Test
+ public void shouldGetDefaultCachePolicyFromRepository() {
+ assertThat(connection.getDefaultCachePolicy(),
is(sameInstance(defaultCachePolicy)));
+ verify(repository, times(1)).getDefaultCachePolicy();
+ }
+
+ @Test
+ public void shouldHaveNoXaResource() {
+ assertThat(connection.getXAResource(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCheckRepositoryAdminsStartedStateForPingResult() {
+ stub(repositoryAdmin.isStarted()).toReturn(true);
+ assertThat(connection.ping(1, TimeUnit.SECONDS), is(true));
+ verify(repositoryAdmin, times(1)).isStarted();
+ }
+
+ @Test( expected = RepositorySourceException.class )
+ public void shouldFailExecutionIfRepositoryAdminsIsNotStarted() {
+ stub(repositoryAdmin.isStarted()).toReturn(false);
+ ExecutionEnvironment env = mock(ExecutionEnvironment.class);
+ GraphCommand command = mock(GraphCommand.class);
+ connection.execute(env, command);
+ }
+
+ @Test
+ public void shouldAddListenerToRepositoryWhenSetOnConnection() {
+ // Old listener is no-op, so it is not removed from repository ...
+ RepositorySourceListener listener = mock(RepositorySourceListener.class);
+ connection.setListener(listener);
+ verify(repository, times(1)).addListener(listener);
+
+ // Old listener is NOT no-op, so it is removed from repository ...
+ RepositorySourceListener listener2 = mock(RepositorySourceListener.class);
+ connection.setListener(listener2);
+ verify(repository, times(1)).removeListener(listener);
+ verify(repository, times(1)).addListener(listener2);
+ }
+
+ @Test
+ public void shouldRemoveListenerFromRepositoryWhenConnectionIsClosed() {
+ // Old listener is NOT no-op, so it is removed from repository ...
+ RepositorySourceListener listener2 = mock(RepositorySourceListener.class);
+ connection.setListener(listener2);
+ verify(repository, times(1)).addListener(listener2);
+
+ // Closing connection will remove listener ...
+ connection.close();
+ verify(repository, times(1)).removeListener(listener2);
+ }
+
+}
Deleted:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java
===================================================================
---
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -1,218 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.dna.repository.federation;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.RefAddr;
-import javax.naming.Reference;
-import org.jboss.dna.spi.graph.connection.RepositorySourceException;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- */
-public class FederatedRepositorySourceTest {
-
- private FederatedRepositorySource source;
- private FederatedRepositoryConnection connection;
- private FederatedRepository repository;
- private FederationService service;
- private String repositoryName;
- private String username;
- private String credentials;
-
- /**
- * @throws java.lang.Exception
- */
- @Before
- public void beforeEach() throws Exception {
- this.repositoryName = "Test Repository";
- this.service = mock(FederationService.class);
- this.source = new FederatedRepositorySource(service, repositoryName);
- this.repository = mock(FederatedRepository.class);
- this.username = "valid username";
- this.credentials = "valid password";
- this.source.setUsername(username);
- this.source.setCredentials(credentials);
- }
-
- @Test
- public void shouldCreateConnectionsByAuthenticateUsingFederationRepository() throws
Exception {
- stub(repository.authenticate(source.getUsername(),
source.getCredentials())).toReturn(true);
- stub(service.getRepository(source.getRepositoryName())).toReturn(repository);
- connection = (FederatedRepositoryConnection)source.getConnection();
- assertThat(connection, is(notNullValue()));
- assertThat(connection.getRepository(), is(sameInstance(repository)));
- verify(repository, times(1)).authenticate(source.getUsername(),
source.getCredentials());
- verify(service, times(1)).getRepository(source.getRepositoryName());
- }
-
- @Test( expected = RepositorySourceException.class )
- public void shouldNotCreateConnectionWhenAuthenticationFails() throws Exception {
- stub(repository.authenticate(source.getUsername(),
source.getCredentials())).toReturn(false);
- stub(service.getRepository(source.getRepositoryName())).toReturn(repository);
- connection = (FederatedRepositoryConnection)source.getConnection();
- }
-
- @Test
- public void shouldHaveNameSuppliedInConstructor() {
- assertThat(source.getRepositoryName(), is(repositoryName));
- }
-
- @Test
- public void shouldHaveNullSourceNameUponConstruction() {
- assertThat(source.getName(), is(nullValue()));
- }
-
- @Test
- public void shouldAllowSettingName() {
- source.setName("Something");
- assertThat(source.getName(), is("Something"));
- source.setName("another name");
- assertThat(source.getName(), is("another name"));
- }
-
- @Test
- public void shouldAllowSettingNameToNull() {
- source.setName("some name");
- source.setName(null);
- assertThat(source.getName(), is(nullValue()));
- }
-
- @Test
- public void shouldAllowSettingUsername() {
- source.setUsername("Something");
- assertThat(source.getUsername(), is("Something"));
- source.setUsername("another name");
- assertThat(source.getUsername(), is("another name"));
- }
-
- @Test
- public void shouldAllowSettingUsernameToNull() {
- source.setUsername("some name");
- source.setUsername(null);
- assertThat(source.getUsername(), is(nullValue()));
- }
-
- @Test
- public void shouldAllowSettingCredentials() {
- source.setCredentials("Something");
- assertThat(source.getCredentials(), is("Something"));
- source.setCredentials("another name");
- assertThat(source.getCredentials(), is("another name"));
- }
-
- @Test
- public void shouldAllowSettingCredentialsToNull() {
- source.setCredentials("some name");
- source.setCredentials(null);
- assertThat(source.getCredentials(), is(nullValue()));
- }
-
- @Test
- public void shouldHaveDefaultRetryLimit() {
- assertThat(source.getRetryLimit(),
is(FederatedRepositorySource.DEFAULT_RETRY_LIMIT));
- }
-
- @Test
- public void shouldSetRetryLimitToZeroWhenSetWithNonPositiveValue() {
- source.setRetryLimit(0);
- assertThat(source.getRetryLimit(), is(0));
- source.setRetryLimit(-1);
- assertThat(source.getRetryLimit(), is(0));
- source.setRetryLimit(-100);
- assertThat(source.getRetryLimit(), is(0));
- }
-
- @Test
- public void shouldAllowRetryLimitToBeSet() {
- for (int i = 0; i != 100; ++i) {
- source.setRetryLimit(i);
- assertThat(source.getRetryLimit(), is(i));
- }
- }
-
- @Test
- public void shouldCreateJndiReferenceAndRecreatedObjectFromReference() throws
Exception {
- String serviceJndiName = "jndiName";
- stub(service.getJndiName()).toReturn(serviceJndiName);
-
- int retryLimit = 100;
- source.setCredentials(credentials);
- source.setUsername(username);
- source.setRetryLimit(retryLimit);
- source.setName("Some source");
-
- Reference ref = source.getReference();
- assertThat(ref.getClassName(), is(FederatedRepositorySource.class.getName()));
- assertThat(ref.getFactoryClassName(),
is(FederatedRepositorySource.NamingContextObjectFactory.class.getName()));
-
- Map<String, Object> refAttributes = new HashMap<String, Object>();
- Enumeration<RefAddr> enumeration = ref.getAll();
- while (enumeration.hasMoreElements()) {
- RefAddr addr = enumeration.nextElement();
- refAttributes.put(addr.getType(), addr.getContent());
- }
-
- assertThat(refAttributes.remove(FederatedRepositorySource.USERNAME),
is((Object)username));
- assertThat(refAttributes.remove(FederatedRepositorySource.CREDENTIALS),
is((Object)credentials));
- assertThat(refAttributes.remove(FederatedRepositorySource.SOURCE_NAME),
is((Object)source.getName()));
- assertThat(refAttributes.remove(FederatedRepositorySource.REPOSITORY_NAME),
is((Object)repositoryName));
-
assertThat(refAttributes.remove(FederatedRepositorySource.FEDERATION_SERVICE_JNDI_NAME),
is((Object)serviceJndiName));
- assertThat(refAttributes.remove(FederatedRepositorySource.RETRY_LIMIT),
is((Object)Integer.toString(retryLimit)));
- assertThat(refAttributes.isEmpty(), is(true));
-
- // Recreate the object, use a newly constructed source ...
- FederatedRepositorySource.NamingContextObjectFactory factory = new
FederatedRepositorySource.NamingContextObjectFactory();
- Name name = mock(Name.class);
- Context context = mock(Context.class);
- stub(context.lookup(serviceJndiName)).toReturn(service);
- Hashtable<?, ?> env = new Hashtable<Object, Object>();
- FederatedRepositorySource recoveredSource =
(FederatedRepositorySource)factory.getObjectInstance(ref, name, context, env);
- assertThat(recoveredSource, is(notNullValue()));
-
- assertThat(recoveredSource.getName(), is(source.getName()));
- assertThat(recoveredSource.getUsername(), is(source.getUsername()));
- assertThat(recoveredSource.getCredentials(), is(source.getCredentials()));
- assertThat(recoveredSource.getRepositoryName(), is(source.getRepositoryName()));
- assertThat(recoveredSource.getRetryLimit(), is(source.getRetryLimit()));
- assertThat(recoveredSource.getFederationService(), is(service));
-
- assertThat(recoveredSource.equals(source), is(true));
- assertThat(source.equals(recoveredSource), is(true));
- }
-}
Copied:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java
(from rev 245,
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java)
===================================================================
---
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java
(rev 0)
+++
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,218 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedRepositorySourceTest {
+
+ private FederatedRepositorySource source;
+ private FederatedRepositoryConnection connection;
+ private FederatedRepository repository;
+ private FederationService service;
+ private String repositoryName;
+ private String username;
+ private String credentials;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void beforeEach() throws Exception {
+ this.repositoryName = "Test Repository";
+ this.service = mock(FederationService.class);
+ this.source = new FederatedRepositorySource(service, repositoryName);
+ this.repository = mock(FederatedRepository.class);
+ this.username = "valid username";
+ this.credentials = "valid password";
+ this.source.setUsername(username);
+ this.source.setCredentials(credentials);
+ }
+
+ @Test
+ public void shouldCreateConnectionsByAuthenticateUsingFederationRepository() throws
Exception {
+ stub(repository.authenticate(source.getUsername(),
source.getCredentials())).toReturn(true);
+ stub(service.getRepository(source.getRepositoryName())).toReturn(repository);
+ connection = (FederatedRepositoryConnection)source.getConnection();
+ assertThat(connection, is(notNullValue()));
+ assertThat(connection.getRepository(), is(sameInstance(repository)));
+ verify(repository, times(1)).authenticate(source.getUsername(),
source.getCredentials());
+ verify(service, times(1)).getRepository(source.getRepositoryName());
+ }
+
+ @Test( expected = RepositorySourceException.class )
+ public void shouldNotCreateConnectionWhenAuthenticationFails() throws Exception {
+ stub(repository.authenticate(source.getUsername(),
source.getCredentials())).toReturn(false);
+ stub(service.getRepository(source.getRepositoryName())).toReturn(repository);
+ connection = (FederatedRepositoryConnection)source.getConnection();
+ }
+
+ @Test
+ public void shouldHaveNameSuppliedInConstructor() {
+ assertThat(source.getRepositoryName(), is(repositoryName));
+ }
+
+ @Test
+ public void shouldHaveNullSourceNameUponConstruction() {
+ assertThat(source.getName(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowSettingName() {
+ source.setName("Something");
+ assertThat(source.getName(), is("Something"));
+ source.setName("another name");
+ assertThat(source.getName(), is("another name"));
+ }
+
+ @Test
+ public void shouldAllowSettingNameToNull() {
+ source.setName("some name");
+ source.setName(null);
+ assertThat(source.getName(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowSettingUsername() {
+ source.setUsername("Something");
+ assertThat(source.getUsername(), is("Something"));
+ source.setUsername("another name");
+ assertThat(source.getUsername(), is("another name"));
+ }
+
+ @Test
+ public void shouldAllowSettingUsernameToNull() {
+ source.setUsername("some name");
+ source.setUsername(null);
+ assertThat(source.getUsername(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowSettingCredentials() {
+ source.setCredentials("Something");
+ assertThat(source.getCredentials(), is("Something"));
+ source.setCredentials("another name");
+ assertThat(source.getCredentials(), is("another name"));
+ }
+
+ @Test
+ public void shouldAllowSettingCredentialsToNull() {
+ source.setCredentials("some name");
+ source.setCredentials(null);
+ assertThat(source.getCredentials(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldHaveDefaultRetryLimit() {
+ assertThat(source.getRetryLimit(),
is(FederatedRepositorySource.DEFAULT_RETRY_LIMIT));
+ }
+
+ @Test
+ public void shouldSetRetryLimitToZeroWhenSetWithNonPositiveValue() {
+ source.setRetryLimit(0);
+ assertThat(source.getRetryLimit(), is(0));
+ source.setRetryLimit(-1);
+ assertThat(source.getRetryLimit(), is(0));
+ source.setRetryLimit(-100);
+ assertThat(source.getRetryLimit(), is(0));
+ }
+
+ @Test
+ public void shouldAllowRetryLimitToBeSet() {
+ for (int i = 0; i != 100; ++i) {
+ source.setRetryLimit(i);
+ assertThat(source.getRetryLimit(), is(i));
+ }
+ }
+
+ @Test
+ public void shouldCreateJndiReferenceAndRecreatedObjectFromReference() throws
Exception {
+ String serviceJndiName = "jndiName";
+ stub(service.getJndiName()).toReturn(serviceJndiName);
+
+ int retryLimit = 100;
+ source.setCredentials(credentials);
+ source.setUsername(username);
+ source.setRetryLimit(retryLimit);
+ source.setName("Some source");
+
+ Reference ref = source.getReference();
+ assertThat(ref.getClassName(), is(FederatedRepositorySource.class.getName()));
+ assertThat(ref.getFactoryClassName(),
is(FederatedRepositorySource.NamingContextObjectFactory.class.getName()));
+
+ Map<String, Object> refAttributes = new HashMap<String, Object>();
+ Enumeration<RefAddr> enumeration = ref.getAll();
+ while (enumeration.hasMoreElements()) {
+ RefAddr addr = enumeration.nextElement();
+ refAttributes.put(addr.getType(), addr.getContent());
+ }
+
+ assertThat(refAttributes.remove(FederatedRepositorySource.USERNAME),
is((Object)username));
+ assertThat(refAttributes.remove(FederatedRepositorySource.CREDENTIALS),
is((Object)credentials));
+ assertThat(refAttributes.remove(FederatedRepositorySource.SOURCE_NAME),
is((Object)source.getName()));
+ assertThat(refAttributes.remove(FederatedRepositorySource.REPOSITORY_NAME),
is((Object)repositoryName));
+
assertThat(refAttributes.remove(FederatedRepositorySource.FEDERATION_SERVICE_JNDI_NAME),
is((Object)serviceJndiName));
+ assertThat(refAttributes.remove(FederatedRepositorySource.RETRY_LIMIT),
is((Object)Integer.toString(retryLimit)));
+ assertThat(refAttributes.isEmpty(), is(true));
+
+ // Recreate the object, use a newly constructed source ...
+ FederatedRepositorySource.NamingContextObjectFactory factory = new
FederatedRepositorySource.NamingContextObjectFactory();
+ Name name = mock(Name.class);
+ Context context = mock(Context.class);
+ stub(context.lookup(serviceJndiName)).toReturn(service);
+ Hashtable<?, ?> env = new Hashtable<Object, Object>();
+ FederatedRepositorySource recoveredSource =
(FederatedRepositorySource)factory.getObjectInstance(ref, name, context, env);
+ assertThat(recoveredSource, is(notNullValue()));
+
+ assertThat(recoveredSource.getName(), is(source.getName()));
+ assertThat(recoveredSource.getUsername(), is(source.getUsername()));
+ assertThat(recoveredSource.getCredentials(), is(source.getCredentials()));
+ assertThat(recoveredSource.getRepositoryName(), is(source.getRepositoryName()));
+ assertThat(recoveredSource.getRetryLimit(), is(source.getRetryLimit()));
+ assertThat(recoveredSource.getFederationService(), is(service));
+
+ assertThat(recoveredSource.equals(source), is(true));
+ assertThat(source.equals(recoveredSource), is(true));
+ }
+}
Deleted:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java
===================================================================
---
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -1,174 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.dna.repository.federation;
-
-import java.util.concurrent.TimeUnit;
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import org.jboss.dna.spi.graph.connection.RepositoryConnection;
-import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
-import org.jboss.dna.spi.graph.connection.RepositorySource;
-import org.jboss.dna.spi.graph.connection.RepositorySourceException;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- */
-public class FederatedSourceTest {
-
- private RepositoryConnection connection;
- private FederatedSource source;
- private RepositorySource repositorySource;
-
- /**
- * @throws java.lang.Exception
- */
- @Before
- public void beforeEach() throws Exception {
- this.repositorySource = mock(RepositorySource.class);
- this.source = new FederatedSource(this.repositorySource);
- this.connection = mock(RepositoryConnection.class);
- }
-
- @After
- public void afterEach() throws Exception {
- RepositoryConnectionPool pool = source.getConnectionPool();
- pool.shutdown();
- pool.awaitTermination(1, TimeUnit.SECONDS);
- }
-
- @Test
- public void shouldConstructWithNonNullRepositorySource() {
- assertThat(source, is(notNullValue()));
- }
-
- @Test( expected = IllegalArgumentException.class )
- public void shouldFailToConstructWithNullRepositorySource() {
- new FederatedSource(null);
- }
-
- @Test
- public void shouldHaveConnectionPoolAfterConstruction() {
- assertThat(source.getConnectionPool(), is(notNullValue()));
- }
-
- @Test
- public void shouldGetTheNameFromTheRepositorySource() {
- String theName = "My Repository";
- stub(repositorySource.getName()).toReturn(theName);
- assertThat(source.getName(), is(theName));
- verify(repositorySource, times(1)).getName();
-
- // Change the name of the source, and try again ...
- theName = theName + " part deux";
- stub(repositorySource.getName()).toReturn(theName);
- assertThat(source.getName(), is(theName));
- verify(repositorySource, times(2)).getName();
- }
-
- @Test
- public void shouldCheckAvailabilityByCreatingConnectionAndPing() throws Exception {
- // Set up the connection mock to return value from ping, and then
- // set up the source mock to return the connection ...
- stub(this.repositorySource.getConnection()).toReturn(connection);
- stub(connection.ping(1, TimeUnit.SECONDS)).toReturn(true);
- assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(true));
- }
-
- @Test
- public void shouldConsiderSourceToNotBeAvailabilityWhenUnableToPingConnection()
throws Exception {
- // Set up the connection mock to return value from ping, and then
- // set up the source mock to return the connection ...
- stub(this.repositorySource.getConnection()).toReturn(connection);
- stub(connection.ping(1, TimeUnit.SECONDS)).toReturn(false);
- assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
- }
-
- @Test
- public void shouldConsiderSourceToNotBeAvailabilityWhenPingThrowsException() throws
Exception {
- // Set up the connection mock to return value from ping, and then
- // set up the source mock to return the connection ...
- stub(this.repositorySource.getConnection()).toReturn(connection);
- stub(connection.ping(1, TimeUnit.SECONDS)).toThrow(new
NullPointerException("sorry"));
- assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
- }
-
- @Test
- public void
shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsRepositorySourceException()
throws Exception {
- // Set up the connection mock to return value from ping, and then
- // set up the source mock to return the connection ...
- stub(this.repositorySource.getConnection()).toThrow(new
RepositorySourceException("sorry"));
- assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
- }
-
- @Test
- public void
shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsIllegalStateException()
throws Exception {
- stub(this.repositorySource.getConnection()).toThrow(new
IllegalStateException("sorry"));
- assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
- }
-
- @Test
- public void
shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsInterruptedException()
throws Exception {
- stub(this.repositorySource.getConnection()).toThrow(new
InterruptedException("sorry"));
- assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
- }
-
- @Test
- public void
shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsAnyException() throws
Exception {
- stub(this.repositorySource.getConnection()).toThrow(new
NullPointerException("sorry"));
- assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
- }
-
- @Test
- public void shouldConsiderEqualAnyFederatedSourcesWithSameName() {
- RepositorySource repositorySource2 = mock(RepositorySource.class);
- FederatedSource source2 = new FederatedSource(repositorySource2);
-
- String theName = "Some name";
- stub(repositorySource.getName()).toReturn(theName);
- stub(repositorySource2.getName()).toReturn(theName);
- assertThat(source.equals(source2), is(true));
- }
-
- @Test
- public void shouldNotConsiderEqualAnyFederatedSourcesWithDifferentNames() {
- RepositorySource repositorySource2 = mock(RepositorySource.class);
- FederatedSource source2 = new FederatedSource(repositorySource2);
-
- String theName = "Some name";
- stub(repositorySource.getName()).toReturn(theName + " ");
- stub(repositorySource2.getName()).toReturn(theName);
- assertThat(source.equals(source2), is(false));
-
- stub(repositorySource.getName()).toReturn(theName.toLowerCase());
- stub(repositorySource2.getName()).toReturn(theName.toUpperCase());
- assertThat(source.equals(source2), is(false));
- }
-
-}
Copied:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java
(from rev 245,
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java)
===================================================================
---
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java
(rev 0)
+++
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,174 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import java.util.concurrent.TimeUnit;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedSourceTest {
+
+ private RepositoryConnection connection;
+ private FederatedSource source;
+ private RepositorySource repositorySource;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void beforeEach() throws Exception {
+ this.repositorySource = mock(RepositorySource.class);
+ this.source = new FederatedSource(this.repositorySource);
+ this.connection = mock(RepositoryConnection.class);
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ RepositoryConnectionPool pool = source.getConnectionPool();
+ pool.shutdown();
+ pool.awaitTermination(1, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void shouldConstructWithNonNullRepositorySource() {
+ assertThat(source, is(notNullValue()));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToConstructWithNullRepositorySource() {
+ new FederatedSource(null);
+ }
+
+ @Test
+ public void shouldHaveConnectionPoolAfterConstruction() {
+ assertThat(source.getConnectionPool(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldGetTheNameFromTheRepositorySource() {
+ String theName = "My Repository";
+ stub(repositorySource.getName()).toReturn(theName);
+ assertThat(source.getName(), is(theName));
+ verify(repositorySource, times(1)).getName();
+
+ // Change the name of the source, and try again ...
+ theName = theName + " part deux";
+ stub(repositorySource.getName()).toReturn(theName);
+ assertThat(source.getName(), is(theName));
+ verify(repositorySource, times(2)).getName();
+ }
+
+ @Test
+ public void shouldCheckAvailabilityByCreatingConnectionAndPing() throws Exception {
+ // Set up the connection mock to return value from ping, and then
+ // set up the source mock to return the connection ...
+ stub(this.repositorySource.getConnection()).toReturn(connection);
+ stub(connection.ping(1, TimeUnit.SECONDS)).toReturn(true);
+ assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(true));
+ }
+
+ @Test
+ public void shouldConsiderSourceToNotBeAvailabilityWhenUnableToPingConnection()
throws Exception {
+ // Set up the connection mock to return value from ping, and then
+ // set up the source mock to return the connection ...
+ stub(this.repositorySource.getConnection()).toReturn(connection);
+ stub(connection.ping(1, TimeUnit.SECONDS)).toReturn(false);
+ assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+ }
+
+ @Test
+ public void shouldConsiderSourceToNotBeAvailabilityWhenPingThrowsException() throws
Exception {
+ // Set up the connection mock to return value from ping, and then
+ // set up the source mock to return the connection ...
+ stub(this.repositorySource.getConnection()).toReturn(connection);
+ stub(connection.ping(1, TimeUnit.SECONDS)).toThrow(new
NullPointerException("sorry"));
+ assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+ }
+
+ @Test
+ public void
shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsRepositorySourceException()
throws Exception {
+ // Set up the connection mock to return value from ping, and then
+ // set up the source mock to return the connection ...
+ stub(this.repositorySource.getConnection()).toThrow(new
RepositorySourceException("sorry"));
+ assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+ }
+
+ @Test
+ public void
shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsIllegalStateException()
throws Exception {
+ stub(this.repositorySource.getConnection()).toThrow(new
IllegalStateException("sorry"));
+ assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+ }
+
+ @Test
+ public void
shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsInterruptedException()
throws Exception {
+ stub(this.repositorySource.getConnection()).toThrow(new
InterruptedException("sorry"));
+ assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+ }
+
+ @Test
+ public void
shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsAnyException() throws
Exception {
+ stub(this.repositorySource.getConnection()).toThrow(new
NullPointerException("sorry"));
+ assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+ }
+
+ @Test
+ public void shouldConsiderEqualAnyFederatedSourcesWithSameName() {
+ RepositorySource repositorySource2 = mock(RepositorySource.class);
+ FederatedSource source2 = new FederatedSource(repositorySource2);
+
+ String theName = "Some name";
+ stub(repositorySource.getName()).toReturn(theName);
+ stub(repositorySource2.getName()).toReturn(theName);
+ assertThat(source.equals(source2), is(true));
+ }
+
+ @Test
+ public void shouldNotConsiderEqualAnyFederatedSourcesWithDifferentNames() {
+ RepositorySource repositorySource2 = mock(RepositorySource.class);
+ FederatedSource source2 = new FederatedSource(repositorySource2);
+
+ String theName = "Some name";
+ stub(repositorySource.getName()).toReturn(theName + " ");
+ stub(repositorySource2.getName()).toReturn(theName);
+ assertThat(source.equals(source2), is(false));
+
+ stub(repositorySource.getName()).toReturn(theName.toLowerCase());
+ stub(repositorySource2.getName()).toReturn(theName.toUpperCase());
+ assertThat(source.equals(source2), is(false));
+ }
+
+}
Copied:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml (from
rev 245, trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml)
Deleted:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java
===================================================================
---
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -1,213 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.dna.repository.sequencers.xml;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsInstanceOf.instanceOf;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.junit.Assert.assertThat;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import org.jboss.dna.common.monitor.ProgressMonitor;
-import org.jboss.dna.common.monitor.SimpleProgressMonitor;
-import org.jboss.dna.spi.graph.Name;
-import org.jboss.dna.spi.graph.NameFactory;
-import org.jboss.dna.spi.graph.Path;
-import org.jboss.dna.spi.sequencers.MockSequencerOutput;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author John Verhaeg
- */
-public class XmlSequencerTest {
-
- private XmlSequencer sequencer;
- private InputStream stream;
- private MockSequencerOutput output;
- private ProgressMonitor monitor;
- private URL xml1;
- private URL xml2;
- private URL xml3;
- private URL xml4;
- private URL xsd;
-
- @Before
- public void beforeEach() throws Exception {
- sequencer = new XmlSequencer();
- output = new MockSequencerOutput() {
-
- @Override
- public void setProperty( Path nodePath,
- Name propertyName,
- Object... values ) {
- super.setProperty(nodePath, propertyName, values);
- // System.out.println(nodePath + "." + propertyName + " = " +
Arrays.asList(values));
- }
- };
- monitor = new SimpleProgressMonitor("Test activity");
- xml1 =
this.getClass().getClassLoader().getResource("jackrabbitInMemoryTestRepositoryConfig.xml");
- assertThat(xml1, is(notNullValue()));
- xml2 = this.getClass().getClassLoader().getResource("master.xml");
- assertThat(xml2, is(notNullValue()));
- xml3 =
this.getClass().getClassLoader().getResource("CurrencyFormatterExample.mxml");
- assertThat(xml3, is(notNullValue()));
- xml4 = this.getClass().getClassLoader().getResource("plugin.xml");
- assertThat(xml4, is(notNullValue()));
- xsd = this.getClass().getClassLoader().getResource("Descriptor.1.0.xsd");
- assertThat(xsd, is(notNullValue()));
- }
-
- @After
- public void afterEach() throws Exception {
- if (stream != null) {
- try {
- stream.close();
- } finally {
- stream = null;
- }
- }
- }
-
- @Test
- public void shouldSequenceXml() throws IOException {
- verifyDocument(xml1);
- verifyName(XmlSequencer.COMMENT + "[1]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.COMMENT);
- String text = verify(XmlSequencer.COMMENT + "[1]",
XmlSequencer.COMMENT_CONTENT, String.class);
- assertThat(text.startsWith("\n Licensed to the Apache Software Foundation
(ASF)"), is(true));
- assertThat(text.endsWith(" limitations under the License.\n"), is(true));
- verifyString("", XmlSequencer.DTD_NAME, "Repository");
- verifyString("", XmlSequencer.DTD_PUBLIC_ID, "-//The Apache Software
Foundation//DTD Jackrabbit 1.2//EN");
- verifyString("", XmlSequencer.DTD_SYSTEM_ID,
"http://jackrabbit.apache.org/dtd/repository-1.2.dtd");
- verifyName(XmlSequencer.COMMENT + "[2]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.COMMENT);
- verifyString(XmlSequencer.COMMENT + "[2]", XmlSequencer.COMMENT_CONTENT,
" Example Repository Configuration File ");
- verifyName("Repository[1]", NameFactory.JCR_PRIMARY_TYPE,
"Repository");
- verifyName("Repository[1]/" + XmlSequencer.COMMENT + "[1]",
NameFactory.JCR_PRIMARY_TYPE, XmlSequencer.COMMENT);
- }
-
- @Test
- public void shouldHandleNamespaces() throws IOException {
- verifyDocument(xml2);
- verifyName("book[1]/bookinfo[1]/xi:include[1]", NameFactory.JCR_PRIMARY_TYPE,
"xi:include");
- verifyString("book[1]/bookinfo[1]/xi:include[1]", "xi:href",
"Author_Group.xml");
- verifyName("book[1]/bookinfo[1]/xi:include[2]", NameFactory.JCR_PRIMARY_TYPE,
"xi:include");
- verifyString("book[1]/bookinfo[1]/xi:include[2]", "xi:href",
"Legal_Notice.xml");
- }
-
- @Test
- public void shouldSequenceEntityDeclarations() throws IOException {
- verifyDocument(xml2);
- verifyName(XmlSequencer.ENTITY + "[1]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.ENTITY);
- verifyString(XmlSequencer.ENTITY + "[1]", XmlSequencer.DTD_NAME,
"%RH-ENTITIES");
- verifyString(XmlSequencer.ENTITY + "[1]", XmlSequencer.DTD_SYSTEM_ID,
"Common_Config/rh-entities.ent");
- verifyName(XmlSequencer.ENTITY + "[2]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.ENTITY);
- verifyString(XmlSequencer.ENTITY + "[2]", XmlSequencer.DTD_NAME,
"versionNumber");
- verifyString(XmlSequencer.ENTITY + "[2]", XmlSequencer.DTD_VALUE,
"0.1");
- verifyName(XmlSequencer.ENTITY + "[3]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.ENTITY);
- verifyString(XmlSequencer.ENTITY + "[3]", XmlSequencer.DTD_NAME,
"copyrightYear");
- verifyString(XmlSequencer.ENTITY + "[3]", XmlSequencer.DTD_VALUE,
"2008");
- }
-
- @Test
- public void shouldSequenceElementContent() throws IOException {
- verifyDocument(xml2);
- verifyString("book[1]/chapter[4]/sect1[1]/para[8]/" +
XmlSequencer.ELEMENT_CONTENT + "[1]",
- XmlSequencer.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]/" +
XmlSequencer.ELEMENT_CONTENT + "[1]",
- XmlSequencer.ELEMENT_CONTENT,
- "/a/b/c@title => /d/e/f");
- }
-
- @Test
- public void shouldSequenceCData() throws IOException {
- verifyDocument(xml3);
- verifyString("mx:Application[1]/mx:Script[1]/" + XmlSequencer.CDATA +
"[1]",
- XmlSequencer.CDATA_CONTENT,
- "\n\n" + " import
mx.events.ValidationResultEvent;\t\t\t\n"
- + " private var vResult:ValidationResultEvent;\n" +
"\t\t\t\n"
- + " // Event handler to validate and format
input.\n"
- + " private function Format():void {\n" + "
\n"
- + " vResult = numVal.validate();\n\n"
- + " if (vResult.type==ValidationResultEvent.VALID) {\n"
- + " var temp:Number=Number(priceUS.text);
\n"
- + " formattedUSPrice.text=
usdFormatter.format(temp);\n" + " }\n"
- + " \n" + " else
{\n"
- + "
formattedUSPrice.text=\"\";\n" + " }\n" +
" }\n"
- + " ");
- }
-
- @Test
- public void shouldSequenceProcessingInstructions() throws IOException {
- verifyDocument(xml4);
- verifyName(XmlSequencer.PI + "[1]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.PI);
- verifyString(XmlSequencer.PI + "[1]", XmlSequencer.TARGET,
"eclipse");
- verifyString(XmlSequencer.PI + "[1]", XmlSequencer.PI_CONTENT,
"version=\"3.0\"");
- }
-
- @Test
- public void shouldSequenceXsds() throws IOException {
- verifyDocument(xsd);
- verifyName("xs:schema[1]", NameFactory.JCR_PRIMARY_TYPE,
"xs:schema");
- verifyString("xs:schema[1]", "xs:targetNamespace",
"http://ns.adobe.com/air/application/1.0");
- verifyString("xs:schema[1]", "xs:elementFormDefault",
"qualified");
- verifyName("xs:schema[1]/xs:element[1]", NameFactory.JCR_PRIMARY_TYPE,
"xs:element");
- verifyString("xs:schema[1]/xs:element[1]", "xs:name",
"application");
- }
-
- private <T> T verify( String nodePath,
- String property,
- Class<T> expectedClass ) {
- Object[] values = output.getPropertyValues(nodePath.length() == 0 ? "." :
"./" + nodePath, property);
- assertThat(values, notNullValue());
- assertThat(values.length, is(1));
- Object value = values[0];
- assertThat(value, instanceOf(expectedClass));
- return expectedClass.cast(value);
- }
-
- private void verifyDocument( URL url ) throws IOException {
- stream = url.openStream();
- assertThat(stream, is(notNullValue()));
- sequencer.sequence(stream, output, monitor);
- verifyName("", NameFactory.JCR_PRIMARY_TYPE, XmlSequencer.DOCUMENT);
- }
-
- private void verifyName( String nodePath,
- String property,
- String expectedName ) {
- Name name = verify(nodePath, property, Name.class);
- assertThat(name, is(output.getFactories().getNameFactory().create(expectedName)));
- }
-
- private void verifyString( String nodePath,
- String property,
- String expectedString ) {
- String string = verify(nodePath, property, String.class);
- assertThat(string, is(expectedString));
- }
-}
Copied:
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java
(from rev 245,
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java)
===================================================================
---
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java
(rev 0)
+++
branches/maeste/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/xml/XmlSequencerTest.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,213 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.repository.sequencers.xml;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertThat;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+import org.jboss.dna.common.monitor.SimpleProgressMonitor;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.sequencers.MockSequencerOutput;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author John Verhaeg
+ */
+public class XmlSequencerTest {
+
+ private XmlSequencer sequencer;
+ private InputStream stream;
+ private MockSequencerOutput output;
+ private ProgressMonitor monitor;
+ private URL xml1;
+ private URL xml2;
+ private URL xml3;
+ private URL xml4;
+ private URL xsd;
+
+ @Before
+ public void beforeEach() throws Exception {
+ sequencer = new XmlSequencer();
+ output = new MockSequencerOutput() {
+
+ @Override
+ public void setProperty( Path nodePath,
+ Name propertyName,
+ Object... values ) {
+ super.setProperty(nodePath, propertyName, values);
+ // System.out.println(nodePath + "." + propertyName + " = " +
Arrays.asList(values));
+ }
+ };
+ monitor = new SimpleProgressMonitor("Test activity");
+ xml1 =
this.getClass().getClassLoader().getResource("jackrabbitInMemoryTestRepositoryConfig.xml");
+ assertThat(xml1, is(notNullValue()));
+ xml2 = this.getClass().getClassLoader().getResource("master.xml");
+ assertThat(xml2, is(notNullValue()));
+ xml3 =
this.getClass().getClassLoader().getResource("CurrencyFormatterExample.mxml");
+ assertThat(xml3, is(notNullValue()));
+ xml4 = this.getClass().getClassLoader().getResource("plugin.xml");
+ assertThat(xml4, is(notNullValue()));
+ xsd = this.getClass().getClassLoader().getResource("Descriptor.1.0.xsd");
+ assertThat(xsd, is(notNullValue()));
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ if (stream != null) {
+ try {
+ stream.close();
+ } finally {
+ stream = null;
+ }
+ }
+ }
+
+ @Test
+ public void shouldSequenceXml() throws IOException {
+ verifyDocument(xml1);
+ verifyName(XmlSequencer.COMMENT + "[1]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.COMMENT);
+ String text = verify(XmlSequencer.COMMENT + "[1]",
XmlSequencer.COMMENT_CONTENT, String.class);
+ assertThat(text.startsWith("\n Licensed to the Apache Software Foundation
(ASF)"), is(true));
+ assertThat(text.endsWith(" limitations under the License.\n"), is(true));
+ verifyString("", XmlSequencer.DTD_NAME, "Repository");
+ verifyString("", XmlSequencer.DTD_PUBLIC_ID, "-//The Apache Software
Foundation//DTD Jackrabbit 1.2//EN");
+ verifyString("", XmlSequencer.DTD_SYSTEM_ID,
"http://jackrabbit.apache.org/dtd/repository-1.2.dtd");
+ verifyName(XmlSequencer.COMMENT + "[2]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.COMMENT);
+ verifyString(XmlSequencer.COMMENT + "[2]", XmlSequencer.COMMENT_CONTENT,
" Example Repository Configuration File ");
+ verifyName("Repository[1]", NameFactory.JCR_PRIMARY_TYPE,
"Repository");
+ verifyName("Repository[1]/" + XmlSequencer.COMMENT + "[1]",
NameFactory.JCR_PRIMARY_TYPE, XmlSequencer.COMMENT);
+ }
+
+ @Test
+ public void shouldHandleNamespaces() throws IOException {
+ verifyDocument(xml2);
+ verifyName("book[1]/bookinfo[1]/xi:include[1]", NameFactory.JCR_PRIMARY_TYPE,
"xi:include");
+ verifyString("book[1]/bookinfo[1]/xi:include[1]", "xi:href",
"Author_Group.xml");
+ verifyName("book[1]/bookinfo[1]/xi:include[2]", NameFactory.JCR_PRIMARY_TYPE,
"xi:include");
+ verifyString("book[1]/bookinfo[1]/xi:include[2]", "xi:href",
"Legal_Notice.xml");
+ }
+
+ @Test
+ public void shouldSequenceEntityDeclarations() throws IOException {
+ verifyDocument(xml2);
+ verifyName(XmlSequencer.ENTITY + "[1]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.ENTITY);
+ verifyString(XmlSequencer.ENTITY + "[1]", XmlSequencer.DTD_NAME,
"%RH-ENTITIES");
+ verifyString(XmlSequencer.ENTITY + "[1]", XmlSequencer.DTD_SYSTEM_ID,
"Common_Config/rh-entities.ent");
+ verifyName(XmlSequencer.ENTITY + "[2]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.ENTITY);
+ verifyString(XmlSequencer.ENTITY + "[2]", XmlSequencer.DTD_NAME,
"versionNumber");
+ verifyString(XmlSequencer.ENTITY + "[2]", XmlSequencer.DTD_VALUE,
"0.1");
+ verifyName(XmlSequencer.ENTITY + "[3]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.ENTITY);
+ verifyString(XmlSequencer.ENTITY + "[3]", XmlSequencer.DTD_NAME,
"copyrightYear");
+ verifyString(XmlSequencer.ENTITY + "[3]", XmlSequencer.DTD_VALUE,
"2008");
+ }
+
+ @Test
+ public void shouldSequenceElementContent() throws IOException {
+ verifyDocument(xml2);
+ verifyString("book[1]/chapter[4]/sect1[1]/para[8]/" +
XmlSequencer.ELEMENT_CONTENT + "[1]",
+ XmlSequencer.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]/" +
XmlSequencer.ELEMENT_CONTENT + "[1]",
+ XmlSequencer.ELEMENT_CONTENT,
+ "/a/b/c@title => /d/e/f");
+ }
+
+ @Test
+ public void shouldSequenceCData() throws IOException {
+ verifyDocument(xml3);
+ verifyString("mx:Application[1]/mx:Script[1]/" + XmlSequencer.CDATA +
"[1]",
+ XmlSequencer.CDATA_CONTENT,
+ "\n\n" + " import
mx.events.ValidationResultEvent;\t\t\t\n"
+ + " private var vResult:ValidationResultEvent;\n" +
"\t\t\t\n"
+ + " // Event handler to validate and format
input.\n"
+ + " private function Format():void {\n" + "
\n"
+ + " vResult = numVal.validate();\n\n"
+ + " if (vResult.type==ValidationResultEvent.VALID) {\n"
+ + " var temp:Number=Number(priceUS.text);
\n"
+ + " formattedUSPrice.text=
usdFormatter.format(temp);\n" + " }\n"
+ + " \n" + " else
{\n"
+ + "
formattedUSPrice.text=\"\";\n" + " }\n" +
" }\n"
+ + " ");
+ }
+
+ @Test
+ public void shouldSequenceProcessingInstructions() throws IOException {
+ verifyDocument(xml4);
+ verifyName(XmlSequencer.PI + "[1]", NameFactory.JCR_PRIMARY_TYPE,
XmlSequencer.PI);
+ verifyString(XmlSequencer.PI + "[1]", XmlSequencer.TARGET,
"eclipse");
+ verifyString(XmlSequencer.PI + "[1]", XmlSequencer.PI_CONTENT,
"version=\"3.0\"");
+ }
+
+ @Test
+ public void shouldSequenceXsds() throws IOException {
+ verifyDocument(xsd);
+ verifyName("xs:schema[1]", NameFactory.JCR_PRIMARY_TYPE,
"xs:schema");
+ verifyString("xs:schema[1]", "xs:targetNamespace",
"http://ns.adobe.com/air/application/1.0");
+ verifyString("xs:schema[1]", "xs:elementFormDefault",
"qualified");
+ verifyName("xs:schema[1]/xs:element[1]", NameFactory.JCR_PRIMARY_TYPE,
"xs:element");
+ verifyString("xs:schema[1]/xs:element[1]", "xs:name",
"application");
+ }
+
+ private <T> T verify( String nodePath,
+ String property,
+ Class<T> expectedClass ) {
+ Object[] values = output.getPropertyValues(nodePath.length() == 0 ? "." :
"./" + nodePath, property);
+ assertThat(values, notNullValue());
+ assertThat(values.length, is(1));
+ Object value = values[0];
+ assertThat(value, instanceOf(expectedClass));
+ return expectedClass.cast(value);
+ }
+
+ private void verifyDocument( URL url ) throws IOException {
+ stream = url.openStream();
+ assertThat(stream, is(notNullValue()));
+ sequencer.sequence(stream, output, monitor);
+ verifyName("", NameFactory.JCR_PRIMARY_TYPE, XmlSequencer.DOCUMENT);
+ }
+
+ private void verifyName( String nodePath,
+ String property,
+ String expectedName ) {
+ Name name = verify(nodePath, property, Name.class);
+ assertThat(name, is(output.getFactories().getNameFactory().create(expectedName)));
+ }
+
+ private void verifyString( String nodePath,
+ String property,
+ String expectedString ) {
+ String string = verify(nodePath, property, String.class);
+ assertThat(string, is(expectedString));
+ }
+}
Copied: branches/maeste/dna-repository/src/test/resources/CurrencyFormatterExample.mxml
(from rev 245, trunk/dna-repository/src/test/resources/CurrencyFormatterExample.mxml)
===================================================================
--- branches/maeste/dna-repository/src/test/resources/CurrencyFormatterExample.mxml
(rev 0)
+++
branches/maeste/dna-repository/src/test/resources/CurrencyFormatterExample.mxml 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Simple example to demonstrate the CurrencyFormatter. -->
+<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml">
+
+ <mx:Script>
+ <![CDATA[
+
+ import mx.events.ValidationResultEvent;
+ private var vResult:ValidationResultEvent;
+
+ // Event handler to validate and format input.
+ private function Format():void {
+
+ vResult = numVal.validate();
+
+ if (vResult.type==ValidationResultEvent.VALID) {
+ var temp:Number=Number(priceUS.text);
+ formattedUSPrice.text= usdFormatter.format(temp);
+ }
+
+ else {
+ formattedUSPrice.text="";
+ }
+ }
+ ]]>
+ </mx:Script>
+
+ <mx:CurrencyFormatter id="usdFormatter" precision="2"
+ currencySymbol="$" decimalSeparatorFrom="."
+ decimalSeparatorTo="." useNegativeSign="true"
+ useThousandsSeparator="true" alignSymbol="left"/>
+
+ <mx:NumberValidator id="numVal" source="{priceUS}"
property="text"
+ allowNegative="true" domain="real"/>
+
+ <mx:Panel title="CurrencyFormatter Example" width="75%"
height="75%"
+ paddingTop="10" paddingLeft="10" paddingRight="10"
paddingBottom="10">
+
+ <mx:Form>
+ <mx:FormItem label="Enter U.S. dollar amount:">
+ <mx:TextInput id="priceUS" text=""
width="50%"/>
+ </mx:FormItem>
+
+ <mx:FormItem label="Formatted amount: ">
+ <mx:TextInput id="formattedUSPrice" text=""
width="50%" editable="false"/>
+ </mx:FormItem>
+
+ <mx:FormItem>
+ <mx:Button label="Validate and Format"
click="Format();"/>
+ </mx:FormItem>
+ </mx:Form>
+
+ </mx:Panel>
+</mx:Application>
Copied: branches/maeste/dna-repository/src/test/resources/Descriptor.1.0.xsd (from rev
245, trunk/dna-repository/src/test/resources/Descriptor.1.0.xsd)
===================================================================
--- branches/maeste/dna-repository/src/test/resources/Descriptor.1.0.xsd
(rev 0)
+++ branches/maeste/dna-repository/src/test/resources/Descriptor.1.0.xsd 2008-06-07
12:28:47 UTC (rev 246)
@@ -0,0 +1,127 @@
+<?xml version="1.0"?>
+<xs:schema
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
+
targetNamespace="http://ns.adobe.com/air/application/1.0"
+
xmlns="http://ns.adobe.com/air/application/1.0"
+ elementFormDefault="qualified"
+>
+ <xs:element name="application">
+ <xs:complexType>
+ <xs:all>
+ <!-- About this application -->
+ <xs:element name="id">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Za-z0-9\-\.]{1,212}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="name" type="xs:string"
minOccurs="0"/>
+ <xs:element name="version" type="xs:string"/>
+ <xs:element name="filename">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <!-- name cannot begin with a ' ' (space), have any of these
characters: *"/:<>?\|, and end with a . (dot) or ' ' (space) -->
+ <xs:pattern value='[^\*"/:><\?\\\|\.
]|[^\*"/:><\?\\\|
][^\*"/:><\?\\\|]*[^\*"/:><\?\\\|\. ]'/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="description" type="xs:string"
minOccurs="0"/>
+ <xs:element name="copyright" type="xs:string"
minOccurs="0"/>
+ <xs:element name="icon" type="IconType"
minOccurs="0"/>
+
+ <!-- How to start this application -->
+ <xs:element name="initialWindow">
+ <xs:complexType>
+ <xs:all>
+ <xs:element name="content" type="xs:anyURI"
minOccurs="1" />
+ <xs:element name="title" type="xs:string"
minOccurs="0" />
+
+ <xs:element name="systemChrome" minOccurs="0" >
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="none"/>
+ <xs:enumeration value="standard"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="transparent" type="xs:boolean"
minOccurs="0" />
+ <xs:element name="visible" type="xs:boolean"
minOccurs="0" />
+
+ <xs:element name="minimizable" type="xs:boolean"
minOccurs="0" />
+ <xs:element name="maximizable" type="xs:boolean"
minOccurs="0" />
+ <xs:element name="resizable" type="xs:boolean"
minOccurs="0" />
+
+ <xs:element name="x" type="xs:int"
minOccurs="0" />
+ <xs:element name="y" type="xs:int"
minOccurs="0" />
+ <xs:element name="width" type="xs:unsignedInt"
minOccurs="0" />
+ <xs:element name="height" type="xs:unsignedInt"
minOccurs="0" />
+ <xs:element name="minSize" type="BoundsSizeType"
minOccurs="0" />
+ <xs:element name="maxSize" type="BoundsSizeType"
minOccurs="0" />
+ </xs:all>
+ </xs:complexType>
+ </xs:element>
+
+ <!-- About installing this application -->
+ <xs:element name="installFolder" minOccurs="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <!-- installFolder cannot begin with a / (forward-slash) or a '
' (space), have any of these characters: *":<>?\|, and end with a . (dot)
or ' ' (space) -->
+ <xs:pattern value='[^\*"/:><\?\\\|\.
]|[^\*"/:><\?\\\|
][^\*":><\?\\\|]*[^\*":><\?\\\|\. ]'/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="programMenuFolder" minOccurs="0">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <!-- programMenuFolder cannot begin with a / (forward-slash) or a '
' (space), have any of these characters: *":<>?\|, and end with a . (dot)
or ' ' (space) -->
+ <xs:pattern value='[^\*"/:><\?\\\|\.
]|[^\*"/:><\?\\\|
][^\*":><\?\\\|]*[^\*":><\?\\\|\. ]'/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+
+ <!-- Features this application can opt in to -->
+ <xs:element name="customUpdateUI" type="xs:boolean"
minOccurs="0"/>
+ <xs:element name="allowBrowserInvocation"
type="xs:boolean" minOccurs="0"/>
+ <xs:element name="fileTypes" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="fileType" minOccurs="0"
maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:all>
+ <xs:element name="name" type="xs:string"/>
+ <xs:element name="extension"
type="xs:string"/>
+ <xs:element name="description" type="xs:string"
minOccurs="0"/>
+ <xs:element name="contentType" type="xs:string"
minOccurs="0"/>
+ <xs:element name="icon" type="IconType"
minOccurs="0"/>
+ </xs:all>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:all>
+
+ <!-- About the runtime version required -->
+ <xs:attribute name="minimumPatchLevel"
type="xs:unsignedInt"/>
+ </xs:complexType>
+ </xs:element>
+
+ <!-- Type definitions -->
+ <xs:complexType name="IconType">
+ <xs:all>
+ <xs:element name="image16x16" type="xs:anyURI"
minOccurs="0"/>
+ <xs:element name="image32x32" type="xs:anyURI"
minOccurs="0"/>
+ <xs:element name="image48x48" type="xs:anyURI"
minOccurs="0"/>
+ <xs:element name="image128x128" type="xs:anyURI"
minOccurs="0"/>
+ </xs:all>
+ </xs:complexType>
+ <xs:simpleType name="UnsignedIntListType">
+ <xs:list itemType="xs:unsignedInt"/>
+ </xs:simpleType>
+ <xs:simpleType name="BoundsSizeType">
+ <xs:restriction base="UnsignedIntListType">
+ <xs:length value="2"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
Copied: branches/maeste/dna-repository/src/test/resources/master.xml (from rev 245,
trunk/dna-repository/src/test/resources/master.xml)
===================================================================
--- branches/maeste/dna-repository/src/test/resources/master.xml
(rev 0)
+++ branches/maeste/dna-repository/src/test/resources/master.xml 2008-06-07 12:28:47 UTC
(rev 246)
@@ -0,0 +1,1890 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+<!ENTITY % RH-ENTITIES SYSTEM "Common_Config/rh-entities.ent">
+<!ENTITY versionNumber "0.1">
+<!ENTITY copyrightYear "2008">
+<!ENTITY copyrightHolder "Red Hat Middleware, LLC.">]>
+<book>
+ <bookinfo>
+ <title>JBoss DNA</title>
+ <subtitle>Getting Started Guide</subtitle>
+ <releaseinfo>&versionNumber;
+ </releaseinfo>
+ <productnumber>&versionNumber;
+ </productnumber>
+ <issuenum>1</issuenum>
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/dna-logo.png" align="center"
/>
+ </imageobject>
+ <imageobject role="pdf">
+ <imagedata fileref="images/dna-logo.png" scale="75"
align="center" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="images/dna-logo.png" depth="3cm"
/>
+ </imageobject>
+ <imageobject role="xhtml">
+ <imagedata fileref="images/dna-logo.png" depth="3cm"
/>
+ </imageobject>
+ <imageobject role="xhtml_single">
+ <imagedata fileref="images/dna-logo.png" depth="3cm"
/>
+ </imageobject>
+ </mediaobject>
+ <xi:include
xmlns:xi="http://www.w3.org/2001/XInclude"
href="Author_Group.xml" />
+ <xi:include
xmlns:xi="http://www.w3.org/2001/XInclude"
href="Legal_Notice.xml" />
+ </bookinfo>
+ <preface id="preface" revision="1">
+ <title>What this book covers</title>
+ <para>The goal of this book is to help you learn about JBoss DNA and how you
can use it in your own applications to get the
+ most out of your JCR repositories.</para>
+ <para>The first part of the book starts out with an introduction to content
repositories and an overview of the JCR API,
+ both of which are important aspects of JBoss DNA. This is followed by an overview
of the JBoss DNA project, its
+ architecture, and a basic roadmap for what's coming next.</para>
+ <para>The next part of the book covers how to download and build the examples,
how to use JBoss DNA with existing
+ repositories, and how to build and use custom sequencers.</para>
+ <para>
+ If you have any questions or comments, please feel free to contact JBoss DNA's
+ <ulink url="mailto:dna-users@jboss.org">user mailing
list</ulink>
+ or use the
+ <ulink
url="http://www.jboss.com/index.html?module=bb&op=viewforum&...
forums</ulink>
+ . If you'd like to get involved on the project, join the
+ <ulink
url="http://www.jboss.org/dna/lists.html">mailing
lists</ulink>
+ ,
+ <ulink
url="http://www.jboss.org/dna/subversion.html">download the
code</ulink>
+ and get it building, and visit our
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA">JIRA issue
management system</ulink>
+ . If there's something in particular you're interested in, talk with the
community - there may be others interested in the
+ same thing.
+ </para>
+ </preface>
+ <chapter id="introduction">
+ <title>Introduction</title>
+ <para>There are a lot of choices for how applications can store information
persistently so that it can be accessed at a
+ later time and by other processes. The challenge developers face is how to use an
approach that most closely matches the
+ needs of their application. This choice becomes more important as developers choose
to focus their efforts on
+ application-specific logic, delegating much of the responsibilities for persistence
to libraries and frameworks.</para>
+ <para>
+ Perhaps one of the easiest techniques is to simply store information in
+ <emphasis>files</emphasis>
+ . The Java language makes working with files relatively easy, but Java really
doesn't provide many bells and whistles. So
+ using files is an easy choice when the information is either not complicated (for
example property files), or when users may
+ need to read or change the information outside of the application (for example log
files or configuration files). But using
+ files to persist information becomes more difficult as the information becomes more
complex, as the volume of it increases,
+ or if it needs to be accessed by multiple processes. For these situations, other
techniques often offer better choices.
+ </para>
+ <para>
+ Another technique built into the Java language is
+ <emphasis>Java serialization</emphasis>
+ , which is capable of persisting the state of an object graph so that it can be
read back in at a later time. However, Java
+ serialization can quickly become tricky if the classes are changed, and so it's
beneficial usually when the information is
+ persisted for a very short period of time. For example, serialization is sometimes
used to send an object graph from one
+ process to another.
+ </para>
+ <para>
+ One of the more popular persistence technologies is the
+ <emphasis>relational database</emphasis>
+ . Relational database management systems have been around for decades and are very
capable. The Java Database Connectivity
+ (JDBC) API provides a standard interface for connecting to and interacting with
relational databases. However, it is a
+ low-level API that requires a lot of code to use correctly, and it still
doesn't abstract away the DBMS-specific SQL
+ grammar. Also, working with relational data in an object-oriented language can feel
somewhat unnatural, so many developers
+ map this data to classes that fit much more cleanly into their application. The
problem is that manually creating this
+ mapping layer requires a lot of repetitive and non-trivial JDBC code.
+ </para>
+ <para>
+ <emphasis>Object-relational mapping</emphasis>
+ libraries automate the creation of this mapping layer and result in far less code
that is much more maintainable with
+ performance that is often as good as (if not better than) handwritten JDBC code.
The new
+ <ulink
url="http://java.sun.com/developer/technicalArticles/J2EE/jpa/"...
Persistence API (JPA)</ulink>
+ provide a standard mechanism for defining the mappings (through annotations) and
working with these entity objects. Several
+ commercial and open-source libraries implement JPA, and some even offer additional
capabilities and features that go beyond
+ JPA. For example,
+ <ulink url="http://www.hibernate.org">Hibernate</ulink>
+ is one of the most feature-rich JPA implementations and offers object caching,
statement caching, extra association
+ mappings, and other features that help to improve performance and usefulness.
+ </para>
+ <para>
+ While relational databases and JPA are solutions that work for many applications,
they become more limited in cases when the
+ information structure is highly flexible, is not known
+ <emphasis>a priori</emphasis>
+ , or is subject to frequent change and customization. In these situations,
+ <emphasis>content repositories</emphasis>
+ may offer a better choice for persistence. Content repositories are almost a hybrid
between relational databases and file
+ systems, and typically provide other capabilities as well, including versioning,
indexing, search, access control,
+ transactions, and observation. Because of this, content repositories are used by
content management systems (CMS), document
+ management systems (DMS), and other applications that manage electronic files
(e.g., documents, images, multi-media, web
+ content, etc.) and metadata associated with them (e.g., author, date, status,
security information, etc.). The
+ <ulink
url="http://www.jcp.org/en/jsr/detail?id=170">Content
Repository for Java technology API</ulink>
+ provides a standard Java API for working with content repositories. Abbreviated
"JCR", this API was developed as part of the
+ Java Community Process under
+ <ulink
url="http://www.jcp.org/en/jsr/detail?id=170">JSR-170</ul...
+ and is being revised under
+ <ulink
url="http://www.jcp.org/en/jsr/detail?id=283">JSR-283</ul...
+ .
+ </para>
+ <para>
+ The
+ <emphasis>JBoss DNA project</emphasis>
+ is building the tools and services that surround content repositories. Nearly all
of these capabilities are to be hidden
+ below the JCR API and involve automated processing of the information in the
repository. Thus, JBoss DNA can add value to
+ existing repository implementations. For example, JCR repositories offer the
ability to upload files into the repository and
+ have the file content indexed for search purposes. JBoss DNA also defines a library
for "sequencing" content - to extract
+ meaningful information from that content and store it in the repository, where it
can then be searched, accessed, and
+ analyzed using the JCR API.
+ </para>
+ <para> JBoss DNA is building other features as well. One goal of JBoss DNA is
to create federated repositories that
+ dynamically merge the information from multiple databases, services, applications,
and other JCR repositories. Another is to
+ create customized views based upon the type of data and the role of the user that
is accessing the data. And yet another is
+ to create a REST-ful API to allow the JCR content to be accessed easily by other
applications written in other languages.
+ </para>
+ <para>
+ The
+ <link linkend="jboss_dna">next chapter</link>
+ in this book goes into more detail about JBoss DNA and its architecture, the
different components, what's available now, and
+ what's coming in future releases.
+ <link linkend="downloading_and_running">Chapter 3</link>
+ then provides instructions for downloading and running the sequencer examples for
the current release.
+ <link linkend="using_dna">Chapter 4</link>
+ walks through how to use JBoss DNA in your applications, while
+ <link linkend="custom_sequencers">Chapter 5</link>
+ goes over how to create custom sequencers. Finally,
+ <link linkend="future_directions">Chapter 6</link>
+ wraps things up with a discussion about the future of JBoss DNA.
+ </para>
+ </chapter>
+ <chapter id="jboss_dna">
+ <title>Understanding JBoss DNA</title>
+ <sect1 id="jboss_dna_overview">
+ <title>Overview</title>
+ <para>JBoss DNA is a repository and set of tools that make it easy to
capture, version, analyze, and understand the
+ fundamental building blocks of information. As models, service and process
definitions, schemas, source code, and other
+ artifacts are added to the repository, JBoss DNA "sequences" the makeup
of these components and extracts their structure
+ and interdependencies. The JBoss DNA web application allows end users to access,
visualize, and edit this information in
+ the terminology and structure they are familiar with. Such domain-specific
solutions can be easily created with little or
+ no programming.</para>
+ <para> JBoss DNA supports the Java Content Repository (JCR) standard and is
able to provide a single integrated view of
+ multiple repositories, external databases, services, and applications, ensuring
that JBoss DNA has access to the latest
+ and most reliable master data. For instance, DNA could provide in a single view
valuable insight into the business
+ processes and process-level services impacted by a change to in an intermediary
web server operation defined via WSDL.
+ Similarly, a user could quickly view and navigate the dependencies between the
data source models and transformation
+ information stored within a content repository, the code base stored within a
version control system, and the database
+ schemas used by an application.</para>
+ </sect1>
+ <sect1 id="architecture">
+ <title>Architecture</title>
+ <para>The architecture for JBoss DNA consists of several major components
that will be built on top of standard APIs,
+ including JCR, JDBC, JNDI and HTTP. The goal is to allow these components to be
assembled as needed and add value on top
+ of other DNA components or third-party systems that support these standard
APIs.</para>
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata align="center"
fileref="images/dna-architecture.png" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata align="center"
fileref="images/dna-architecture.png" />
+ </imageobject>
+ </mediaobject>
+ <para>
+ As shown in the diagram above, the major components are (starting at the top):
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Eclipse
Plugins</emphasis>
+ enable Eclipse users to access the contents of a JBoss DNA repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA JDBC Driver</emphasis>
+ provides a driver implementation, allowing JDBC-aware applications to
connect to and use a JBoss DNA repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Remote JCR</emphasis>
+ is a client-side component for accessing remote JCR repositories.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Web
Application</emphasis>
+ is used by end users and domain experts to visualize, search, edit, change
and tag the repository content. The web
+ application uses views to define how different types of information are to
be presented and edited in
+ domain-specific ways. The goal is that this web application is easily
customized and branded for inclusion into
+ other solutions and application systems. The DNA Web Application operates
upon any JCR-compliant repository,
+ although it does rely upon the DNA analysis and templating services.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Publishing
Server</emphasis>
+ allows content to be downloaded, uploaded, and edited using the Atom
Publishing Protocol. With the DNA Publishing
+ Server, the content of the repository can easily be created, read, edited,
and deleted using the standard HTTP
+ operations of POST, GET, PUT, and DELETE (respectively). More and more
tools are being created that support working
+ with Atom Publishing servers. The DNA Publishing Server operates upon any
JCR-compliant repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA WebDAV Server</emphasis>
+ allows clients such as Microsoft Windows and Apple OS X to connect to,
read, and edit the content in the repository
+ using the WebDAV standard. Since WebDAV is an extension of HTTP, web
browsers are able to read (but not modify) the
+ content served by a WebDAV compliant server. The DNA WebDAV Server operates
upon any JCR-compliant repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Sequencers</emphasis>
+ are pluggable components that make it possible for content to be uploaded
to the repository and automatically
+ processed to extract meaningful structure and place that structure in the
repository. Once this information is in
+ the repository, it can be viewed, edited, analyzed, searched, and related
to other content. DNA defines a Java
+ interface that sequencers must implement. DNA sequencers operate upon any
JCR-compliant repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Analyses</emphasis>
+ are pluggable components that analyze content and the relationships between
content to generate reports or to answer
+ queries. DNA will include some standard analyzers, like dependency analysis
and similarity analysis, that are
+ commonly needed by many different solutions. DNA analyzers operate upon any
JCR-compliant repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Views</emphasis>
+ are definitions of how types of information are to be presented in a user
interface to allow for creation, reading,
+ editing, and deletion of information. DNA view definitions consist of data
stored in a JCR repository, and as such
+ views can be easily added, changed or removed entirely by using the DNA Web
Application, requiring no programming.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Federation</emphasis>
+ is an implementation of the JCR API that builds the content within the
repository by accessing and integrating
+ information from multiple sources. DNA Federation allows the integration of
external systems, like other JCR
+ repositories, databases, applications, and services.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Connectors</emphasis>
+ are used to communicate with these external sources of information. In the
federation engine, each source is able to
+ contribute node structure and node properties to any part of the federated
graph, although typically many connectors
+ will contribute most of their information to isolated subgraphs. The result
is that integration from a wide range of
+ systems can be integrated and accessed through the DNA Web Application, DNA
Publishing Server, and DNA WebDAV
+ Server. Connectors also may optionally participate in distributed
transactions by exposing an XAResource.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">DNA Maven</emphasis>
+ is a classloader library compatible with Maven 2 project dependencies. This
allows the creation of Java ClassLoader
+ instances using Maven 2 style paths, and all dependencies are transitively
managed and included.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Continue reading the rest of this chapter for more detail about the
+ <link linkend="sequencers">sequencing framework</link>
+ available in this release, or the
+ <link linkend="federation">federation engine</link>
+ and
+ <link linkend="federation_connectors">connectors</link>
+ that will be the focus of the next release. Or, skip to the
+ <link linkend="downloading_and_running">examples</link>
+ to see how to start using JBoss DNA &versionNumber;
+ today.
+ </para>
+ </sect1>
+ <sect1 id="sequencers">
+ <title>Sequencing content</title>
+ <para> The current JBoss DNA release contains a sequencing framework that is
designed to sequence data (typically files)
+ stored in a JCR repository to automatically extract meaningful and useful
information. This additional information is then
+ saved back into the repository, where it can be accessed and used.</para>
+ <para> In other words, you can just upload various kinds of files into a JCR
repository, and DNA automatically processes
+ those files to extract meaningful structured information. For example, load DDL
files into the repository, and let
+ sequencers extract the structure and metadata for the database schema. Load
Hibernate configuration files into the
+ repository, and let sequencers extract the schema and mapping information. Load
Java source into the repository, and let
+ sequencers extract the class structure, JavaDoc, and annotations. Load a PNG,
JPEG, or other image into the repository,
+ and let sequencers extract the metadata from the image and save it in the
repository. The same with XSDs, WSDL, WS
+ policies, UML, MetaMatrix models, etc.</para>
+ <para>
+ JBoss DNA sequencers sit on top of existing JCR repositories (including federated
repositories) - they basically extract
+ more useful information from what's already stored in the repository. And
they use the existing JCR versioning system. Each
+ sequencer typically processes a single kind of file format or a single kind of
content. </para>
+ <para>The following sequencers are included in JBoss DNA:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">Image sequencer</emphasis>
+ - A sequencer that processes the binary content of an image file, extracts
the metadata for the image, and then
+ writes that image metadata to the repository. It gets the file format,
image resolution, number of bits per pixel
+ (and optionally number of images), comments and physical resolution from
JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM,
+ PGM, PPM, and PSD files. (This sequencer may be improved in the future to
also extract EXIF metadata from JPEG
+ files; see
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ul...
+ .)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">MP3 sequencer</emphasis>
+ - A sequencer that processes the contents of an MP3 audio file, extracts
the metadata for the file, and then
+ writes that image metadata to the repository. It gets the title, author,
album, year, and comment.
+ (This sequencer may be improved in the future to also extract other ID3
metadata from other audio file formats; see
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-66">DNA-26</ul...
+ .)
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ As the community develops additional sequencers, they will also be included in
JBoss DNA. Some of those that have been
+ identified as being useful include:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">XML Schema Document (XSD)
Sequencer</emphasis>
+ - Process XSD files and extract the various elements, attributes, complex
types, simple types, groups, and other
+ information. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-32">DNA-32</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Web Service Definition Language
(WSDL) Sequencer</emphasis>
+ - Process WSDL files and extract the services, bindings, ports, operations,
parameters, and other information. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-33">DNA-33</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Hibernate File
Sequencer</emphasis>
+ - Process Hibernate configuration (cfg.xml) and mapping (hbm.xml) files to
extract the configuration and mapping
+ information. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-61">DNA-61</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">XML Metadata Interchange (XMI)
Sequencer</emphasis>
+ - Process XMI documents that contain UML models or models using another
metamodel, extracting the model structure
+ into the repository. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-31">DNA-31</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">ZIP Archive
Sequencer</emphasis>
+ - Process ZIP archive files to extract (explode) the contents into the
repository. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-63">DNA-63</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Java Archive (JAR)
Sequencer</emphasis>
+ - Process JAR files to extract (explode) the contents into the classes and
file resources. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-64">DNA-64</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Java Class File
Sequencer</emphasis>
+ - Process Java class files (bytecode) to extract the class structure
(including annotations) into the repository.
+ (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-62">DNA-62</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Java Source File
Sequencer</emphasis>
+ - Process Java source files to extract the class structure (including
annotations) into the repository. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-51">DNA-51</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">PDF Sequencer</emphasis>
+ - Process PDF files to extract the document metadata, including table of
contents. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-50">DNA-50</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Maven 2 POM
Sequencer</emphasis>
+ - Process Maven 2 Project Object Model (POM) files to extract the project
information, dependencies, plugins, and
+ other content. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-24">DNA-24</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Data Definition Language (DDL)
Sequencer</emphasis>
+ - Process various dialects of DDL, including that from Oracle, SQL Server,
MySQL, PostgreSQL, and others. May need
+ to be split up into a different sequencer for each dialect. (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-26">DNA-26</ul...
+ )
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">MP3 and MP4
Sequencer</emphasis>
+ - Process MP3 and MP4 audio files to extract the name of the song, artist,
album, track number, and other metadata.
+ (See
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA-30">DNA-30</ul...
+ )
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The
+ <link linkend="using_dna">examples</link>
+ in this book go into more detail about how sequencers are managed and used, and
+ <link linkend="custom_sequencers">Chapter 5</link>
+ goes into detail about how to write custom sequencers.
+ </para>
+ </sect1>
+ <sect1 id="federation">
+ <title>Federating content</title>
+ <para>There is a lot of information stored in many of different places:
databases, repositories, SCM systems,
+ registries, file systems, services, etc. The purpose of the federation engine is
to allow applications to use the JCR API
+ to access that information as if it were all stored in a single JCR repository,
but to really leave the information where
+ it is.</para>
+ <para>Why not just move the information into a JCR repository? Most likely
there are existing applications that rely upon
+ that information being where it is. If we were to move it, then all those
applications would break. Or they'd have to be
+ changed to use JCR. If the information is being used, the most practical thing is
to leave it where it is.</para>
+ <para>
+ Then why not just copy the information into a JCR repository? Actually, there are
times when it's perfectly reasonable to
+ make a copy of the data. Perhaps the system managing the existing information
cannot handle the additional load of more
+ clients. Or, perhaps the information doesn't change, or it does change and we
want snapshots that don't change. But more
+ likely, the data
+ <emphasis>does</emphasis>
+ change. So if applications are to use the most current information and we make
copies of the data, we have to keep the
+ copies synchronized with the master. That's generally a lot of work.
+ </para>
+ <para>The JBoss DNA federation engine lets us leave the information where it
is, yet lets client applications use the JCR
+ API to access all the information without caring where the information really
exists. If the underlying information
+ changes, client applications using JCR observation will be notified of the
changes. If a JBoss DNA federated repository is
+ configured to allow updates, client applications can change the information in
the repository and JBoss DNA will propagate
+ those changes down to the original source.</para>
+ <sect2 id="federation_connectors">
+ <title>Connecting to information sources</title>
+ <para>
+ The JBoss DNA federation engine will use connectors to interact with different
information sources to get at the content
+ in those systems. Some ideas for connectors include:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis role="strong">JCR Repository
Connector</emphasis>
+ - Connect to and interact with other JCR repositories.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">File System
Connector</emphasis>
+ - Expose the files and directories on a file system through JCR.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Maven 2 Repository
Connector</emphasis>
+ - Access and expose the contents of a Maven 2 repository (either on the
local file system or via HTTP) through
+ JCR.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">JDBC Metadata
Connector</emphasis>
+ - Connect to relational databases via JDBC and expose their schema as
content in a repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">UDDI Connector</emphasis>
+ - Interact with UDDI registries to integrate their content into a
repository.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">SVN Connector</emphasis>
+ - Interact with Subversion software configuration management (SCM)
repositories to expose the managed resources
+ through JCR. Consider using the
+ <ulink
url="http://svnkit.com/">SVNkit</ulink>
+ (dual license) library for an API into Subversion.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">CVS Connector</emphasis>
+ - Interact with CVS software configuration management (SCM) repositories
to expose the managed resources through
+ JCR.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">JDBC Storage
Connector</emphasis>
+ - Store and access information in a relational database. Also useful for
persisting information in the federated
+ repository not stored elsewhere.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis role="strong">Distributed Database
Connector</emphasis>
+ - Store and access information in a
+ <ulink
url="http://www.hypertable.org/">Hypertable</ulink>
+ or
+ <ulink
url="http://hadoop.apache.org/hbase/">HBase</ulink>
+ distributed databases. Also useful for persisting information in the
federated repository not stored elsewhere.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ If the connectors allow the information they contribute to be updated, they
must provide an
+ <code>XAResource</code>
+ implementation that can be used with a Java Transaction Service. Connectors
that provide read-only access need not
+ provide an implementation.
+ </para>
+ <para>
+ Also, connectors talk to
+ <emphasis>sources</emphasis>
+ of information, and it's quite likely that the same connector is used to
talk to different sources. Each source contains
+ the configuration details (e.g., connection information, location, properties,
options, etc.) for working with that
+ particular source, as well as a reference to the connector that should be used
to establish connections to the source.
+ And of course, sources can be added or removed without having to stop and
restart the federated repository.
+ </para>
+ </sect2>
+ <sect2 id="federation_graph">
+ <title>Building the unified graph</title>
+ <para> The federation engine works by effectively building up a single
graph by querying each source and merging or
+ unifying the responses. This information is cached, which improves performance,
reduces the number of (potentially
+ expensive) remote calls, reduces the load on the sources, and helps mitigate
problems with source availability. As
+ clients interact with the repository, this cache is consulted first. When the
requested portion of the graph (or
+ "subgraph") is contained completely in the cache, it is retuned
immediately. However, if any part of the requested
+ subgraph is not in the cache, each source is consulted for their contributions
to that subgraph, and any results are
+ cached.</para>
+ <para> This basic flow makes it possible for the federated repository to
build up a local cache of the integrated graph
+ (or at least the portions that are used by clients). In fact, the federated
repository caches information in a manner
+ that is similar to that of the Domain Name System (DNS). As sources are
consulted for their contributions, the source
+ also specifies whether it is the authoritative source for this information
(some sources that are themselves federated
+ may not be the information's authority), whether the information may be
modified, the time-to-live (TTL) value (the time
+ after which the cached information should be refreshed), and the expiration
time (the time after which the cached
+ information is no longer valid). In effect, the source has complete control
over how the information it contributes is
+ cached and used.</para>
+ <para>
+ The federated repository also needs to incorporate
+ <emphasis>negative caching</emphasis>
+ , which is storage of the knowledge that something does not exist. Sources can
be configured to contribute information
+ only below certain paths (e.g.,
+ <code>/A/B/C</code>
+ ), and the federation engine can take advantage of this by never consulting
that source for contributions to information
+ on other paths. However, below that path, any negative responses must also be
cached (with appropriate TTL and expiry
+ parameters) to prevent the exclusion of that source (in case the source has
information to contribute at a later time)
+ or the frequent checking with the source.
+ </para>
+ </sect2>
+ <sect2 id="federation_queries">
+ <title>Searching and querying</title>
+ <para> The JBoss DNA federated repository will also support queries against
the integrated and unified graph. In some
+ situations the query can be determined to apply to a single source, but in most
situations the query must be planned
+ (and possibly rewritten) such that it can be pushed down to all the appropriate
sources. Also, the cached results must
+ be consulted prior to returning the query results, as the results from one
source might have contributions from another
+ source.</para>
+ <note>
+ <para> It is hoped that the MetaMatrix query engine can be used for this
purpose after it is open-sourced. This engine
+ implements sophisticated query planning and optimization techniques for
working efficiently with multiple sources.
+ </para>
+ </note>
+ <para>Searching the whole federated repository is also important. This
allows users to simply supply a handful of
+ search terms, and to get results that are ranked based upon how close each
result is to the search terms. (Searching is
+ very different from querying, which involves specifying the exact semantics of
what is to be searched and how the
+ information is to be compared.) JBoss DNA will incorporate a search engine
(e.g., likely to be Lucene) and will populate
+ the engine's indexes using the federated content and the cached
information. Notifications of changing information will
+ be reflected in the indexes, but some sources may want to explicitly allow or
disallow periodic crawling of their
+ content.</para>
+ </sect2>
+ <sect2 id="federation_updates">
+ <title>Updating content</title>
+ <para>
+ The JBoss DNA federated repositories also make it possible for client
applications to make changes to the unified graph
+ within the context of distributed transactions. According to the JCR API,
client applications use the Java Transaction
+ API (JTA) to control the boundaries of their transactions. Meanwhile, the
federated repository uses a
+ <ulink
url="http://www.jboss.org/jbosstm/">distributed
transaction service</ulink>
+ to coordinate the XA resources provided by the connectors.
+ </para>
+ <para> It is quite possible that clients add properties to nodes in the
unified graph, and that this information cannot be
+ handled by the same underlying source that contributed to the node. In this
case, the federated repository can be
+ configured with a fallback source that will be used used to store this
"extra" information.</para>
+ <para>
+ It is a goal that non-XA sources (i.e., sources that use connectors without XA
resources) can participate in distributed
+ transactions through the use of
+ <emphasis>compensating transactions</emphasis>
+ . Because the JBoss DNA federation engine implements the JCR observation
system, it is capable of recording all of the
+ changes made to the distributed graph (and those changes sent to each updatable
source). Therefore, if a non-XA source
+ is involved in a distributed transaction that must be rolled back, any changes
made to non-XA sources can be undone. (Of
+ course, this does not make the underlying source transactional:
non-transactional sources still may expose the interim
+ changes to other clients.)
+ </para>
+ </sect2>
+ <sect2 id="federation_events">
+ <title>Observing changes</title>
+ <para> The JCR API supports observing a repository to receive notifications
of additions, changes and deletions of nodes
+ and properties. The JBoss DNA federated repository will support this API
through two primary means.</para>
+ <para> When the changes are made through the federated repository, the
JBoss DNA federation engine is well aware of the
+ set of changes that have been (or are being) made to the unified graph. These
events are directly propagated to
+ listeners.</para>
+ <para> Sources have the ability to publish events, making it possible for
the JBoss DNA federation engine and clients that
+ have registered listeners to be notified of changes in the information managed
by that source. These events are first
+ processed by the federation engine and possibly altered based upon
contributions from other sources. (The federation
+ engine also uses these events to update or purge information in the cache,
which may add to the event set.) The
+ resulting (and possibly altered) event set is then sent to all client
listeners.</para>
+ </sect2>
+ </sect1>
+ </chapter>
+ <!--
====================================================================================================
+ Chapter
+
====================================================================================================
-->
+ <chapter id="downloading_and_running">
+ <title>Running the example application</title>
+ <para>
+ This chapter provides instructions for downloading and running a sample application
that demonstrates how JBoss DNA works
+ with a JCR repository to automatically sequence changing content to extract useful
information. So read on to get the simple
+ application running, and then in the
+ <link linkend="using_dna">next chapter</link>
+ we'll dive into the source code for the example and show how to use JBoss DNA
in your own applications.
+ </para>
+ <para>JBoss DNA uses Maven 2 for its build system, as is this example. Using
Maven 2 has several advantages, including
+ the ability to manage dependencies. If a library is needed, Maven automatically
finds and downloads that library, plus
+ everything that library needs. This means that it's very easy to build the
examples - or even create a maven project that
+ depends on the JBoss DNA JARs.</para>
+ <note>
+ <para>
+ To use Maven with JBoss DNA, you'll need to have
+ <ulink
url="http://java.sun.com/javase/downloads/index_jdk5.jsp">JDK 5 or
6</ulink>
+ and Maven 2.0.7 (or higher).
+ </para>
+ <para>
+ Maven can be downloaded from
+ <ulink
url="http://maven.apache.org/">http://maven.apache.org/</...
+ , 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.spi.sequencers.StreamSequencer</code> interface with your
own implementation, and create unit tests to verify
+ the functionality and expected behavior;</para>
+ </listitem>
+ <listitem>
+ <para>Add the sequencer configuration to the JBoss DNA
<code>SequencingService</code> in your application
+ as described in the <link linkend="using_dna">previous
chapter</link>; and</para>
+ </listitem>
+ <listitem>
+ <para>Deploy the JAR file with your implementation (as well as any
dependencies), and make them available to JBoss DNA
+ in your application.</para>
+ </listitem>
+ </itemizedlist>
+ It's that simple.
+ </para>
+ <sect1 id="custom_sequencer_project">
+ <title>Creating the Maven 2 project</title>
+ <para>The first step is to create the Maven 2 project that you can use to
compile your code and build the JARs.
+ Maven 2 automates a lot of the work, and since you're already <link
linkend="downloading_and_running">set up to use Maven</link>,
+ using Maven for your project will save you a lot of time and effort. Of course, you
don't have to use Maven 2, but then you'll
+ have to get the required libraries and manage the compiling and building process
yourself.</para>
+ <note>
+ <para>JBoss DNA may provide in the future a Maven archetype for creating
sequencer projects. If you'd find this useful
+ and would like to help create it, please <link
linkend="preface">join the community</link>.</para>
+ </note>
+ <note>
+ <para>The <code>dna-sequencer-images</code> project is a small,
self-contained sequencer implementation that
+ has only the minimal dependencies. Starting with this project's source and
modifying it to suit your needs may be the easiest way to get started.
+ See the subversion repository: <ulink
url="http://anonsvn.jboss.org/repos/dna/trunk/sequencers/dna-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-spi</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.spi.sequencers.StreamSequencer</code> interface.
This interface is very straightforward
+ and involves a single method:
+ <programlisting>
+public interface StreamSequencer {
+
+ /**
+ * Sequence the data found in the supplied stream, placing the output
+ * information into the supplied map.
+ *
+ * @param stream the stream with the data to be sequenced; never null
+ * @param output the output from the sequencing operation; never null
+ * @param progressMonitor the progress monitor that should be kept
+ * updated with the sequencer's progress and that should be
+ * frequently consulted as to whether this operation has been cancelled.
+ */
+ void sequence( InputStream stream, SequencerOutput output,
+ ProgressMonitor progressMonitor );</programlisting>
+ </para>
+ <para>The job of a stream sequencer is to process the data in the supplied
stream, and place into the <code>SequencerOutput</code>
+ any information that is to go into the JCR repository. JBoss DNA figures out when
your sequencer should be called
+ (of course, using the sequencing configuration you'll add in a bit), and then
makes sure the generated information
+ is saved in the correct place in the repository.
+ </para>
+ <para>The <code>SequencerOutput</code> class is fairly easy to use.
There are basically two methods you need to call.
+ One method sets the property values, while the other sets references to other nodes
in the repository. Use these
+ methods to describe the properties of the nodes you want to create, using relative
paths for the nodes and
+ valid JCR property names for properties and references. JBoss DNA will ensure that
nodes are created or updated
+ whenever they're needed.
+ <programlisting>
+public interface SequencerOutput {
+
+ /**
+ * Set the supplied property on the supplied node. The allowable
+ * values are any of the following:
+ * - primitives (which will be autoboxed)
+ * - String instances
+ * - String arrays
+ * - byte arrays
+ * - InputStream instances
+ * - Calendar instances
+ *
+ * @param nodePath the path to the node containing the property;
+ * may not be null
+ * @param property the name of the property to be set
+ * @param values the value(s) for the property; may be empty if
+ * any existing property is to be removed
+ */
+ void setProperty( String nodePath, String property,
+ Object... values );
+
+ /**
+ * Set the supplied reference on the supplied node.
+ *
+ * @param nodePath the path to the node containing the property;
+ * may not be null
+ * @param property the name of the property to be set
+ * @param paths the paths to the referenced property, which may be
+ * absolute paths or relative to the sequencer output node;
+ * may be empty if any existing property is to be removed
+ */
+ void setReference( String nodePath, String property,
+ String... paths );
+}</programlisting>
+ </para>
+ <para>JBoss DNA will create nodes of type
<code>nt:unstructured</code> unless you specify the value for the
+ <code>jcr:primaryType</code> property. You can also specify the values
for the <code>jcr:mixinTypes</code> property
+ if you want to add mixins to any node.
+ </para>
+ <para>For a complete example of a sequencer, let's look at the
<code>org.jboss.dna.sequencers.image.ImageMetadataSequencer</code>
implementation:
+ <programlisting>
+public class ImageMetadataSequencer implements StreamSequencer {
+
+ public static final String METADATA_NODE = "image:metadata";
+ public static final String IMAGE_PRIMARY_TYPE = "jcr:primaryType";
+ public static final String IMAGE_MIXINS = "jcr:mixinTypes";
+ public static final String IMAGE_MIME_TYPE = "jcr:mimeType";
+ public static final String IMAGE_ENCODING = "jcr:encoding";
+ public static final String IMAGE_FORMAT_NAME = "image:formatName";
+ public static final String IMAGE_WIDTH = "image:width";
+ public static final String IMAGE_HEIGHT = "image:height";
+ public static final String IMAGE_BITS_PER_PIXEL = "image:bitsPerPixel";
+ public static final String IMAGE_PROGRESSIVE = "image:progressive";
+ public static final String IMAGE_NUMBER_OF_IMAGES =
"image:numberOfImages";
+ public static final String IMAGE_PHYSICAL_WIDTH_DPI =
"image:physicalWidthDpi";
+ public static final String IMAGE_PHYSICAL_HEIGHT_DPI =
"image:physicalHeightDpi";
+ public static final String IMAGE_PHYSICAL_WIDTH_INCHES =
"image:physicalWidthInches";
+ public static final String IMAGE_PHYSICAL_HEIGHT_INCHES =
"image:physicalHeightInches";
+
+ /**
+ * {@inheritDoc}
+ */
+ public void sequence( InputStream stream, SequencerOutput output,
+ ProgressMonitor progressMonitor ) {
+ progressMonitor.beginTask(10, ImageSequencerI18n.sequencerTaskName);
+
+ ImageMetadata metadata = new ImageMetadata();
+ metadata.setInput(stream);
+ metadata.setDetermineImageNumber(true);
+ metadata.setCollectComments(true);
+
+ // Process the image stream and extract the metadata ...
+ if (!metadata.check()) {
+ metadata = null;
+ }
+ progressMonitor.worked(5);
+ if (progressMonitor.isCancelled()) return;
+
+ // Generate the output graph if we found useful metadata ...
+ if (metadata != null) {
+ // Place the image metadata into the output map ...
+ output.setProperty(METADATA_NODE, IMAGE_PRIMARY_TYPE,
"image:metadata");
+ // output.psetProperty(METADATA_NODE, IMAGE_MIXINS, "");
+ output.setProperty(METADATA_NODE, IMAGE_MIME_TYPE, metadata.getMimeType());
+ // output.setProperty(METADATA_NODE, IMAGE_ENCODING, "");
+ output.setProperty(METADATA_NODE, IMAGE_FORMAT_NAME,
metadata.getFormatName());
+ output.setProperty(METADATA_NODE, IMAGE_WIDTH, metadata.getWidth());
+ output.setProperty(METADATA_NODE, IMAGE_HEIGHT, metadata.getHeight());
+ output.setProperty(METADATA_NODE, IMAGE_BITS_PER_PIXEL,
metadata.getBitsPerPixel());
+ output.setProperty(METADATA_NODE, IMAGE_PROGRESSIVE,
metadata.isProgressive());
+ output.setProperty(METADATA_NODE, IMAGE_NUMBER_OF_IMAGES,
metadata.getNumberOfImages());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_DPI,
metadata.getPhysicalWidthDpi());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_DPI,
metadata.getPhysicalHeightDpi());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_WIDTH_INCHES,
metadata.getPhysicalWidthInch());
+ output.setProperty(METADATA_NODE, IMAGE_PHYSICAL_HEIGHT_INCHES,
metadata.getPhysicalHeightInch());
+ }
+
+ progressMonitor.done();
+ }
+}</programlisting>
+ </para>
+ <para>
+ Notice how the image metadata is extracted and the output graph is generated. A
single node is created with the name <code>image:metadata</code>
+ and with the <code>image:metadata</code> node type. No mixins are
defined for the node, but several properties are set on the node
+ using the values obtained from the image metadata. After this method returns, the
constructed graph will be saved to the repository
+ in all of the places defined by its configuration. (This is why only relative paths
are used in the sequencer.)
+ </para>
+ <para>Also note how the progress monitor is used. Reporting progress through
the supplied <code>ProgressMonitor</code> is very easy, and it ensures that
JBoss DNA
+ can accurately monitor and report the status of sequencing activities to the users.
At the beginning of the operation, call
+ <code>beginTask(...)</code> with a meaningful message describing
+ the operation and a total for the amount of work that will be done by this
sequencer. Then perform the sequencing work,
+ periodically reporting work by specifying the incremental amount of work with the
<code>worked(double)</code> method, or
+ by creating a subtask with the <code>createSubtask(double)</code> method
and reporting work against that subtask
+ monitor.
+ </para>
+ <para>Your method should periodically use the ProgressMonitor's
<code>isCancelled()</code> method to check whether the operation has been
+ cancelled.. If this method returns true, the implementation should abort all work
as
+ soon as possible and close any resources that were acquired or opened.
+ </para>
+ <para>
+ Finally, when your sequencing operation is completed, it should call
<code>done()</code> on the progress monitor.
+ </para>
+ </sect1>
+ <sect1 id="testing_custom_sequencers">
+ <title>Testing custom sequencers</title>
+ <para>The sequencing framework was designed to make testing sequencers much
easier. In particular, the
+ <code>StreamSequencer</code> interface does not make use of the JCR API.
So instead of requiring a fully-configured
+ JCR repository and JBoss DNA system, unit tests for a sequencer can focus on testing
that the content is
+ processed correctly and the desired output graph is generated.</para>
+ <note>
+ <para>For a complete example of a sequencer unit test, see the
<code>ImageMetadataSequencerTest</code> unit test
+ in the <code>org.jboss.dna.sequencer.images</code> package of the
<code>dna-sequencers-image</code> project.
+ </para>
+ </note>
+ <para>The following code fragment shows one way of testing a sequencer, using
JUnit 4.4 assertions and
+ some of the classes made available by JBoss DNA. Of course,
+ this example code does not do any error handling and does not make all the
assertions a real test would.
+ <programlisting>
+Sequencer sequencer = new ImageMetadataSequencer();
+MockSequencerOutput output = new MockSequencerOutput();
+ProgressMonitor progress = new SimpleProgressMonitor("Test activity");
+InputStream stream = null;
+try {
+ stream =
this.getClass().getClassLoader().getResource("caution.gif").openStream();
+ sequencer.sequence(stream,output,progress); // writes to 'output'
+ assertThat(output.getPropertyValues("image:metadata",
"jcr:primaryType"),
+ is(new Object[] {"image:metadata"}));
+ assertThat(output.getPropertyValues("image:metadata",
"jcr:mimeType"),
+ is(new Object[] {"image/gif"}));
+ // ... make more assertions here
+ assertThat(output.hasReferences(), is(false));
+} finally {
+ stream.close();
+}</programlisting>
+ </para>
+ <para>It's also useful to test that a sequencer produces no output for
something it should not understand:
+ <programlisting>
+Sequencer sequencer = new ImageMetadataSequencer();
+MockSequencerOutput output = new MockSequencerOutput();
+ProgressMonitor progress = new SimpleProgressMonitor("Test activity");
+InputStream stream = null;
+try {
+ stream =
this.getClass().getClassLoader().getResource("caution.pict").openStream();
+ sequencer.sequence(stream,output,progress); // writes to 'output'
+ assertThat(output.hasProperties(), is(false));
+ assertThat(output.hasReferences(), is(false));
+} finally {
+ stream.close();
+}</programlisting>
+ </para>
+ <para>These are just two simple tests that show ways of testing a sequencer.
Some tests may get quite involved,
+ especially if a lot of output data is produced.
+ </para>
+ <para>It may also be useful to create some integration tests
+ that <link linkend="using_dna">configure JBoss DNA</link> to
use a custom sequencer, and to then upload
+ content using the JCR API, verifying that the custom sequencer did run. However,
remember that JBoss DNA
+ runs sequencers asynchronously in the background, and you must sychronize your tests
to ensure that the
+ sequencers have a chance to run before checking the results. (One way of doing this
(although, granted, not always reliable) is to wait for a second
+ after uploading your content, shutdown the <code>SequencingService</code>
and await its termination,
+ and then check that the sequencer output has been saved to the JCR repository. For
an example of this technique,
+ see the <code>SequencingClientTest</code> unit test in the example
application.)
+ </para>
+ </sect1>
+ <sect1 id="deploying_custom_sequencers">
+ <title>Deploying custom sequencers</title>
+ <para>The first step of deploying a sequencer consists of adding/changing the
sequencer configuration (e.g., <code>SequencerConfig</code>)
+ in the <code>SequencingService</code>. This was covered in the <link
linkend="sequencing_service">previous chapter</link>.
+ </para>
+ <para>
+ The second step is to make the sequencer implementation available to JBoss DNA. At
this time, the JAR containing
+ your new sequencer, as well as any JARs that your sequencer depends on, should be
placed on your application classpath.</para>
+ <note>
+ <para>A future goal of JBoss DNA is to allow sequencers, connectors, and
other extensions to be easily deployed into
+ a runtime repository. This process will not only be much simpler, but it will
also provide JBoss DNA
+ with the information necessary to update configurations and create the
appropriate class loaders for each extension.
+ Having separate class loaders for each extension helps prevent the pollution of
the common classpath,
+ facilitates an isolated runtime environment to eliminate any dependency
conflicts, and may potentially
+ enable hot redeployment of newer extension versions.
+ </para>
+ </note>
+ </sect1>
+</chapter>
+
+<!--
====================================================================================================
+ Chapter
+
====================================================================================================
-->
+<chapter id="future_directions">
+ <title>Looking to the future</title>
+ <para>What's next for JBoss DNA? Well, the sequencing system is just the
beginning. With this release, the sequencing system
+ is stable enough so that more <link
linkend="sequencers">sequencers</link> can be developed and used within
your own applications.
+ If you're interested in getting involved with the JBoss DNA project, consider
picking up one of the sequencers on our
+ <ulink
url="http://jira.jboss.org/jira/browse/DNA?report=com.atlassian.jira...;.
+ 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
Copied: branches/maeste/dna-repository/src/test/resources/plugin.xml (from rev 245,
trunk/dna-repository/src/test/resources/plugin.xml)
===================================================================
--- branches/maeste/dna-repository/src/test/resources/plugin.xml
(rev 0)
+++ branches/maeste/dna-repository/src/test/resources/plugin.xml 2008-06-07 12:28:47 UTC
(rev 246)
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<!-- (c) 2007 Varsity Gateway LLC. All rights reserved. -->
+<plugin
+ id="com.metamatrix.metamodels.transformation"
+ name="%pluginName"
+ version="5.5.1"
+ provider-name="%providerName"
+ class="com.metamatrix.metamodels.transformation.TransformationPlugin">
+
+ <runtime>
+ <library name="metamodelsTransformation.jar">
+ <export name="*"/>
+ </library>
+ </runtime>
+ <requires>
+ <import plugin="org.eclipse.emf.mapping" export="true"/>
+ <import plugin="org.eclipse.emf.ecore" export="true"/>
+ <import plugin="org.eclipse.emf.edit" export="true"/>
+ <import plugin="org.eclipse.emf.ecore.edit"
export="true"/>
+ <import plugin="org.eclipse.core.runtime"
export="true"/>
+ <import plugin="com.metamatrix.core" export="true"/>
+ <import plugin="com.metamatrix.metamodels.core"
export="true"/>
+ </requires>
+
+
+<!--
+ Each extension below represents a single metamodel. Each metmodel is
+ registered using under the specified <uri> value which must be the same
+ eNS_URI value defined in the EPackage class for that metamodel.
+ -->
+ <extension
+ id="transformation"
+ name="%metamodelName"
+ point="com.metamatrix.modeler.core.metamodel">
+ <uri>
+
http://www.metamatrix.com/metamodels/Transformation
+ </uri>
+ <alternateUri>
+ mtkplugin:///com.metamatrix.metamodels.Transformation
+ </alternateUri>
+ <packageClass
+
name="com.metamatrix.metamodels.transformation.TransformationPackage">
+ </packageClass>
+ <adapterClass
+
name="com.metamatrix.metamodels.transformation.provider.TransformationItemProviderAdapterFactory">
+ </adapterClass>
+ <properties
+ createAsPhysical="false"
+ requiresProxies="false"
+ participatoryOnly="true"
+ createAsVirtual="false"
+ supportsDiagrams="false"
+ supportsExtension="true">
+ </properties>
+ </extension>
+ <extension
+ point="org.eclipse.emf.ecore.generated_package">
+ <package
+
uri="http://www.metamatrix.com/metamodels/Transformation"
+
class="com.metamatrix.metamodels.transformation.TransformationPackage">
+ </package>
+ </extension>
+
+ <extension
+ id="mapping"
+ name="%mappingMetamodelName"
+ point="com.metamatrix.modeler.core.metamodel">
+ <uri>
+
http://www.eclipse.org/emf/2002/Mapping
+ </uri>
+ <alternateUri>
+
mtkplugin:///www.eclipse.org/emf/2002/Mapping
+ </alternateUri>
+ <packageClass
+ name="org.eclipse.emf.mapping.MappingPackage">
+ </packageClass>
+ <adapterClass
+
name="org.eclipse.emf.mapping.provider.MappingItemProviderAdapterFactory">
+ </adapterClass>
+ <properties
+ createAsPhysical="false"
+ requiresProxies="false"
+ participatoryOnly="true"
+ createAsVirtual="false"
+ supportsDiagrams="false"
+ supportsExtension="false">
+ </properties>
+ </extension>
+
+</plugin>
Modified:
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/InvalidPathException.java
===================================================================
---
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/InvalidPathException.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/InvalidPathException.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -57,4 +57,11 @@
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
}
Modified:
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/NamespaceException.java
===================================================================
---
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/NamespaceException.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/NamespaceException.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -57,4 +57,11 @@
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
}
Modified:
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathNotFoundException.java
===================================================================
---
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathNotFoundException.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathNotFoundException.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -57,4 +57,11 @@
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
}
Modified:
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/ValueFormatException.java
===================================================================
---
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/ValueFormatException.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/ValueFormatException.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -57,4 +57,11 @@
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
}
Modified:
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnection.java
===================================================================
---
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnection.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnection.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -23,6 +23,7 @@
import java.util.concurrent.TimeUnit;
import javax.transaction.xa.XAResource;
+import org.jboss.dna.spi.cache.CachePolicy;
import org.jboss.dna.spi.graph.commands.GraphCommand;
/**
@@ -31,6 +32,7 @@
* These connections need not support concurrent operations by multiple threads, since
the federation engine never uses them this
* way.
* </p>
+ *
* @author Randall Hauch
*/
public interface RepositoryConnection {
@@ -38,6 +40,7 @@
/**
* Get the name for this repository source. This value should be the same as that
{@link RepositorySource#getName() returned}
* by the same {@link RepositorySource} that created this connection.
+ *
* @return the identifier; never null or empty
*/
String getSourceName();
@@ -45,12 +48,14 @@
/**
* Return the transactional resource associated with this connection. The transaction
manager will use this resource to manage
* the participation of this connection in a distributed transaction.
+ *
* @return the XA resource, or null if this connection is not aware of distributed
transactions
*/
XAResource getXAResource();
/**
* Ping the underlying system to determine if the connection is still valid and
alive.
+ *
* @param time the length of time to wait before timing out
* @param unit the time unit to use; may not be null
* @return true if this connection is still valid and can still be used, or false
otherwise
@@ -60,12 +65,21 @@
/**
* Set the listener that is to receive notifications to changes to content within
this source.
+ *
* @param listener the new listener, or null if no component is interested in the
change notifications
*/
void setListener( RepositorySourceListener listener );
/**
+ * Get the default cache policy for this repository. If none is provided, a global
cache policy will be used.
+ *
+ * @return the default cache policy
+ */
+ CachePolicy getDefaultCachePolicy();
+
+ /**
* Execute the supplied commands against this repository source.
+ *
* @param env the environment in which the commands are being executed; never null
* @param commands the commands to be executed; never null
* @throws RepositorySourceException if there is a problem loading the node data
@@ -75,6 +89,7 @@
/**
* Close this connection to signal that it is no longer needed and that any
accumulated resources are to be released.
+ *
* @throws InterruptedException if the thread has been interrupted while the close
was in progress
*/
void close() throws InterruptedException;
Modified:
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java
===================================================================
---
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -43,6 +43,7 @@
import org.jboss.dna.common.util.LogContext;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.spi.SpiI18n;
+import org.jboss.dna.spi.cache.CachePolicy;
import org.jboss.dna.spi.graph.commands.GraphCommand;
/**
@@ -52,6 +53,21 @@
public class RepositoryConnectionPool implements RepositoryConnectionFactory {
/**
+ * The core pool size for default-constructed pools is {@value}.
+ */
+ public static final int DEFAULT_CORE_POOL_SIZE = 1;
+
+ /**
+ * The maximum pool size for default-constructed pools is {@value}.
+ */
+ public static final int DEFAULT_MAXIMUM_POOL_SIZE = 10;
+
+ /**
+ * The keep-alive time for connections in default-constructed pools is {@value}
seconds.
+ */
+ public static final long DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS = 30;
+
+ /**
* Permission for checking shutdown
*/
private static final RuntimePermission shutdownPerm = new
RuntimePermission("modifyThread");
@@ -146,7 +162,20 @@
private final Logger logger = Logger.getLogger(this.getClass());
/**
+ * Create the pool to use the supplied connection factory, which is typically a
{@link RepositorySource}. This constructor
+ * uses the {@link #DEFAULT_CORE_POOL_SIZE default core pool size}, {@link
#DEFAULT_MAXIMUM_POOL_SIZE default maximum pool
+ * size}, and {@link #DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS default keep-alive time (in
seconds)}.
+ *
+ * @param connectionFactory the factory for connections
+ * @throws IllegalArgumentException if the connection factory is null or any of the
supplied arguments are invalid
+ */
+ public RepositoryConnectionPool( RepositoryConnectionFactory connectionFactory ) {
+ this(connectionFactory, DEFAULT_CORE_POOL_SIZE, DEFAULT_MAXIMUM_POOL_SIZE,
DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS, TimeUnit.SECONDS);
+ }
+
+ /**
* Create the pool to use the supplied connection factory, which is typically a
{@link RepositorySource}.
+ *
* @param connectionFactory the factory for connections
* @param corePoolSize the number of connections to keep in the pool, even if they
are idle.
* @param maximumPoolSize the maximum number of connections to allow in the pool.
@@ -226,6 +255,7 @@
* Sets the time limit for which connections may remain idle before being closed. If
there are more than the core number of
* connections currently in the pool, after waiting this amount of time without being
used, excess threads will be terminated.
* This overrides any value set in the constructor.
+ *
* @param time the time to wait. A time value of zero will cause excess connections
to terminate immediately after being
* returned.
* @param unit the time unit of the time argument
@@ -240,6 +270,7 @@
/**
* Returns the connection keep-alive time, which is the amount of time which
connections in excess of the core pool size may
* remain idle before being closed.
+ *
* @param unit the desired time unit of the result
* @return the time limit
* @see #setKeepAliveTime
@@ -259,6 +290,7 @@
/**
* Sets the maximum allowed number of connections. This overrides any value set in
the constructor. If the new value is
* smaller than the current value, excess existing but unused connections will be
closed.
+ *
* @param maximumPoolSize the new maximum
* @throws IllegalArgumentException if maximumPoolSize less than zero or the {@link
#getCorePoolSize() core pool size}
* @see #getMaximumPoolSize
@@ -284,6 +316,7 @@
/**
* Returns the core number of connections.
+ *
* @return the core number of connections
* @see #setCorePoolSize(int)
*/
@@ -295,6 +328,7 @@
* Sets the core number of connections. This overrides any value set in the
constructor. If the new value is smaller than the
* current value, excess existing and unused connections will be closed. If larger,
new connections will, if needed, be
* created.
+ *
* @param corePoolSize the new core size
* @throws RepositorySourceException if there was an error obtaining the new
connection
* @throws InterruptedException if the thread was interrupted during the operation
@@ -328,7 +362,9 @@
// -------------------------------------------------
/**
- * Returns the current number of connections in the pool.
+ * Returns the current number of connections in the pool, including those that are
checked out (in use) and those that are not
+ * being used.
+ *
* @return the number of connections
*/
public int getPoolSize() {
@@ -336,7 +372,8 @@
}
/**
- * Returns the approximate number of connections that have been checked out from the
pool.
+ * Returns the approximate number of connections that are currently checked out from
the pool.
+ *
* @return the number of checked-out connections
*/
public int getInUseCount() {
@@ -351,6 +388,7 @@
/**
* Get the total number of connections that have been created by this pool.
+ *
* @return the total number of connections created by this pool
*/
public long getTotalConnectionsCreated() {
@@ -359,6 +397,7 @@
/**
* Get the total number of times connections have been {@link #getConnection()}
used.
+ *
* @return the total number
*/
public long getTotalConnectionsUsed() {
@@ -371,6 +410,7 @@
/**
* Call the supplied operation, using a connection from this pool.
+ *
* @param <T> the return type for the operation
* @param operation the operation to be run using a connection in this pool
* @return the results from the operation
@@ -378,7 +418,7 @@
* @throws InterruptedException if the thread was interrupted during the operation
* @throws IllegalArgumentException if the operation is null
* @see #callable(RepositoryOperation)
- * @see #callables(Collection)
+ * @see #callables(Iterable)
* @see #callables(RepositoryOperation...)
*/
public <T> T call( RepositoryOperation<T> operation ) throws
RepositorySourceException, InterruptedException {
@@ -399,11 +439,12 @@
/**
* Return a callable object that, when run, performs the supplied repository
operation against a connection in this pool.
+ *
* @param <T> the return type for the operation
* @param operation the operation to be run using a connection in this pool
* @return the callable
* @see #call(RepositoryOperation)
- * @see #callables(Collection)
+ * @see #callables(Iterable)
* @see #callables(RepositoryOperation...)
*/
public <T> Callable<T> callable( final RepositoryOperation<T>
operation ) {
@@ -413,6 +454,7 @@
/**
* Execute by getting a connection from this pool, running the client, and
return the connection to the pool.
+ *
* @return the operation's result
* @throws Exception
*/
@@ -425,12 +467,13 @@
/**
* Return a collection of callable objects that, when run, perform the supplied
repository operations against connections in
* this pool.
+ *
* @param <T> the return type for the operations
* @param operations the operations to be run using connection from this pool
* @return the collection of callables
* @see #call(RepositoryOperation)
* @see #callable(RepositoryOperation)
- * @see #callables(Collection)
+ * @see #callables(Iterable)
*/
public <T> List<Callable<T>> callables(
RepositoryOperation<T>... operations ) {
List<Callable<T>> callables = new
ArrayList<Callable<T>>();
@@ -443,6 +486,7 @@
/**
* Return a collection of callable objects that, when run, perform the supplied
repository operations against connections in
* this pool.
+ *
* @param <T> the return type for the operations
* @param operations the operations to be run using connection from this pool
* @return the collection of callables
@@ -450,7 +494,7 @@
* @see #callable(RepositoryOperation)
* @see #callables(RepositoryOperation...)
*/
- public <T> List<Callable<T>> callables(
Collection<RepositoryOperation<T>> operations ) {
+ public <T> List<Callable<T>> callables(
Iterable<RepositoryOperation<T>> operations ) {
List<Callable<T>> callables = new
ArrayList<Callable<T>>();
for (final RepositoryOperation<T> operation : operations) {
callables.add(callable(operation));
@@ -466,6 +510,7 @@
* Starts a core connection, causing it to idly wait for use. This overrides the
default policy of starting core connections
* only when they are {@link #getConnection() needed}. This method will return
<tt>false</tt> if all core connections have
* already been started.
+ *
* @return true if a connection was started
* @throws RepositorySourceException if there was an error obtaining the new
connection
* @throws InterruptedException if the thread was interrupted during the operation
@@ -483,6 +528,7 @@
/**
* Starts all core connections, causing them to idly wait for use. This overrides the
default policy of starting core
* connections only when they are {@link #getConnection() needed}.
+ *
* @return the number of connections started.
* @throws RepositorySourceException if there was an error obtaining the new
connection
* @throws InterruptedException if the thread was interrupted during the operation
@@ -500,9 +546,11 @@
/**
* Initiates an orderly shutdown in which connections that are currently in use are
allowed to be used and closed as normal,
* but no new connections will be created. Invocation has no additional effect if
already shut down.
- * @throws SecurityException if a security manager exists and shutting down this
ConnectionPool may manipulate threads that
- * the caller is not permitted to modify because it does not hold {@link
java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
- * or the security manager's <tt>checkAccess</tt> method denies
access.
+ *
+ * @throws SecurityException if a security manager exists and shutting down this pool
may manipulate threads that the caller
+ * is not permitted to modify because it does not hold {@link
java.lang.RuntimePermission}<tt>("modifyThread")</tt>, or
+ * the security manager's <tt>checkAccess</tt> method denies access.
+ * @see #shutdownNow()
*/
public void shutdown() {
// Fail if caller doesn't have modifyThread permission. We
@@ -548,14 +596,12 @@
}
/**
- * Attempts to stop all actively executing tasks, halts the processing of waiting
tasks, and returns a list of the tasks that
- * were awaiting execution.
- * <p>
- * This implementation cancels tasks via {@link Thread#interrupt}, so if any tasks
mask or fail to respond to interrupts,
- * they may never terminate.
- * @throws SecurityException if a security manager exists and shutting down this
ExecutorService may manipulate threads that
- * the caller is not permitted to modify because it does not hold {@link
java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
- * or the security manager's <tt>checkAccess</tt> method denies
access.
+ * Attempts to close all connections, including those connections currently in use,
and prevent the use of other connections.
+ *
+ * @throws SecurityException if a security manager exists and shutting down this pool
may manipulate threads that the caller
+ * is not permitted to modify because it does not hold {@link
java.lang.RuntimePermission}<tt>("modifyThread")</tt>, or
+ * the security manager's <tt>checkAccess</tt> method denies access.
+ * @see #shutdown()
*/
public void shutdownNow() {
// Almost the same code as shutdown()
@@ -608,25 +654,67 @@
if (fullyTerminated) terminated();
}
+ /**
+ * Return whether this connection pool is running and is able to {@link
#getConnection() provide connections}. Note that this
+ * method is effectively <code>!isShutdown()</code>.
+ *
+ * @return true if this pool is running, or false otherwise
+ * @see #isShutdown()
+ * @see #isTerminated()
+ * @see #isTerminating()
+ */
+ public boolean isRunning() {
+ return runState == RUNNING;
+ }
+
+ /**
+ * Return whether this connection pool is in the process of shutting down or has
already been shut down. A result of
+ * <code>true</code> signals that the pool may no longer be used. Note
that this method is effectively
+ * <code>!isRunning()</code>.
+ *
+ * @return true if this pool has been shut down, or false otherwise
+ * @see #isShutdown()
+ * @see #isTerminated()
+ * @see #isTerminating()
+ */
public boolean isShutdown() {
return runState != RUNNING;
}
/**
- * Returns true if this executor is in the process of terminating after
<tt>shutdown</tt> or <tt>shutdownNow</tt> but has
- * not completely terminated. This method may be useful for debugging. A return of
<tt>true</tt> reported a sufficient
- * period after shutdown may indicate that submitted tasks have ignored or suppressed
interruption, causing this executor not
- * to properly terminate.
- * @return true if terminating but not yet terminated.
+ * Returns true if this pool is in the process of terminating after {@link
#shutdown()} or {@link #shutdownNow()} has been
+ * called but has not completely terminated. This method may be useful for debugging.
A return of <tt>true</tt> reported a
+ * sufficient period after shutdown may indicate that submitted tasks have ignored or
suppressed interruption, causing this
+ * executor not to properly terminate.
+ *
+ * @return true if terminating but not yet terminated, or false otherwise
+ * @see #isTerminated()
*/
public boolean isTerminating() {
return runState == STOP;
}
+ /**
+ * Return true if this pool has completed its termination and no longer has any open
connections.
+ *
+ * @return true if terminated, or false otherwise
+ * @see #isTerminating()
+ */
public boolean isTerminated() {
return runState == TERMINATED;
}
+ /**
+ * Method that can be called after {@link #shutdown()} or {@link #shutdownNow()} to
wait until all connections in use at the
+ * time those methods were called have been closed normally. This method accepts a
maximum time duration, after which it will
+ * return even if all connections have not been closed.
+ *
+ * @param timeout the maximum time to wait for all connections to be closed and
returned to the pool
+ * @param unit the time unit for <code>timeout</code>
+ * @return true if the pool was terminated in the supplied time (or was already
terminated), or false if the timeout occurred
+ * before all the connections were closed
+ * @throws InterruptedException if the thread was interrupted
+ */
public boolean awaitTermination( long timeout, TimeUnit unit ) throws
InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
@@ -645,14 +733,14 @@
}
/**
- * Method invoked when the Executor has terminated. Default implementation does
nothing. Note: To properly nest multiple
+ * Method invoked when the pool has terminated. Default implementation does nothing.
Note: To properly nest multiple
* overridings, subclasses should generally invoke
<tt>super.terminated</tt> within this method.
*/
protected void terminated() {
}
/**
- * Invokes <tt>shutdown</tt> when this executor is no longer referenced.
+ * Invokes <tt>shutdown</tt> when this pool is no longer referenced.
*/
@Override
protected void finalize() {
@@ -743,6 +831,7 @@
/**
* This method is automatically called by the {@link ConnectionWrapper} when it is
{@link ConnectionWrapper#close() closed}.
+ *
* @param wrapper the wrapper to the connection that is being returned to the pool
*/
protected void returnConnection( ConnectionWrapper wrapper ) {
@@ -786,6 +875,7 @@
/**
* Validate the supplied connection, returning the connection if valid or null if the
connection is not valid.
+ *
* @param connection the connection to be validated; may not be null
* @return the validated connection, or null if the connection did not validate and
was removed from the pool
*/
@@ -814,6 +904,7 @@
* connection would violate the {@link #maximumPoolSize maximum pool size} nor does
it add the new connection to the
* {@link #availableConnections available connections} (as the caller may want it
immediately), but it does increment the
* {@link #poolSize pool size}.
+ *
* @return the connection wrapper with a new connection
* @throws RepositorySourceException if there was an error obtaining the new
connection
* @throws InterruptedException if the thread was interrupted during the operation
@@ -829,6 +920,7 @@
/**
* Close a connection that is in the pool but no longer in the {@link
#availableConnections available connections}. This
* method does decrement the {@link #poolSize pool size}.
+ *
* @param wrapper the wrapper for the connection to be closed
* @throws InterruptedException if the thread was interrupted during the operation
*/
@@ -957,6 +1049,14 @@
/**
* {@inheritDoc}
*/
+ public CachePolicy getDefaultCachePolicy() {
+ if (closed) throw new
IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
+ return this.original.getDefaultCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public void execute( ExecutionEnvironment env, GraphCommand... commands ) throws
RepositorySourceException, InterruptedException {
if (closed) throw new
IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
this.original.execute(env, commands);
Modified:
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositorySource.java
===================================================================
---
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositorySource.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositorySource.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -23,7 +23,6 @@
import java.io.Serializable;
import javax.naming.Referenceable;
-import org.jboss.dna.spi.cache.CachePolicy;
/**
* A repository source is a description of a resource that can be used to access or store
repository information. This class
@@ -39,6 +38,7 @@
* {@link Referenceable} and {@link Serializable} so that such objects can be stored in
any JNDI naming context and enable proper
* system recovery,
* </p>
+ *
* @author Randall Hauch
*/
public interface RepositorySource extends RepositoryConnectionFactory, Referenceable,
Serializable {
@@ -47,6 +47,7 @@
* Get the maximum number of retries that may be performed on a given operation when
using
* {@link #getConnection() connections} created by this source. This value does not
constitute a minimum number of retries; in
* fact, the connection user is not required to retry any operations.
+ *
* @return the maximum number of allowable retries, or 0 if the source has no limit
*/
int getRetryLimit();
@@ -55,14 +56,9 @@
* Set the maximum number of retries that may be performed on a given operation when
using
* {@link #getConnection() connections} created by this source. This value does not
constitute a minimum number of retries; in
* fact, the connection user is not required to retry any operations.
+ *
* @param limit the maximum number of allowable retries, or 0 if the source has no
limit
*/
void setRetryLimit( int limit );
- /**
- * Get the default cache policy for this source. If none is provided, a global cache
policy will be used.
- * @return the default cache policy
- */
- CachePolicy getDefaultCachePolicy();
-
}
Modified:
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositorySourceException.java
===================================================================
---
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositorySourceException.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositorySourceException.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -70,4 +70,12 @@
return this.sourceName;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+
}
Modified:
branches/maeste/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java
===================================================================
---
branches/maeste/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -75,9 +75,6 @@
this.retryLimit.set(limit);
}
- /**
- * {@inheritDoc}
- */
public CachePolicy getDefaultCachePolicy() {
return defaultCachePolicy;
}
@@ -170,6 +167,13 @@
/**
* {@inheritDoc}
*/
+ public CachePolicy getDefaultCachePolicy() {
+ return MockRepositorySource.this.getDefaultCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public XAResource getXAResource() {
return this.xaResource.get();
}
Modified:
branches/maeste/dna-spi/src/test/java/org/jboss/dna/spi/sequencers/MockSequencerOutput.java
===================================================================
---
branches/maeste/dna-spi/src/test/java/org/jboss/dna/spi/sequencers/MockSequencerOutput.java 2008-06-06
21:21:35 UTC (rev 245)
+++
branches/maeste/dna-spi/src/test/java/org/jboss/dna/spi/sequencers/MockSequencerOutput.java 2008-06-07
12:28:47 UTC (rev 246)
@@ -34,6 +34,7 @@
/**
* @author Randall Hauch
+ * @author John Verhaeg
*/
@NotThreadSafe
public class MockSequencerOutput implements SequencerOutput {
@@ -46,10 +47,12 @@
public MockSequencerOutput() {
this.properties = new HashMap<Path, Object[]>();
NamespaceRegistry registry = new BasicNamespaceRegistry();
- registry.register("dna", "http://www.jboss.org/dna/1.0");
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("dna", "http://www.jboss.org/dna/1.0");
+ registry.register("dnadtd", "http://www.jboss.org/dna/1.0/dtd");
+ registry.register("dnaxml", "http://www.jboss.org/dna/1.0/xml");
factories = new StandardValueFactories(registry);
}
@@ -64,7 +67,7 @@
* <p>
* {@inheritDoc}
* </p>
- *
+ *
* @see org.jboss.dna.spi.sequencers.SequencerOutput#getNamespaceRegistry()
*/
public NamespaceRegistry getNamespaceRegistry() {
Modified: branches/maeste/docs/examples/gettingstarted/sequencers/.classpath
===================================================================
--- branches/maeste/docs/examples/gettingstarted/sequencers/.classpath 2008-06-06 21:21:35
UTC (rev 245)
+++ branches/maeste/docs/examples/gettingstarted/sequencers/.classpath 2008-06-07 12:28:47
UTC (rev 246)
@@ -2,8 +2,8 @@
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
- <classpathentry kind="src" path="src/test/java"/>
- <classpathentry kind="src" path="src/test/resources"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/resources"/>
<classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
Copied: branches/maeste/eclipse-code-formatter-profile.xml (from rev 245,
trunk/eclipse-code-formatter-profile.xml)
===================================================================
--- branches/maeste/eclipse-code-formatter-profile.xml (rev 0)
+++ branches/maeste/eclipse-code-formatter-profile.xml 2008-06-07 12:28:47 UTC (rev 246)
@@ -0,0 +1,267 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<profiles version="11">
+ <profile kind="CodeFormatterProfile" name="DNA"
version="11">
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant"
value="end_of_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns"
value="false"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve"
value="1"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations"
value="1"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line"
value="false"/>
+ <setting
id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for"
value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.tabulation.size"
value="4"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports"
value="1"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk"
value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.continuation_indentation"
value="0"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration"
value="83"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment"
value="4"/>
+ <setting
id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type"
value="1"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression"
value="4"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description"
value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_html"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_source_code"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration"
value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.indentation.size"
value="4"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration"
value="36"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration"
value="end_of_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.lineSplit"
value="130"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration"
value="36"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_header"
value="false"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call"
value="18"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields"
value="16"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer"
value="20"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field"
value="0"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration"
value="36"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments"
value="false"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression"
value="18"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator"
value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package"
value="1"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration"
value="36"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode"
value="enabled"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups"
value="0"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression"
value="18"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports"
value="1"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier"
value="error"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant"
value="18"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration"
value="0"/>
+ <setting
id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line"
value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_empty_lines"
value="false"/>
+ <setting
id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block"
value="insert"/>
+ <setting id="org.eclipse.jdt.core.compiler.source"
value="1.5"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.line_length"
value="130"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.compiler.compliance"
value="1.5"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.compact_else_if"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments"
value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration"
value="83"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body"
value="0"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier"
value="error"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line"
value="false"/>
+ <setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform"
value="1.5"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if"
value="0"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration"
value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression"
value="18"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation"
value="4"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column"
value="false"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer"
value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags"
value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants"
value="81"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration"
value="36"/>
+ <setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation"
value="82"/>
+ <setting id="org.eclipse.jdt.core.formatter.tabulation.char"
value="space"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package"
value="0"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line"
value="true"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters"
value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method"
value="1"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration"
value="insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column"
value="false"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator"
value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block"
value="end_of_line"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression"
value="do not insert"/>
+ <setting
id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter"
value="insert"/>
+ </profile>
+</profiles>
Copied: branches/maeste/eclipse-preferences.epf (from rev 245,
trunk/eclipse-preferences.epf)
===================================================================
--- branches/maeste/eclipse-preferences.epf (rev 0)
+++ branches/maeste/eclipse-preferences.epf 2008-06-07 12:28:47 UTC (rev 246)
@@ -0,0 +1,71 @@
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.compliance=1.5
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.deprecation=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.finalParameterBound=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=protected
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingJavadocTags=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.nullReference=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.typeParameterHiding=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=error
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.source=1.5
+/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.gettersetter.use.is=true
+/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.ignorelowercasenames=true
+/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.importorder=\#;java;javax;org;com;
+/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.javadoc=true
+/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.ondemandthreshold=99
+/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.overrideannotation=true
+/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.staticondemandthreshold=99
+/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.text.custom_code_templates=<?xml
version\="1.0" encoding\="UTF-8"
standalone\="no"?><templates><template autoinsert\="false"
context\="gettercomment_context" deleted\="false"
description\="Comment for getter method" enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment"
name\="gettercomment">/**\n * @return ${bare_field_name}\n
*/</template><template autoinsert\="false"
context\="settercomment_context" deleted\="false"
description\="Comment for setter method" enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.settercomment"
name\="settercomment">/**\n * @param ${param} Sets ${bare_field_name} to the
specified value.\n */</template><template autoinsert\="false"
context\="constructorcomment_context" deleted\="false"
description\="Comment for created constructors" enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment"
name\="constructorcomment">/**\n * ${tags}\n */</template><tem!
plate autoinsert\="false" context\="filecomment_context"
deleted\="false" description\="Comment for created Java files"
enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.filecomment"
name\="filecomment">/*\n *\n */</template><template
autoinsert\="false" context\="typecomment_context"
deleted\="false" description\="Comment for created types"
enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.typecomment"
name\="typecomment">/**\n * @author John Verhaeg\n * ${tags}\n
*/</template><template autoinsert\="false"
context\="fieldcomment_context" deleted\="false"
description\="Comment for fields" enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment"
name\="fieldcomment">/**\n */</template><template
autoinsert\="false" context\="methodcomment_context"
deleted\="false" description\="Comment for non-overriding methods"
enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment"
name\="methodcomment">/**\n * ${tags}\n */</template><tem!
plate autoinsert\="false" context\="overridecomment_context"
deleted\=
"false" description\="Comment for overriding methods"
enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment"
name\="overridecomment">/**\n * <p>\n * {@inheritDoc}\n *
</p>\n *\n * ${see_to_overridden}\n */</template><template
autoinsert\="false" context\="delegatecomment_context"
deleted\="false" description\="Comment for delegate methods"
enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment"
name\="delegatecomment">/**\n * <p>\n * {@inheritDoc}\n *
</p>\n *\n * ${see_to_target}\n */</template><template
autoinsert\="false" context\="catchblock_context"
deleted\="false" description\="Code in new catch blocks"
enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock"
name\="catchblock"/><template autoinsert\="false"
context\="methodbody_context" deleted\="false" description\="Code
in created method stubs" enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.methodbody"
name\="methodbody">${bo!
dy_statement}</template><template autoinsert\="false"
context\="constructorbody_context" deleted\="false"
description\="Code in created constructor stubs" enabled\="true"
id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody"
name\="constructorbody">${body_statement}\n</template><template
autoinsert\="false" context\="getterbody_context"
deleted\="false" description\="Code in created getters"
enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody"
name\="getterbody">return ${field};</template><template
autoinsert\="false" context\="setterbody_context"
deleted\="false" description\="Code in created setters"
enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody"
name\="setterbody">${field} \= ${param};</template></templates>
+/instance/org.eclipse.jdt.ui/outlinesortoption=SF,SI,SM,F,I,C,M,T,
+/instance/org.eclipse.ui.editors/spacesForTabs=true