DNA SVN: r849 - in trunk: dna-jcr/src/main/java/org/jboss/dna/jcr and 4 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-23 12:43:27 -0400 (Thu, 23 Apr 2009)
New Revision: 849
Added:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaLexicon.java
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SimpleSessionFactory.java
trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java
Log:
DNA-58 Create repository configuration and component
Refactored the DnaConfiguration to make use of the graph repository for storing the configuration. When used, the DnaConfiguration instance persists all the information to this graph, where it can be read and used. A "save()" method was added to allow the code using the DnaConfiguration instance to control when the content is updated. (This also simplified the unit testing, since it's very easy to check the graph content after the DnaConfiguration methods are used.) The DnaEngine was then updated to read the configuration repository content and to instantiate and set up the services.
This "configuration repository" defaults to an in-memory repository, but can be set up to use a particular RepositorySource instance (that has already been set up) or to reflectively create an instance given the class name, optional class loader, and various (implementation-specific) Java bean properties.
This means that in the simplest case, one can simply create a DnaConfiguration and configure the sequencers, sources, detectors, etc. It also makes it very simple to "read" an XML file with the configuration, since that just uses the XML graph importer. But using a configuration repository shines in the more advanced cases, such as when a process participates in a cluster. Here, the process can create a DnaConfiguration, very easily set it up to use a shared (and remote) configuration repository (that already has the content), and without any other work immediately build the DnaEngine.
Using a graph as the configuration repository also means that any changes to the configuration could be monitored via graph events, allowing the DnaEngine to monitor any changes and dynamically alter its services.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -234,7 +234,7 @@
}
/**
- * Find the method on the target class that matches the supplied method name.
+ * Find the methods on the target class that matches the supplied method name.
*
* @param methodNamePattern the regular expression pattern for the name of the method that is to be found.
* @return the Method objects that have a matching name, or an empty array if there are no methods that have a matching name.
@@ -252,6 +252,50 @@
}
/**
+ * Find the getter methods on the target class that begin with "get" or "is", that have no parameters, and that return
+ * something other than void. This method skips the {@link Object#getClass()} method.
+ *
+ * @return the Method objects for the getters; never null but possibly empty
+ */
+ public Method[] findGetterMethods() {
+ final Method[] allMethods = this.targetClass.getMethods();
+ final List<Method> result = new ArrayList<Method>();
+ for (int i = 0; i < allMethods.length; i++) {
+ final Method m = allMethods[i];
+ int numParams = m.getParameterTypes().length;
+ if (numParams != 0) continue;
+ String name = m.getName();
+ if (name.equals("getClass")) continue;
+ if (m.getReturnType() == Void.TYPE) continue;
+ if (name.startsWith("get") || name.startsWith("is")) {
+ result.add(m);
+ }
+ }
+ return result.toArray(new Method[result.size()]);
+ }
+
+ /**
+ * Find the property names with getter methods on the target class. This method returns the property names for the methods
+ * returned by {@link #findGetterMethods()}.
+ *
+ * @return the Java Bean property names for the getters; never null but possibly empty
+ */
+ public String[] findGetterPropertyNames() {
+ final Method[] getters = findGetterMethods();
+ final List<String> result = new ArrayList<String>();
+ for (int i = 0; i < getters.length; i++) {
+ final Method m = getters[i];
+ String name = m.getName();
+ if (name.startsWith("get") && name.length() > 3) {
+ result.add(name.substring(3));
+ } else if (name.startsWith("is") && name.length() > 2) {
+ result.add(name.substring(2));
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ /**
* Find the method on the target class that matches the supplied method name.
*
* @param methodName the name of the method that is to be found.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -29,7 +29,7 @@
/**
* @author Randall Hauch
*/
-public class DnaLexicon extends org.jboss.dna.graph.DnaLexicon {
+public class DnaLexicon extends org.jboss.dna.repository.DnaLexicon {
public static final Name DEFINED = new BasicName(Namespace.URI, "defined");
public static final Name NAMESPACE = new BasicName(Namespace.URI, "namespace");
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -21,45 +21,61 @@
*/
package org.jboss.dna.repository;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.component.ClassLoaderFactory;
import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.text.Inflector;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.Reflection;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Node;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
import org.jboss.dna.graph.mimetype.MimeTypeDetector;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathExpression;
-import org.jboss.dna.graph.sequencer.StreamSequencer;
-import org.jboss.dna.repository.mimetype.MimeTypeDetectorConfig;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
import org.jboss.dna.repository.sequencer.Sequencer;
-import org.jboss.dna.repository.sequencer.SequencerConfig;
-import org.jboss.dna.repository.sequencer.StreamSequencerAdapter;
/**
*/
@Immutable
public class DnaConfiguration {
- protected RepositorySource configurationSource;
- protected String configurationSourceDescription;
- protected Graph configuration;
+ protected static final Map<String, Name> NAMES_TO_MAP;
+ static {
+ Map<String, Name> names = new HashMap<String, Name>();
+ names.put(DnaLexicon.READABLE_NAME.getLocalName(), DnaLexicon.READABLE_NAME);
+ names.put(DnaLexicon.DESCRIPTION.getLocalName(), DnaLexicon.DESCRIPTION);
+ names.put(DnaLexicon.DEFAULT_CACHE_POLICY.getLocalName(), DnaLexicon.DEFAULT_CACHE_POLICY);
+ names.put(DnaLexicon.RETRY_LIMIT.getLocalName(), DnaLexicon.RETRY_LIMIT);
+ names.put(DnaLexicon.PATH_EXPRESSIONS.getLocalName(), DnaLexicon.PATH_EXPRESSIONS);
+ names.put(DnaLexicon.CLASSNAME.getLocalName(), DnaLexicon.CLASSNAME);
+ names.put(DnaLexicon.CLASSPATH.getLocalName(), DnaLexicon.CLASSPATH);
+ NAMES_TO_MAP = Collections.unmodifiableMap(names);
+ }
+
+ protected class Source {
+ protected RepositorySource source;
+ protected String description;
+ protected Path path;
+ }
+
private final ExecutionContext context;
+ protected Source configurationSource;
+ private Path sourcesPath;
+ private Path sequencersPath;
+ private Path detectorsPath;
+ private Graph graph;
+ private Graph.Batch batch;
/**
- * Mapping of repository names to configured repositories
- */
- protected final Map<String, DnaRepositoryDetails> repositories;
- protected final Map<String, DnaMimeTypeDetectorDetails> mimeTypeDetectors;
- protected final Map<String, DnaSequencerDetails> sequencers;
-
- /**
* Create a new configuration for DNA.
*/
public DnaConfiguration() {
@@ -70,61 +86,79 @@
* Specify a new {@link ExecutionContext} that should be used for this DNA instance.
*
* @param context the new context, or null if a default-constructed execution context should be used
+ * @throws IllegalArgumentException if the supplied context reference is null
*/
public DnaConfiguration( ExecutionContext context ) {
+ CheckArg.isNotNull(context, "context");
this.context = context;
- this.repositories = new HashMap<String, DnaRepositoryDetails>();
- this.mimeTypeDetectors = new HashMap<String, DnaMimeTypeDetectorDetails>();
- this.sequencers = new HashMap<String, DnaSequencerDetails>();
// Set up the default configuration repository ...
this.configurationSource = createDefaultConfigurationSource();
+ }
+ /**
+ * Method that is used to set up the default configuration repository source. By default, this method sets up the
+ * {@link InMemoryRepositorySource} loaded from the classpath.
+ *
+ * @return the default repository source
+ */
+ protected Source createDefaultConfigurationSource() {
+ InMemoryRepositorySource defaultSource = new InMemoryRepositorySource();
+ defaultSource.setName("Configuration");
+ Source result = new Source();
+ result.source = defaultSource;
+ result.path = this.context.getValueFactories().getPathFactory().createRootPath();
+ result.description = "Configuration Repository";
+ return result;
}
- private DnaConfiguration( DnaConfiguration source ) {
- this.configuration = source.configuration;
- this.configurationSource = source.configurationSource;
- this.context = source.context;
- this.configurationSourceDescription = source.configurationSourceDescription;
- this.repositories = new HashMap<String, DnaRepositoryDetails>(source.repositories);
- this.mimeTypeDetectors = new HashMap<String, DnaMimeTypeDetectorDetails>(source.mimeTypeDetectors);
- this.sequencers = new HashMap<String, DnaSequencerDetails>(source.sequencers);
+ protected final ExecutionContext context() {
+ return this.context;
}
- private DnaConfiguration with( String repositoryName,
- DnaRepositoryDetails details ) {
- DnaConfiguration newConfig = new DnaConfiguration(this);
- newConfig.repositories.put(repositoryName, details);
-
- return newConfig;
+ protected final PathFactory pathFactory() {
+ return context().getValueFactories().getPathFactory();
}
- protected ExecutionContext getExecutionContext() {
- return this.context;
+ /**
+ * Get the graph containing the configuration information. This should be called only after the
+ * {@link #withConfigurationRepository() configuration repository} is set up.
+ *
+ * @return the configuration repository graph; never null
+ * @see #graph()
+ */
+ protected final Graph graph() {
+ if (this.graph == null) {
+ this.graph = Graph.create(configurationSource.source, context);
+ }
+ return this.graph;
}
- protected Graph getConfiguration() {
- if (this.configuration == null) {
- this.configuration = Graph.create(configurationSource, context);
+ /**
+ * Get the graph batch that can be used to change the configuration, where the changes are enqueued until {@link #save()
+ * saved}. This should be called only after the {@link #withConfigurationRepository() configuration repository} is set up.
+ *
+ * @return the latest batch for changes to the configuration repository; never null
+ * @see #graph()
+ */
+ protected final Graph.Batch configuration() {
+ if (this.batch == null) {
+ this.batch = graph().batch();
}
- return this.configuration;
+ return this.batch;
}
/**
- * Method that is used to set up the default configuration repository source. By default, this method sets up the
- * {@link InMemoryRepositorySource} loaded from the classpath.
+ * Save any changes that have been made so far to the configuration. This method does nothing if no changes have been made.
*
- * @return the default repository source
+ * @return this configuration object for method chaining purposes; never null
*/
- protected RepositorySource createDefaultConfigurationSource() {
- this.withConfigurationRepository()
- .usingClass(InMemoryRepositorySource.class.getName())
- .loadedFromClasspath()
- .describedAs("Configuration Repository")
- .with("name")
- .setTo("Configuration");
- return configurationSource;
+ public DnaConfiguration save() {
+ if (this.batch != null) {
+ this.batch.execute();
+ this.batch = this.graph.batch();
+ }
+ return this;
}
/**
@@ -135,40 +169,69 @@
* @return the interface for choosing the class, which returns the interface used to configure the repository source that will
* be used for the configuration repository; never null
*/
- public ChooseClass<RepositorySource, RepositoryDetails> withConfigurationRepository() {
- return addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME);
+ public ChooseClass<RepositorySource, ConfigRepositoryDetails> withConfigurationRepository() {
+ final Source source = this.configurationSource;
+ // The config repository is different, since it has to load immediately ...
+ return new ChooseClass<RepositorySource, ConfigRepositoryDetails>() {
+ public LoadedFrom<ConfigRepositoryDetails> usingClass( final String className ) {
+ return new LoadedFrom<ConfigRepositoryDetails>() {
+ @SuppressWarnings( "unchecked" )
+ public ConfigRepositoryDetails loadedFrom( String... classpath ) {
+ ClassLoader classLoader = context().getClassLoader(classpath);
+ Class<? extends RepositorySource> clazz = null;
+ try {
+ clazz = (Class<? extends RepositorySource>)classLoader.loadClass(className);
+ } catch (ClassNotFoundException err) {
+ throw new DnaConfigurationException(RepositoryI18n.unableToLoadClassUsingClasspath.text(className,
+ classpath));
+ }
+ return usingClass(clazz);
+ }
+
+ @SuppressWarnings( "unchecked" )
+ public ConfigRepositoryDetails loadedFromClasspath() {
+ Class<? extends RepositorySource> clazz = null;
+ try {
+ clazz = (Class<? extends RepositorySource>)Class.forName(className);
+ } catch (ClassNotFoundException err) {
+ throw new DnaConfigurationException(RepositoryI18n.unableToLoadClass.text(className));
+ }
+ return usingClass(clazz);
+ }
+ };
+ }
+
+ public ConfigRepositoryDetails usingClass( Class<? extends RepositorySource> repositorySource ) {
+ try {
+ source.source = repositorySource.newInstance();
+ } catch (InstantiationException err) {
+ I18n msg = RepositoryI18n.errorCreatingInstanceOfClass;
+ throw new DnaConfigurationException(msg.text(repositorySource.getName(), err.getLocalizedMessage()), err);
+ } catch (IllegalAccessException err) {
+ I18n msg = RepositoryI18n.errorCreatingInstanceOfClass;
+ throw new DnaConfigurationException(msg.text(repositorySource.getName(), err.getLocalizedMessage()), err);
+ }
+ return new ConfigurationSourceDetails();
+ }
+ };
}
/**
* Add a new {@link RepositorySource repository} for this configuration. The new repository will have the supplied name, and
* if the name of an existing repository is used, this will replace the existing repository configuration.
*
- * @param name the name of the new repository that is to be added
+ * @param id the id of the new repository that is to be added
* @return the interface for choosing the class, which returns the interface used to configure the repository source; never
* null
* @throws IllegalArgumentException if the repository name is null, empty, or otherwise invalid
* @see #addRepository(RepositorySource)
*/
- public ChooseClass<RepositorySource, RepositoryDetails> addRepository( final String name ) {
- return new ClassChooser<RepositorySource, RepositoryDetails>() {
-
- @Override
- protected RepositoryDetails getComponentBuilder( String className,
- String... classpath ) {
- try {
- Class<?> clazz = Class.forName(className);
- Object newInstance = clazz.newInstance();
- assert newInstance instanceof RepositorySource;
-
- DnaRepositoryDetails details = new DnaRepositoryDetails((RepositorySource)newInstance);
- DnaConfiguration.this.repositories.put(name, details);
-
- return details;
- } catch (Exception ex) {
- throw new DnaConfigurationException(ex);
- }
- }
- };
+ public ChooseClass<RepositorySource, RepositoryDetails> addRepository( final String id ) {
+ CheckArg.isNotEmpty(id, "id");
+ // Now create the "dna:source" node with the supplied id ...
+ Path sourcePath = pathFactory().create(sourcesPath(), id);
+ configuration().create(sourcePath).with(DnaLexicon.READABLE_NAME, id).and();
+ return new ClassChooser<RepositorySource, RepositoryDetails>(sourcePath, new GraphRepositoryDetails(sourcePath));
}
/**
@@ -181,338 +244,130 @@
* @see #addRepository(String)
*/
public DnaConfiguration addRepository( RepositorySource source ) {
- return this.with(source.getName(), new DnaRepositoryDetails(source));
+ CheckArg.isNotNull(source, "source");
+ CheckArg.isNotEmpty(source.getName(), "source.getName()");
+ String name = source.getName();
+ RepositoryDetails details = addRepository(source.getName()).usingClass(source.getClass().getName()).loadedFromClasspath();
+ // Record all of the bean properties ...
+ Path sourcePath = pathFactory().create(sourcesPath(), name);
+ Reflection reflector = new Reflection(source.getClass());
+ for (String propertyName : reflector.findGetterPropertyNames()) {
+ Object value;
+ try {
+ value = reflector.invokeGetterMethodOnTarget(propertyName, source);
+ if (value == null) continue;
+ propertyName = Inflector.getInstance().lowerCamelCase(propertyName);
+ if (NAMES_TO_MAP.containsKey(propertyName)) {
+ configuration().set(NAMES_TO_MAP.get(propertyName)).to(value).on(sourcePath);
+ } else {
+ configuration().set(propertyName).to(value).on(sourcePath);
+ }
+ } catch (ValueFormatException err) {
+ throw err;
+ } catch (Throwable err) {
+ // Unable to call getter and set property
+ }
+ }
+ return details.and();
}
/**
* Add a new {@link Sequencer sequencer} to this configuration. The new sequencer will have the supplied name, and if the name
* of an existing sequencer is used, this will replace the existing sequencer configuration.
*
- * @param name the name of the new sequencer
+ * @param id the identifier of the new sequencer
* @return the interface for choosing the class, which returns the interface used to configure the sequencer; never null
* @throws IllegalArgumentException if the sequencer name is null, empty, or otherwise invalid
*/
- public ChooseClass<Sequencer, SequencerDetails> addSequencer( final String name ) {
- return new ClassChooser<Sequencer, SequencerDetails>() {
-
- @Override
- protected SequencerDetails getComponentBuilder( String className,
- String... classpath ) {
- try {
- Class<?> clazz = Class.forName(className);
- Object newInstance = clazz.newInstance();
- assert newInstance instanceof Sequencer;
-
- DnaSequencerDetails details = new DnaSequencerDetails(name, (Sequencer)newInstance, classpath);
- DnaConfiguration.this.sequencers.put(name, details);
-
- return details;
- } catch (Exception ex) {
- throw new DnaConfigurationException(ex);
- }
- }
- };
+ public ChooseClass<Sequencer, SequencerDetails> addSequencer( final String id ) {
+ CheckArg.isNotEmpty(id, "id");
+ // Now create the "dna:sequencer" node with the supplied id ...
+ Path sequencerPath = pathFactory().create(sequencersPath(), id);
+ configuration().create(sequencerPath).with(DnaLexicon.READABLE_NAME, id).and();
+ return new ClassChooser<Sequencer, SequencerDetails>(sequencerPath, new GraphSequencerDetails(sequencerPath));
}
/**
- * Add a new {@link StreamSequencer sequencer} to this configuration. The new stream sequencer will have the supplied name,
- * and if the name of an existing sequencer is used, this will replace the existing sequencer configuration.
- *
- * @param name the name of the new sequencer
- * @return the interface for choosing the class, which returns the interface used to configure the stream sequencer; never
- * null
- * @throws IllegalArgumentException if the sequencer name is null, empty, or otherwise invalid
- */
- public ChooseClass<StreamSequencer, SequencerDetails> addStreamSequencer( final String name ) {
- return new ClassChooser<StreamSequencer, SequencerDetails>() {
-
- @Override
- protected SequencerDetails getComponentBuilder( String className,
- String... classpath ) {
- try {
- Class<?> clazz = Class.forName(className);
- Object newInstance = clazz.newInstance();
- assert newInstance instanceof StreamSequencer;
-
- DnaSequencerDetails details = new DnaSequencerDetails(
- name,
- new StreamSequencerAdapter((StreamSequencer)newInstance),
- classpath);
- DnaConfiguration.this.sequencers.put(name, details);
-
- return details;
- } catch (Exception ex) {
- throw new DnaConfigurationException(ex);
- }
- }
- };
- }
-
- /**
* Add a new {@link MimeTypeDetector MIME type detector} to this configuration. The new detector will have the supplied name,
* and if the name of an existing detector is used, this will replace the existing detector configuration.
*
- * @param name the name of the new detector
+ * @param id the id of the new detector
* @return the interface for choosing the class, which returns the interface used to configure the detector; never null
* @throws IllegalArgumentException if the detector name is null, empty, or otherwise invalid
*/
- public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails> addMimeTypeDetector( final String name ) {
- return new ClassChooser<MimeTypeDetector, MimeTypeDetectorDetails>() {
-
- @Override
- protected MimeTypeDetectorDetails getComponentBuilder( String className,
- String... classpath ) {
- try {
- Class<?> clazz = Class.forName(className);
- Object newInstance = clazz.newInstance();
- assert newInstance instanceof MimeTypeDetector;
-
- DnaMimeTypeDetectorDetails details = new DnaMimeTypeDetectorDetails(name, (MimeTypeDetector)newInstance,
- classpath);
- DnaConfiguration.this.mimeTypeDetectors.put(name, details);
-
- return details;
- } catch (Exception ex) {
- throw new DnaConfigurationException(ex);
- }
- }
- };
+ public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails> addMimeTypeDetector( final String id ) {
+ CheckArg.isNotEmpty(id, "id");
+ // Now create the "dna:sequencer" node with the supplied id ...
+ Path detectorPath = pathFactory().create(detectorsPath(), id);
+ configuration().create(detectorPath).with(DnaLexicon.READABLE_NAME, id).and();
+ return new ClassChooser<MimeTypeDetector, MimeTypeDetectorDetails>(detectorPath,
+ new GraphMimeTypeDetectorDetails(detectorPath));
}
/**
* Complete this configuration and create the corresponding engine.
*
* @return the new engine configured by this instance
+ * @throws DnaConfigurationException if the engine cannot be created from this configuration.
*/
- public DnaEngine build() {
+ public DnaEngine build() throws DnaConfigurationException {
+ save();
return new DnaEngine(this);
}
- /**
- * Interface used to configure a {@link RepositorySource repository}.
- */
- public interface RepositoryDetails
- extends SetDescription<RepositoryDetails>, SetProperties<RepositoryDetails>, ConfigurationBuilder {
-
- RepositorySource getRepositorySource();
+ protected Path sourcesPath() {
+ // Make sure the "dna:sources" node is there
+ if (sourcesPath == null) {
+ Path path = pathFactory().create(this.configurationSource.path, DnaLexicon.SOURCES);
+ Node node = graph().createIfMissing(path).andReturn();
+ this.sourcesPath = node.getLocation().getPath();
+ }
+ return this.sourcesPath;
}
- /**
- * Local implementation of the {@link MimeTypeDetectorDetails} interface that tracks all of the user-provided configuration
- * details.
- */
- protected class DnaMimeTypeDetectorDetails implements MimeTypeDetectorDetails {
- final MimeTypeDetector mimeTypeDetector;
- private String name;
- private String description;
- private Map<String, Object> properties;
- private String className;
- private String[] classpath;
-
- protected DnaMimeTypeDetectorDetails( String name,
- MimeTypeDetector mimeTypeDetector,
- String[] classpath ) {
- this.mimeTypeDetector = mimeTypeDetector;
- this.name = name;
- this.description = mimeTypeDetector.getClass().getName();
- this.properties = new HashMap<String, Object>();
- this.className = mimeTypeDetector.getClass().getName();
- this.classpath = classpath;
+ protected Path sequencersPath() {
+ // Make sure the "dna:sequencers" node is there
+ if (sequencersPath == null) {
+ Path path = pathFactory().create(this.configurationSource.path, DnaLexicon.SEQUENCERS);
+ Node node = graph().createIfMissing(path).andReturn();
+ this.sequencersPath = node.getLocation().getPath();
}
+ return this.sequencersPath;
+ }
- public Map<String, Object> getProperties() {
- return properties;
+ protected Path detectorsPath() {
+ // Make sure the "dna:mimeTypeDetectors" node is there
+ if (detectorsPath == null) {
+ Path path = pathFactory().create(this.configurationSource.path, DnaLexicon.MIME_TYPE_DETECTORS);
+ Node node = graph().createIfMissing(path).andReturn();
+ this.detectorsPath = node.getLocation().getPath();
}
-
- protected String getDescription() {
- return description;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
- */
- public MimeTypeDetectorDetails describedAs( String description ) {
- this.description = description;
- return this;
- }
-
- public PropertySetter<MimeTypeDetectorDetails> with( final String propertyName ) {
- return new MappingPropertySetter<MimeTypeDetectorDetails>(propertyName, this);
- }
-
- public MimeTypeDetector getMimeTypeDetector() {
- return mimeTypeDetector;
- }
-
- MimeTypeDetectorConfig getMimeTypeDetectorConfig() {
- return new MimeTypeDetectorConfig(name, description, properties, className, classpath);
- }
-
- public DnaConfiguration and() {
- return DnaConfiguration.this;
- }
-
+ return this.detectorsPath;
}
/**
- * Local implementation of the {@link RepositoryDetails} interface that tracks all of the user-provided configuration details.
+ * Interface used to configure a {@link RepositorySource repository}.
*/
- protected class DnaRepositoryDetails implements RepositoryDetails {
- private final RepositorySource source;
- private final String description;
- private Map<String, Object> properties;
-
- protected DnaRepositoryDetails( RepositorySource source ) {
- this.source = source;
- this.description = source.getName();
- this.properties = new HashMap<String, Object>();
- }
-
- protected DnaRepositoryDetails( RepositorySource source,
- String description ) {
- this.source = source;
- this.description = description;
- }
-
- public Map<String, Object> getProperties() {
- return properties;
- }
-
- protected String getDescription() {
- return description;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
- */
- public RepositoryDetails describedAs( String description ) {
- return new DnaRepositoryDetails(this.source, description);
- }
-
- public PropertySetter<RepositoryDetails> with( final String propertyName ) {
- return new BeanPropertySetter<RepositoryDetails>(source, propertyName, this);
- }
-
- public RepositorySource getRepositorySource() {
- return source;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
- */
- public DnaConfiguration and() {
- return DnaConfiguration.this;
- }
+ public interface RepositoryDetails
+ extends SetName<RepositoryDetails>, SetDescription<RepositoryDetails>, SetProperties<RepositoryDetails>,
+ ConfigurationBuilder {
}
- /**
- * Local implementation of the {@link SequencerDetails} interface that tracks all of the user-provided configuration details.
- */
- protected class DnaSequencerDetails implements SequencerDetails {
- private final Sequencer sequencer;
- private String name;
- private String description;
- private Map<String, Object> properties;
- private String className;
- private String[] classpath;
- final List<PathExpression> sourcePathExpressions;
- final List<PathExpression> targetPathExpressions;
-
- protected DnaSequencerDetails( String name,
- Sequencer sequencer,
- String[] classpath ) {
- this.sequencer = sequencer;
- this.name = name;
- this.description = sequencer.getClass().getName();
- this.properties = new HashMap<String, Object>();
- this.className = sequencer.getClass().getName();
- this.classpath = classpath;
- this.sourcePathExpressions = new ArrayList<PathExpression>();
- this.targetPathExpressions = new ArrayList<PathExpression>();
- }
-
- public Map<String, Object> getProperties() {
- return properties;
- }
-
- protected String getDescription() {
- return description;
- }
-
+ public interface ConfigRepositoryDetails
+ extends SetDescription<ConfigRepositoryDetails>, SetProperties<ConfigRepositoryDetails>, ConfigurationBuilder {
/**
- * {@inheritDoc}
+ * Specify the path under which the configuration content is to be found. This path is assumed to be "/" by default.
*
- * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
+ * @param path the path to the configuration content in the configuration source; may not be null
+ * @return this instance for method chaining purposes; never null
*/
- public SequencerDetails describedAs( String description ) {
- this.description = description;
- return this;
- }
-
- public PropertySetter<SequencerDetails> with( final String propertyName ) {
- return new MappingPropertySetter<SequencerDetails>(propertyName, this);
- }
-
- public Sequencer getSequencer() {
- return sequencer;
- }
-
- SequencerConfig getSequencerConfig() {
- return new SequencerConfig(this.name, this.description, this.properties, this.className, this.classpath);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
- */
- public DnaConfiguration and() {
- return DnaConfiguration.this;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SequencerDetails#sequencingFrom(java.lang.String)
- */
- public PathExpressionOutput sequencingFrom( String inputExpressionPath ) {
- return this.sequencingFrom(PathExpression.compile(inputExpressionPath));
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.SequencerDetails#sequencingFrom(org.jboss.dna.graph.property.PathExpression)
- */
- public PathExpressionOutput sequencingFrom( final PathExpression inputExpressionPath ) {
- final DnaSequencerDetails details = this;
- return new PathExpressionOutput() {
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.DnaConfiguration.PathExpressionOutput#andOutputtingTo(java.lang.String)
- */
- public DnaSequencerDetails andOutputtingTo( final String outputExpressionPath ) {
- details.sourcePathExpressions.add(inputExpressionPath);
- details.targetPathExpressions.add(PathExpression.compile(outputExpressionPath));
- return details;
- }
- };
- }
-
+ public ConfigRepositoryDetails under( String path );
}
/**
* Interface used to configure a {@link Sequencer sequencer}.
*/
- public interface SequencerDetails extends SetDescription<SequencerDetails>, ConfigurationBuilder {
+ public interface SequencerDetails extends SetName<SequencerDetails>, SetDescription<SequencerDetails>, ConfigurationBuilder {
/**
* Specify the input {@link PathExpression path expression} represented as a string, which determines when this sequencer
@@ -529,9 +384,9 @@
*
* @param inputPathExpression the path expression for nodes that, when they change, will be passed as an input to the
* sequencer
- * @return the interface used to specify the output path expression; never null
+ * @return the interface used to continue specifying the configuration of the sequencer
*/
- PathExpressionOutput sequencingFrom( PathExpression inputPathExpression );
+ SequencerDetails sequencingFrom( PathExpression inputPathExpression );
}
/**
@@ -553,7 +408,8 @@
* Interface used to configure a {@link MimeTypeDetector MIME type detector}.
*/
public interface MimeTypeDetectorDetails
- extends SetDescription<MimeTypeDetectorDetails>, SetProperties<MimeTypeDetectorDetails>, ConfigurationBuilder {
+ extends SetName<MimeTypeDetectorDetails>, SetDescription<MimeTypeDetectorDetails>,
+ SetProperties<MimeTypeDetectorDetails>, ConfigurationBuilder {
}
/**
@@ -670,6 +526,7 @@
*
* @param clazz the class that should be instantiated
* @return the next component to continue configuration; never null
+ * @throws DnaConfigurationException if the class could not be accessed and instantiated (if needed)
* @throws IllegalArgumentException if the class reference is null
*/
ReturnType usingClass( Class<? extends ComponentClassType> clazz );
@@ -691,6 +548,21 @@
}
/**
+ * The interface used to set a human readable name on a component.
+ *
+ * @param <ReturnType> the interface returned from these methods
+ */
+ public interface SetName<ReturnType> {
+ /**
+ * Specify the human-readable name for this component.
+ *
+ * @param description the description; may be null or empty
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType named( String description );
+ }
+
+ /**
* Interface for specifying from where the component's class is to be loaded.
*
* @param <ReturnType> the interface returned from these methods
@@ -725,8 +597,6 @@
*/
public interface ConfigurationBuilder {
- Map<String, Object> getProperties();
-
/**
* Return a reference to the enclosing configuration so that it can be built or further configured.
*
@@ -735,6 +605,211 @@
DnaConfiguration and();
}
+ protected class ConfigurationSourceDetails implements ConfigRepositoryDetails {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
+ */
+ public ConfigRepositoryDetails describedAs( String description ) {
+ DnaConfiguration.this.configurationSource.description = description;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetProperties#with(java.lang.String)
+ */
+ public PropertySetter<ConfigRepositoryDetails> with( String propertyName ) {
+ return new BeanPropertySetter<ConfigRepositoryDetails>(DnaConfiguration.this.configurationSource.source,
+ propertyName, this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ConfigRepositoryDetails#under(java.lang.String)
+ */
+ public ConfigRepositoryDetails under( String path ) {
+ CheckArg.isNotNull(path, "path");
+ DnaConfiguration.this.configurationSource.path = context().getValueFactories().getPathFactory().create(path);
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
+ */
+ public DnaConfiguration and() {
+ return DnaConfiguration.this;
+ }
+ }
+
+ protected class GraphRepositoryDetails implements RepositoryDetails {
+ private final Path path;
+
+ protected GraphRepositoryDetails( Path path ) {
+ assert path != null;
+ this.path = path;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetName#named(java.lang.String)
+ */
+ public RepositoryDetails named( String name ) {
+ configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
+ */
+ public RepositoryDetails describedAs( String description ) {
+ configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetProperties#with(java.lang.String)
+ */
+ public PropertySetter<RepositoryDetails> with( String propertyName ) {
+ return new GraphPropertySetter<RepositoryDetails>(path, propertyName, this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
+ */
+ public DnaConfiguration and() {
+ return DnaConfiguration.this;
+ }
+ }
+
+ protected class GraphSequencerDetails implements SequencerDetails {
+ private final Path path;
+
+ protected GraphSequencerDetails( Path path ) {
+ assert path != null;
+ this.path = path;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SequencerDetails#sequencingFrom(java.lang.String)
+ */
+ public PathExpressionOutput sequencingFrom( final String from ) {
+ CheckArg.isNotEmpty(from, "from");
+ return new PathExpressionOutput() {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.PathExpressionOutput#andOutputtingTo(java.lang.String)
+ */
+ public SequencerDetails andOutputtingTo( String into ) {
+ CheckArg.isNotEmpty(into, "into");
+ return sequencingFrom(PathExpression.compile(from + " => " + into));
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetName#named(java.lang.String)
+ */
+ public SequencerDetails named( String name ) {
+ configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SequencerDetails#sequencingFrom(org.jboss.dna.graph.property.PathExpression)
+ */
+ public SequencerDetails sequencingFrom( PathExpression expression ) {
+ CheckArg.isNotNull(expression, "expression");
+ configuration().set(DnaLexicon.PATH_EXPRESSIONS).on(path).to(expression.getExpression());
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
+ */
+ public SequencerDetails describedAs( String description ) {
+ configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
+ */
+ public DnaConfiguration and() {
+ return DnaConfiguration.this;
+ }
+ }
+
+ protected class GraphMimeTypeDetectorDetails implements MimeTypeDetectorDetails {
+ private final Path path;
+
+ protected GraphMimeTypeDetectorDetails( Path path ) {
+ assert path != null;
+ this.path = path;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetName#named(java.lang.String)
+ */
+ public MimeTypeDetectorDetails named( String name ) {
+ configuration().set(DnaLexicon.READABLE_NAME).to(name).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetProperties#with(java.lang.String)
+ */
+ public PropertySetter<MimeTypeDetectorDetails> with( String propertyName ) {
+ return new GraphPropertySetter<MimeTypeDetectorDetails>(path, propertyName, this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
+ */
+ public MimeTypeDetectorDetails describedAs( String description ) {
+ configuration().set(DnaLexicon.DESCRIPTION).to(description).on(path);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
+ */
+ public DnaConfiguration and() {
+ return DnaConfiguration.this;
+ }
+ }
+
/**
* Abstract implementation of {@link ChooseClass} that has a single abstract method to obtain the interface that should be
* returned when the class name and classpath have been selected.
@@ -743,10 +818,17 @@
* @param <ReturnType> the interface that should be returned when the class name and classpath have been chosen.
* @author Randall Hauch
*/
- protected abstract class ClassChooser<ComponentClass, ReturnType> implements ChooseClass<ComponentClass, ReturnType> {
+ protected class ClassChooser<ComponentClass, ReturnType> implements ChooseClass<ComponentClass, ReturnType> {
+ protected final Path pathOfComponentNode;
+ protected final ReturnType returnObject;
- protected abstract ReturnType getComponentBuilder( String className,
- String... classpath );
+ protected ClassChooser( Path pathOfComponentNode,
+ ReturnType returnObject ) {
+ assert pathOfComponentNode != null;
+ assert returnObject != null;
+ this.pathOfComponentNode = pathOfComponentNode;
+ this.returnObject = returnObject;
+ }
/**
* {@inheritDoc}
@@ -755,13 +837,22 @@
*/
public LoadedFrom<ReturnType> usingClass( final String classname ) {
CheckArg.isNotEmpty(classname, "classname");
+ configuration().set(DnaLexicon.CLASSNAME).to(classname).on(pathOfComponentNode);
return new LoadedFrom<ReturnType>() {
public ReturnType loadedFromClasspath() {
- return getComponentBuilder(classname);
+ return returnObject;
}
public ReturnType loadedFrom( String... classpath ) {
- return getComponentBuilder(classname, classpath);
+ CheckArg.isNotEmpty(classpath, "classpath");
+ if (classpath.length == 1 && classpath[0] != null) {
+ configuration().set(DnaLexicon.CLASSPATH).to(classpath[0]).on(pathOfComponentNode);
+ } else {
+ Object[] remaining = new String[classpath.length - 1];
+ System.arraycopy(classpath, 1, remaining, 0, remaining.length);
+ configuration().set(DnaLexicon.CLASSPATH).to(classpath[0], remaining).on(pathOfComponentNode);
+ }
+ return returnObject;
}
};
}
@@ -773,34 +864,11 @@
*/
public ReturnType usingClass( Class<? extends ComponentClass> clazz ) {
CheckArg.isNotNull(clazz, "clazz");
- return getComponentBuilder(clazz.getName());
+ return usingClass(clazz.getName()).loadedFromClasspath();
}
}
/**
- * Utility method to instantiate a class.
- *
- * @param <T> the interface or superclass that the instantiated object is to implement
- * @param interfaceType the interface or superclass type that the instantiated object is to implement
- * @param className the name of the class
- * @param classloaderNames the names of the class loaders
- * @return the new instance
- */
- @SuppressWarnings( "unchecked" )
- protected <T> T instantiate( Class<T> interfaceType,
- String className,
- String... classloaderNames ) {
- // Load the class and create the instance ...
- try {
- Class<?> clazz = getExecutionContext().getClassLoader(classloaderNames).loadClass(className);
- return (T)clazz.newInstance();
- } catch (Throwable err) {
- I18n msg = RepositoryI18n.errorCreatingInstanceOfClass;
- throw new DnaConfigurationException(msg.text(className, err.getMessage()), err);
- }
- }
-
- /**
* Reusable implementation of {@link PropertySetter} that sets the JavaBean-style property using reflection.
*
* @param <ReturnType>
@@ -864,53 +932,96 @@
}
/**
- * Reusable implementation of {@link PropertySetter} that aggregates the properties to set to be placed into a map
+ * Reusable implementation of {@link PropertySetter} that sets the property on the specified node in the configuration graph.
*
* @param <ReturnType>
* @author Randall Hauch
*/
- protected class MappingPropertySetter<ReturnType extends ConfigurationBuilder> implements PropertySetter<ReturnType> {
+ protected class GraphPropertySetter<ReturnType> implements PropertySetter<ReturnType> {
+ private final Path path;
private final String beanPropertyName;
private final ReturnType returnObject;
- protected MappingPropertySetter( String beanPropertyName,
- ReturnType returnObject ) {
+ protected GraphPropertySetter( Path path,
+ String beanPropertyName,
+ ReturnType returnObject ) {
+ assert path != null;
assert beanPropertyName != null;
assert returnObject != null;
- this.beanPropertyName = beanPropertyName;
+ this.path = path;
+ this.beanPropertyName = Inflector.getInstance().lowerCamelCase(beanPropertyName);
this.returnObject = returnObject;
}
public ReturnType setTo( boolean value ) {
- return setTo((Object)value);
+ if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
+ configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
+ } else {
+ configuration().set(beanPropertyName).to(value).on(path);
+ }
+ return returnObject;
}
public ReturnType setTo( int value ) {
- return setTo((Object)value);
+ if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
+ configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
+ } else {
+ configuration().set(beanPropertyName).to(value).on(path);
+ }
+ return returnObject;
}
public ReturnType setTo( long value ) {
- return setTo((Object)value);
+ if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
+ configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
+ } else {
+ configuration().set(beanPropertyName).to(value).on(path);
+ }
+ return returnObject;
}
public ReturnType setTo( short value ) {
- return setTo((Object)value);
+ if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
+ configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
+ } else {
+ configuration().set(beanPropertyName).to(value).on(path);
+ }
+ return returnObject;
}
public ReturnType setTo( float value ) {
- return setTo((Object)value);
+ if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
+ configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
+ } else {
+ configuration().set(beanPropertyName).to(value).on(path);
+ }
+ return returnObject;
}
public ReturnType setTo( double value ) {
- return setTo((Object)value);
+ if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
+ configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
+ } else {
+ configuration().set(beanPropertyName).to(value).on(path);
+ }
+ return returnObject;
}
public ReturnType setTo( String value ) {
- return setTo((Object)value);
+ if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
+ configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
+ } else {
+ configuration().set(beanPropertyName).to(value).on(path);
+ }
+ return returnObject;
}
public ReturnType setTo( Object value ) {
- returnObject.getProperties().put(beanPropertyName, value);
+ if (NAMES_TO_MAP.containsKey(beanPropertyName)) {
+ configuration().set(NAMES_TO_MAP.get(beanPropertyName)).to(value).on(path);
+ } else {
+ configuration().set(beanPropertyName).to(value).on(path);
+ }
return returnObject;
}
}
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -21,23 +21,44 @@
*/
package org.jboss.dna.repository;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.collection.SimpleProblems;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.JcrMixLexicon;
+import org.jboss.dna.graph.JcrNtLexicon;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.Node;
+import org.jboss.dna.graph.Subgraph;
import org.jboss.dna.graph.connector.RepositoryConnection;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.repository.DnaConfiguration.DnaMimeTypeDetectorDetails;
-import org.jboss.dna.repository.DnaConfiguration.DnaRepositoryDetails;
-import org.jboss.dna.repository.DnaConfiguration.DnaSequencerDetails;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathExpression;
+import org.jboss.dna.graph.property.PathNotFoundException;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.repository.mimetype.MimeTypeDetectorConfig;
import org.jboss.dna.repository.observation.ObservationService;
+import org.jboss.dna.repository.sequencer.SequencerConfig;
import org.jboss.dna.repository.sequencer.SequencingService;
import org.jboss.dna.repository.service.AdministeredService;
+import org.jboss.dna.repository.util.JcrExecutionContext;
+import org.jboss.dna.repository.util.SessionFactory;
+import org.jboss.dna.repository.util.SimpleSessionFactory;
/**
* @author Randall Hauch
@@ -47,6 +68,7 @@
public static final String CONFIGURATION_REPOSITORY_NAME = "dna:configuration";
+ private final Problems problems;
private final ExecutionContext context;
private final List<AdministeredService> services;
@@ -58,33 +80,39 @@
private final RepositoryConnectionFactory connectionFactory;
DnaEngine( DnaConfiguration configuration ) {
- this.context = new ExecutionContext();
+ this.problems = new SimpleProblems();
- DnaRepositoryDetails configSource = configuration.repositories.get(CONFIGURATION_REPOSITORY_NAME);
- assert configSource != null : "Must specify a repository source named " + CONFIGURATION_REPOSITORY_NAME;
+ // Use the configuration's context ...
+ this.context = configuration.context();
- // Use a magic number for now
- executorService = new ScheduledThreadPoolExecutor(10);
+ // Add the configuration source to the repository library ...
+ final DnaConfiguration.Source configSourceInfo = configuration.configurationSource;
+ final RepositorySource configSource = configSourceInfo.source;
+ RepositoryLibrary library = new RepositoryLibrary();
+ library.addSource(configSource);
- observationService = null; // new ObservationService(null);
+ // Create the RepositoryService, pointing it to the configuration repository ...
+ Path pathToConfigurationRoot = configSourceInfo.path;
+ repositoryService = new RepositoryService(library, configSource.getName(), "", pathToConfigurationRoot, context);
- RepositoryLibrary library = new RepositoryLibrary();
- for (DnaRepositoryDetails details : configuration.repositories.values()) {
- // Adding configuration source to the library until proven wrong!
- library.addSource(details.getRepositorySource());
+ for (MimeTypeDetectorConfig config : loadMimeTypeDetectors(problems, context, configSourceInfo)) {
+ library.getMimeTypeDetectors().addDetector(config);
}
- for (DnaMimeTypeDetectorDetails details : configuration.mimeTypeDetectors.values()) {
- library.getMimeTypeDetectors().addDetector(details.getMimeTypeDetectorConfig());
- }
- repositoryService = new RepositoryService(library, configSource.getRepositorySource().getName(), "", context);
-
+ // Create the sequencing service ...
+ executorService = new ScheduledThreadPoolExecutor(10); // Use a magic number for now
sequencingService = new SequencingService();
+ SessionFactory sessionFactory = new SimpleSessionFactory();
+ JcrExecutionContext jcrContext = new JcrExecutionContext(context, sessionFactory, "");
+ sequencingService.setExecutionContext(jcrContext);
sequencingService.setExecutorService(executorService);
- for (DnaSequencerDetails details : configuration.sequencers.values()) {
- sequencingService.addSequencer(details.getSequencerConfig());
+ for (SequencerConfig sequencerConfig : loadSequencingConfigurations(problems, context, configSourceInfo)) {
+ sequencingService.addSequencer(sequencerConfig);
}
+ // Create the observation service ...
+ observationService = null; // new ObservationService(null);
+
this.services = Arrays.asList(new AdministeredService[] { /* observationService, */repositoryService, sequencingService,});
connectionFactory = new RepositoryConnectionFactory() {
@@ -99,6 +127,145 @@
};
}
+ protected static List<MimeTypeDetectorConfig> loadMimeTypeDetectors( Problems problems,
+ ExecutionContext context,
+ DnaConfiguration.Source source ) {
+ List<MimeTypeDetectorConfig> detectors = new ArrayList<MimeTypeDetectorConfig>();
+ Graph graph = Graph.create(source.source, context);
+ Path pathToSequencersNode = context.getValueFactories().getPathFactory().create(source.path,
+ DnaLexicon.MIME_TYPE_DETECTORS);
+ try {
+ Subgraph subgraph = graph.getSubgraphOfDepth(2).at(pathToSequencersNode);
+
+ Set<Name> skipProperties = new HashSet<Name>();
+ skipProperties.add(DnaLexicon.READABLE_NAME);
+ skipProperties.add(DnaLexicon.DESCRIPTION);
+ skipProperties.add(DnaLexicon.CLASSNAME);
+ skipProperties.add(DnaLexicon.CLASSPATH);
+ skipProperties.add(DnaLexicon.PATH_EXPRESSIONS);
+ Set<String> skipNamespaces = new HashSet<String>();
+ skipNamespaces.add(JcrLexicon.Namespace.URI);
+ skipNamespaces.add(JcrNtLexicon.Namespace.URI);
+ skipNamespaces.add(JcrMixLexicon.Namespace.URI);
+
+ for (Location sequencerLocation : subgraph.getRoot().getChildren()) {
+ Node sequencerNode = subgraph.getNode(sequencerLocation);
+ String name = stringValueOf(context, sequencerNode, DnaLexicon.READABLE_NAME);
+ String desc = stringValueOf(context, sequencerNode, DnaLexicon.DESCRIPTION);
+ String classname = stringValueOf(context, sequencerNode, DnaLexicon.CLASSNAME);
+ String[] classpath = stringValuesOf(context, sequencerNode, DnaLexicon.CLASSPATH);
+ Map<String, Object> properties = new HashMap<String, Object>();
+ for (Property property : sequencerNode.getProperties()) {
+ Name propertyName = property.getName();
+ if (skipNamespaces.contains(propertyName.getNamespaceUri())) continue;
+ if (skipProperties.contains(propertyName)) continue;
+ if (property.isSingle()) {
+ properties.put(propertyName.getLocalName(), property.getFirstValue());
+ } else {
+ properties.put(propertyName.getLocalName(), property.getValuesAsArray());
+ }
+ }
+ MimeTypeDetectorConfig config = new MimeTypeDetectorConfig(name, desc, properties, classname, classpath);
+ detectors.add(config);
+ }
+ } catch (PathNotFoundException e) {
+ // no detectors registered ...
+ }
+ return detectors;
+ }
+
+ protected static List<SequencerConfig> loadSequencingConfigurations( Problems problems,
+ ExecutionContext context,
+ DnaConfiguration.Source source ) {
+ List<SequencerConfig> configs = new ArrayList<SequencerConfig>();
+ Graph graph = Graph.create(source.source, context);
+ Path pathToSequencersNode = context.getValueFactories().getPathFactory().create(source.path, DnaLexicon.SEQUENCERS);
+ try {
+ Subgraph subgraph = graph.getSubgraphOfDepth(2).at(pathToSequencersNode);
+
+ Set<Name> skipProperties = new HashSet<Name>();
+ skipProperties.add(DnaLexicon.READABLE_NAME);
+ skipProperties.add(DnaLexicon.DESCRIPTION);
+ skipProperties.add(DnaLexicon.CLASSNAME);
+ skipProperties.add(DnaLexicon.CLASSPATH);
+ skipProperties.add(DnaLexicon.PATH_EXPRESSIONS);
+ Set<String> skipNamespaces = new HashSet<String>();
+ skipNamespaces.add(JcrLexicon.Namespace.URI);
+ skipNamespaces.add(JcrNtLexicon.Namespace.URI);
+ skipNamespaces.add(JcrMixLexicon.Namespace.URI);
+
+ for (Location sequencerLocation : subgraph.getRoot().getChildren()) {
+ Node sequencerNode = subgraph.getNode(sequencerLocation);
+ String name = stringValueOf(context, sequencerNode, DnaLexicon.READABLE_NAME);
+ String desc = stringValueOf(context, sequencerNode, DnaLexicon.DESCRIPTION);
+ String classname = stringValueOf(context, sequencerNode, DnaLexicon.CLASSNAME);
+ String[] classpath = stringValuesOf(context, sequencerNode, DnaLexicon.CLASSPATH);
+ String[] expressionStrings = stringValuesOf(context, sequencerNode, DnaLexicon.PATH_EXPRESSIONS);
+ List<PathExpression> pathExpressions = new ArrayList<PathExpression>();
+ if (expressionStrings != null) {
+ for (String expressionString : expressionStrings) {
+ try {
+ pathExpressions.add(PathExpression.compile(expressionString));
+ } catch (Throwable t) {
+ problems.addError(t,
+ RepositoryI18n.pathExpressionIsInvalidOnSequencer,
+ expressionString,
+ name,
+ t.getLocalizedMessage());
+ }
+ }
+ }
+ String[] goodExpressionStrings = new String[pathExpressions.size()];
+ for (int i = 0; i != pathExpressions.size(); ++i) {
+ PathExpression expression = pathExpressions.get(i);
+ goodExpressionStrings[i] = expression.getExpression();
+ }
+ Map<String, Object> properties = new HashMap<String, Object>();
+ for (Property property : sequencerNode.getProperties()) {
+ Name propertyName = property.getName();
+ if (skipNamespaces.contains(propertyName.getNamespaceUri())) continue;
+ if (skipProperties.contains(propertyName)) continue;
+ if (property.isSingle()) {
+ properties.put(propertyName.getLocalName(), property.getFirstValue());
+ } else {
+ properties.put(propertyName.getLocalName(), property.getValuesAsArray());
+ }
+ }
+ SequencerConfig config = new SequencerConfig(name, desc, properties, classname, classpath, goodExpressionStrings);
+ configs.add(config);
+ }
+ } catch (PathNotFoundException e) {
+ // no detectors registered ...
+ }
+ return configs;
+ }
+
+ private static String stringValueOf( ExecutionContext context,
+ Node node,
+ Name propertyName ) {
+ Property property = node.getProperty(propertyName);
+ if (property == null) return null;
+ if (property.isEmpty()) return null;
+ return context.getValueFactories().getStringFactory().create(property.getFirstValue());
+ }
+
+ private static String[] stringValuesOf( ExecutionContext context,
+ Node node,
+ Name propertyName ) {
+ Property property = node.getProperty(propertyName);
+ if (property == null) return null;
+ return context.getValueFactories().getStringFactory().create(property.getValuesAsArray());
+ }
+
+ /**
+ * Get the problems that were encountered when setting up this engine from the configuration.
+ *
+ * @return the problems, which may be empty but will never be null
+ */
+ public Problems getProblems() {
+ return problems;
+ }
+
/*
* Lookup methods
*/
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaLexicon.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaLexicon.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaLexicon.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -0,0 +1,45 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository;
+
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.basic.BasicName;
+
+/**
+ * @author Randall Hauch
+ */
+public class DnaLexicon extends org.jboss.dna.graph.DnaLexicon {
+
+ public static final Name SOURCES = new BasicName(Namespace.URI, "sources");
+ public static final Name SOURCE = new BasicName(Namespace.URI, "source");
+ public static final Name READABLE_NAME = new BasicName(Namespace.URI, "readableName");
+ public static final Name DESCRIPTION = new BasicName(Namespace.URI, "description");
+ public static final Name SEQUENCERS = new BasicName(Namespace.URI, "sequencers");
+ public static final Name SEQUENCER = new BasicName(Namespace.URI, "sequencer");
+ public static final Name PATH_EXPRESSIONS = new BasicName(Namespace.URI, "pathExpressions");
+ public static final Name MIME_TYPE_DETECTORS = new BasicName(Namespace.URI, "mimeTypeDetectors");
+ public static final Name MIME_TYPE_DETECTOR = new BasicName(Namespace.URI, "mimeTypeDetector");
+ public static final Name RETRY_LIMIT = new BasicName(Namespace.URI, "retryLimit");
+ public static final Name DEFAULT_CACHE_POLICY = new BasicName(Namespace.URI, "defaultCachePolicy");
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaLexicon.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -37,6 +37,7 @@
public static I18n errorCreatingInstanceOfClass;
public static I18n errorCreatingInstanceOfClassUsingClassLoaders;
public static I18n errorSettingJavaBeanPropertyOnInstanceOfClass;
+ public static I18n pathExpressionIsInvalidOnSequencer;
// Services and Repository
public static I18n invalidStateString;
@@ -113,6 +114,7 @@
// General
public static I18n invalidRepositoryNodePath;
+ public static I18n unableToLoadClass;
public static I18n unableToLoadClassUsingClasspath;
public static I18n unableToInstantiateClassUsingClasspath;
public static I18n unableToAccessClassUsingClasspath;
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -35,9 +35,9 @@
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.common.util.Reflection;
import org.jboss.dna.connector.federation.FederationException;
-import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.Node;
import org.jboss.dna.graph.Subgraph;
@@ -205,7 +205,8 @@
// Read the configuration and repository source nodes (children under "/dna:sources") ...
Graph graph = Graph.create(getConfigurationSourceName(), sources, context);
- Path pathToSourcesNode = context.getValueFactories().getPathFactory().create(pathToConfigurationRoot, "dna:sources");
+ Path pathToSourcesNode = context.getValueFactories().getPathFactory().create(pathToConfigurationRoot,
+ DnaLexicon.SOURCES);
try {
String workspaceName = getConfigurationWorkspaceName();
if (workspaceName != null) graph.useWorkspace(workspaceName);
@@ -266,14 +267,10 @@
problems.addError(err, RepositoryI18n.unableToInstantiateClassUsingClasspath, classname, classpath);
}
- // We need to set the name using the local name of the node, so hack this by putting another name property
- // into the map of properties. Since only the local name is used, we don't care what the namespace of the
- // fake property name is, so create something bogus. However, it really won't hurt if this happens to override an existing
- // property.
- String fakeUri = DnaLexicon.Namespace.URI + "/300939b9dg93kd9gb";
- Name nameName = context.getValueFactories().getNameFactory().create(fakeUri, "name");
- Property nameProperty = context.getPropertyFactory().create(nameName, path.getLastSegment().getName().getLocalName());
- properties.put(nameName, nameProperty);
+ // We need to set the name using the local name of the node...
+ Property nameProperty = context.getPropertyFactory().create(JcrLexicon.NAME,
+ path.getLastSegment().getName().getLocalName());
+ properties.put(JcrLexicon.NAME, nameProperty);
// Now set all the properties that we can, ignoring any property that doesn't fit the pattern ...
Reflection reflection = new Reflection(source.getClass());
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SimpleSessionFactory.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SimpleSessionFactory.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SimpleSessionFactory.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -34,21 +34,9 @@
import org.jboss.dna.repository.RepositoryI18n;
/**
- * A SessionFactory implementation that creates {@link Session} instances using {@link Repository} instances registered in JNDI.
+ * A SessionFactory implementation that creates {@link Session} instances from a map of named {@link Repository} references
+ * managed by this factory.
* <p>
- * This factory using a naming convention where the name supplied to the {@link #createSession(String)} contains both the name of
- * the repository and the name of the workspace. Typically, this is <i><code>repositoryName/workspaceName</code></i>, where
- * <code>repositoryName</code> is the JNDI name under which the Repository instance was bound, and <code>workspaceName</code>
- * is the name of the workspace. Note that this method looks for the last delimiter in the whole name to distinguish between the
- * repository and workspace names.
- * </p>
- * <p>
- * For example, if "<code>java:comp/env/repository/dataRepository/myWorkspace</code>" is passed to the
- * {@link #createSession(String)} method, this factory will look for a {@link Repository} instance registered in JDNI with the
- * name "<code>java:comp/env/repository/dataRepository</code>" and use it to {@link Repository#login(String) create a session}
- * to the workspace named "<code>myWorkspace</code>".
- * </p>
- * <p>
* By default, this factory creates an anonymous JCR session. To use sessions with specific {@link Credentials}, simply
* {@link #registerCredentials(String, Credentials) register} credentials for the appropriate repository/workspace name. For
* security reasons, it is not possible to retrieve the Credentials once registered with this factory.
Modified: trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
===================================================================
--- trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2009-04-23 16:43:27 UTC (rev 849)
@@ -24,6 +24,7 @@
errorCreatingInstanceOfClass = Attempt to create instance of {0} resulted in error: {1}
errorCreatingInstanceOfClassUsingClassLoaders = Attempt to create instance of {0} using classloader path {1} resulted in error: {2}
errorSettingJavaBeanPropertyOnInstanceOfClass = Attempt to set {0} property on {1} instance resulted in error: {2}
+pathExpressionIsInvalidOnSequencer = The path expression "{0}" is invalid on the "{1}" sequencer: {2}
invalidStateString = Invalid state parameter "{0}"
serviceShutdowAndMayNotBeStarted = The {0} has been shutdown and may not be (re)started
@@ -93,6 +94,7 @@
errorUnregisteringWorkspaceListenerWhileShuttingDownObservationService = Error unregistering workspace listener while shutting down observation service
invalidRepositoryNodePath = The repository node path "{0}" is not valid: {1}
+unableToLoadClass = Unable to load class "{0}"
unableToLoadClassUsingClasspath = Unable to load class "{0}" using classpath "{1}"
unableToInstantiateClassUsingClasspath = Unable to instantiate class "{0}" using classpath "{1}"
unableToAccessClassUsingClasspath = Unable to access class "{0}" using classpath "{1}"
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -24,16 +24,18 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsNull.nullValue;
+import static org.jboss.dna.graph.IsNodeWithChildren.hasChild;
+import static org.jboss.dna.graph.IsNodeWithProperty.hasProperty;
import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
+import java.util.UUID;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.Subgraph;
+import org.jboss.dna.graph.cache.CachePolicy;
+import org.jboss.dna.graph.cache.ImmutableCachePolicy;
import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
-import org.jboss.dna.graph.mimetype.MimeTypeDetector;
-import org.jboss.dna.repository.DnaConfiguration.DnaSequencerDetails;
+import org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector;
+import org.jboss.dna.graph.property.Path;
import org.jboss.dna.repository.sequencer.MockSequencerA;
-import org.jboss.dna.repository.sequencer.MockSequencerB;
import org.junit.Before;
import org.junit.Test;
@@ -51,6 +53,10 @@
configuration = new DnaConfiguration();
}
+ protected Path.Segment segment( String segment ) {
+ return context.getValueFactories().getPathFactory().createSegment(segment);
+ }
+
@Test
public void shouldAllowCreatingWithNoArguments() {
configuration = new DnaConfiguration();
@@ -62,6 +68,11 @@
}
@Test
+ public void shouldHaveDefaultConfigurationSourceIfNotSpecified() {
+ assertThat(configuration.graph(), is(notNullValue()));
+ }
+
+ @Test
public void shouldAllowSpecifyingConfigurationRepository() {
DnaConfiguration config = configuration.withConfigurationRepository()
.usingClass("org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource")
@@ -71,145 +82,225 @@
.setTo(5)
.with("name")
.setTo("repository name")
- .and();
+ .and()
+ .save();
assertThat(config, is(notNullValue()));
- assertThat(config.repositories.get(null), is(nullValue()));
+ assertThat(config.configurationSource.source, is(instanceOf(InMemoryRepositorySource.class)));
+ InMemoryRepositorySource source = (InMemoryRepositorySource)config.configurationSource.source;
+ assertThat(source.getName(), is("repository name"));
+ assertThat(source.getRetryLimit(), is(5));
}
@Test
public void shouldAllowAddingRepositorySourceInstance() {
- RepositorySource newSource = mock(RepositorySource.class);
- configuration.addRepository(newSource);
+ UUID rootUuid = UUID.randomUUID();
+ CachePolicy cachePolicy = new ImmutableCachePolicy(100);
+ InMemoryRepositorySource newSource = new InMemoryRepositorySource();
+ newSource.setName("name");
+ newSource.setDefaultCachePolicy(cachePolicy);
+ newSource.setDefaultWorkspaceName("default workspace name");
+ newSource.setRetryLimit(100);
+ newSource.setRootNodeUuid(rootUuid);
+
+ // Update the configuration and save it ...
+ configuration.addRepository(newSource).save();
+
+ // Verify that the graph has been updated correctly ...
+ Subgraph subgraph = configuration.graph().getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph.getNode("/dna:sources"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/name"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/name"), hasProperty(DnaLexicon.READABLE_NAME, "name"));
+ assertThat(subgraph.getNode("/dna:sources/name"), hasProperty(DnaLexicon.RETRY_LIMIT, 100));
+ assertThat(subgraph.getNode("/dna:sources/name"), hasProperty(DnaLexicon.DEFAULT_CACHE_POLICY, cachePolicy));
+ assertThat(subgraph.getNode("/dna:sources/name"), hasProperty("defaultWorkspaceName", "default workspace name"));
+ assertThat(subgraph.getNode("/dna:sources/name"), hasProperty("rootNodeUuid", rootUuid));
}
@Test
public void shouldAllowAddingRepositorySourceByClassNameAndSettingProperties() {
- DnaConfiguration config = configuration.addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME)
- .usingClass("org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource")
- .loadedFromClasspath()
- .describedAs("description")
- .with("retryLimit")
- .setTo(5)
- .with("name")
- .setTo("repository name")
- .and();
- assertThat(config, is(notNullValue()));
+ // Update the configuration and save it ...
+ configuration.addRepository("Source1")
+ .usingClass(InMemoryRepositorySource.class.getName())
+ .loadedFromClasspath()
+ .describedAs("description")
+ .with("retryLimit")
+ .setTo(5)
+ .and()
+ .save();
- RepositorySource source = config.repositories.get(DnaEngine.CONFIGURATION_REPOSITORY_NAME).getRepositorySource();
- assertThat(source, is(notNullValue()));
- assertThat(source, is(instanceOf(InMemoryRepositorySource.class)));
+ // Verify that the graph has been updated correctly ...
+ Subgraph subgraph = configuration.graph().getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph.getNode("/dna:sources"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.READABLE_NAME, "Source1"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.RETRY_LIMIT, 5));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.CLASSNAME,
+ InMemoryRepositorySource.class.getName()));
+ }
- InMemoryRepositorySource isource = (InMemoryRepositorySource)source;
- assertThat(isource.getRetryLimit(), is(5));
- assertThat(isource.getName(), is("repository name"));
+ @Test
+ public void shouldAllowAddingRepositorySourceByClassNameAndClasspathAndSettingProperties() {
+ // Update the configuration and save it ...
+ configuration.addRepository("Source1")
+ .usingClass(InMemoryRepositorySource.class.getName())
+ .loadedFrom("cp1", "cp2")
+ .describedAs("description")
+ .with("retryLimit")
+ .setTo(5)
+ .and()
+ .save();
+
+ // Verify that the graph has been updated correctly ...
+ Subgraph subgraph = configuration.graph().getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph.getNode("/dna:sources"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.READABLE_NAME, "Source1"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.RETRY_LIMIT, 5));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.CLASSNAME,
+ InMemoryRepositorySource.class.getName()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.CLASSPATH, "cp1", "cp2"));
}
@Test
public void shouldAllowAddingRepositorySourceByClassReferenceAndSettingProperties() {
- DnaConfiguration config = configuration.addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME)
- .usingClass(InMemoryRepositorySource.class)
- .describedAs("description")
- .with("retryLimit")
- .setTo(5)
- .with("name")
- .setTo("repository name")
- .and();
+ // Update the configuration and save it ...
+ configuration.addRepository("Source1")
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("description")
+ .with("retryLimit")
+ .setTo(5)
+ .and()
+ .save();
- assertThat(config, is(notNullValue()));
- assertThat(config.repositories.get(null), is(nullValue()));
-
- RepositorySource source = config.repositories.get(DnaEngine.CONFIGURATION_REPOSITORY_NAME).getRepositorySource();
- assertThat(source, is(notNullValue()));
- assertThat(source, is(instanceOf(InMemoryRepositorySource.class)));
-
- InMemoryRepositorySource isource = (InMemoryRepositorySource)source;
- assertThat(isource.getRetryLimit(), is(5));
- assertThat(isource.getName(), is("repository name"));
+ // Verify that the graph has been updated correctly ...
+ Subgraph subgraph = configuration.graph().getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph.getNode("/dna:sources"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.READABLE_NAME, "Source1"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.RETRY_LIMIT, 5));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.DESCRIPTION, "description"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.CLASSNAME,
+ InMemoryRepositorySource.class.getName()));
}
@Test
public void shouldAllowOverwritingRepositorySourceByRepositoryName() {
- DnaConfiguration config = configuration.addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME)
- .usingClass(InMemoryRepositorySource.class)
- .describedAs("description")
- .with("retryLimit")
- .setTo(3)
- .and()
- .addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME)
- .usingClass(InMemoryRepositorySource.class)
- .describedAs("description")
- .with("name")
- .setTo("repository name")
- .and();
+ // Update the configuration and save it ...
+ configuration.addRepository("Source1")
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("description")
+ .with("retryLimit")
+ .setTo(3)
+ .and()
+ .addRepository("Source1")
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("new description")
+ .with("retryLimit")
+ .setTo(6)
+ .and()
+ .save();
- assertThat(config, is(notNullValue()));
- assertThat(config.repositories.get(null), is(nullValue()));
-
- RepositorySource source = config.repositories.get(DnaEngine.CONFIGURATION_REPOSITORY_NAME).getRepositorySource();
- assertThat(source, is(notNullValue()));
- assertThat(source, is(instanceOf(InMemoryRepositorySource.class)));
-
- InMemoryRepositorySource isource = (InMemoryRepositorySource)source;
- // This relies on the default retry limit for an InMemoryRepositorySource being 0
- // If the original source was not overwritten, this would be 3
- assertThat(isource.getRetryLimit(), is(0));
- assertThat(isource.getName(), is("repository name"));
+ // Verify that the graph has been updated correctly ...
+ Subgraph subgraph = configuration.graph().getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph.getNode("/dna:sources"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources").getChildren(), hasChild(segment("Source1")));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.READABLE_NAME, "Source1"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.RETRY_LIMIT, 6));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.DESCRIPTION, "new description"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.CLASSNAME,
+ InMemoryRepositorySource.class.getName()));
}
@Test
public void shouldAllowAddingMimeTypeDetector() {
- RepositorySource newSource = mock(RepositorySource.class);
- MimeTypeDetector newDetector = mock(MimeTypeDetector.class);
- DnaConfiguration config = configuration.addRepository(newSource)
- .addMimeTypeDetector("default")
- .usingClass(newDetector.getClass())
- .describedAs("default mime type detector")
- .and();
+ // Update the configuration and save it ...
+ configuration.addRepository("Source1")
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("description")
+ .and()
+ .addMimeTypeDetector("detector")
+ .usingClass(ExtensionBasedMimeTypeDetector.class)
+ .describedAs("default detector")
+ .and()
+ .save();
- assertThat(config, is(notNullValue()));
- assertThat(config.mimeTypeDetectors.get("default").getMimeTypeDetector(), instanceOf(MimeTypeDetector.class));
- assertThat(config.mimeTypeDetectors.get("invalid name"), is(nullValue()));
- assertThat(config.mimeTypeDetectors.get("default").getDescription(), is("default mime type detector"));
+ // Verify that the graph has been updated correctly ...
+ Subgraph subgraph = configuration.graph().getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph.getNode("/dna:sources").getChildren(), hasChild(segment("Source1")));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.READABLE_NAME, "Source1"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.DESCRIPTION, "description"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.CLASSNAME,
+ InMemoryRepositorySource.class.getName()));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors").getChildren(), hasChild(segment("detector")));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors/detector"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors/detector"), hasProperty(DnaLexicon.READABLE_NAME, "detector"));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors/detector"), hasProperty(DnaLexicon.DESCRIPTION, "default detector"));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors/detector"),
+ hasProperty(DnaLexicon.CLASSNAME, ExtensionBasedMimeTypeDetector.class.getName()));
}
@Test
public void shouldAllowAddingSequencer() {
- RepositorySource newSource = mock(RepositorySource.class);
+ // Update the configuration and save it ...
+ configuration.addRepository("Source1")
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("description")
+ .named("A Source")
+ .and()
+ .addSequencer("sequencerA")
+ .usingClass(MockSequencerA.class)
+ .named("The (Main) Sequencer")
+ .describedAs("Mock Sequencer A")
+ // .sequencingFrom("/foo/source")
+ // .andOutputtingTo("/foo/target")
+ .sequencingFrom("/bar/source")
+ .andOutputtingTo("/bar/target")
+ .and()
+ .save();
- DnaConfiguration config = configuration.addRepository(newSource)
- .addSequencer("sequencerA")
- .usingClass(MockSequencerA.class)
- .describedAs("Mock Sequencer A")
- .sequencingFrom("/foo/source")
- .andOutputtingTo("/foo/target")
- .sequencingFrom("/bar/source")
- .andOutputtingTo("/bar/target")
- .and()
- .addSequencer("sequencerB")
- .usingClass(MockSequencerB.class)
- .sequencingFrom("/baz/source")
- .andOutputtingTo("/baz/target")
- .describedAs("Mock Sequencer B")
- .and();
+ // Verify that the graph has been updated correctly ...
+ Subgraph subgraph = configuration.graph().getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph.getNode("/dna:sources").getChildren(), hasChild(segment("Source1")));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.READABLE_NAME, "A Source"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.DESCRIPTION, "description"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.CLASSNAME,
+ InMemoryRepositorySource.class.getName()));
+ assertThat(subgraph.getNode("/dna:sequencers").getChildren(), hasChild(segment("sequencerA")));
+ assertThat(subgraph.getNode("/dna:sequencers/sequencerA"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sequencers/sequencerA"), hasProperty(DnaLexicon.READABLE_NAME, "The (Main) Sequencer"));
+ assertThat(subgraph.getNode("/dna:sequencers/sequencerA"), hasProperty(DnaLexicon.DESCRIPTION, "Mock Sequencer A"));
+ assertThat(subgraph.getNode("/dna:sequencers/sequencerA"), hasProperty(DnaLexicon.CLASSNAME,
+ MockSequencerA.class.getName()));
+ System.out.println(subgraph.getNode("/dna:sequencers/sequencerA").getProperty(DnaLexicon.PATH_EXPRESSIONS));
+ assertThat(subgraph.getNode("/dna:sequencers/sequencerA"), hasProperty(DnaLexicon.PATH_EXPRESSIONS,
+ // "/foo/source => /foo/target",
+ "/bar/source => /bar/target"));
+ }
- assertThat(config, is(notNullValue()));
- assertThat(config.sequencers.get("default"), is(nullValue()));
- assertThat(config.sequencers.get("sequencerA").getSequencer(), instanceOf(MockSequencerA.class));
- assertThat(config.sequencers.get("sequencerB").getSequencer(), instanceOf(MockSequencerB.class));
+ @Test
+ public void shouldAllowConfigurationInMultipleSteps() {
+ configuration.addRepository("Source1").usingClass(InMemoryRepositorySource.class).describedAs("description");
+ configuration.addMimeTypeDetector("detector")
+ .usingClass(ExtensionBasedMimeTypeDetector.class)
+ .describedAs("default detector");
+ configuration.save();
- DnaSequencerDetails detailsA = config.sequencers.get("sequencerA");
- assertThat(detailsA.getDescription(), is("Mock Sequencer A"));
- assertThat(detailsA.sourcePathExpressions.size(), is(2));
- assertThat(detailsA.sourcePathExpressions.get(0).toString(), is("/foo/source"));
- assertThat(detailsA.targetPathExpressions.get(0).toString(), is("/foo/target"));
- assertThat(detailsA.sourcePathExpressions.get(1).toString(), is("/bar/source"));
- assertThat(detailsA.targetPathExpressions.get(1).toString(), is("/bar/target"));
-
- DnaSequencerDetails detailsB = config.sequencers.get("sequencerB");
- assertThat(detailsB.getDescription(), is("Mock Sequencer B"));
- assertThat(detailsB.sourcePathExpressions.size(), is(1));
- assertThat(detailsB.sourcePathExpressions.get(0).toString(), is("/baz/source"));
- assertThat(detailsB.targetPathExpressions.get(0).toString(), is("/baz/target"));
+ // Verify that the graph has been updated correctly ...
+ Subgraph subgraph = configuration.graph().getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph.getNode("/dna:sources").getChildren(), hasChild(segment("Source1")));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.READABLE_NAME, "Source1"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.DESCRIPTION, "description"));
+ assertThat(subgraph.getNode("/dna:sources/Source1"), hasProperty(DnaLexicon.CLASSNAME,
+ InMemoryRepositorySource.class.getName()));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors").getChildren(), hasChild(segment("detector")));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors/detector"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors/detector"), hasProperty(DnaLexicon.READABLE_NAME, "detector"));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors/detector"), hasProperty(DnaLexicon.DESCRIPTION, "default detector"));
+ assertThat(subgraph.getNode("/dna:mimeTypeDetectors/detector"),
+ hasProperty(DnaLexicon.CLASSNAME, ExtensionBasedMimeTypeDetector.class.getName()));
}
-
}
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java 2009-04-23 16:29:28 UTC (rev 848)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java 2009-04-23 16:43:27 UTC (rev 849)
@@ -63,12 +63,13 @@
@Test
public void shouldAllowCreatingWithConfigRepository() throws InterruptedException {
- engine = new DnaConfiguration()
- .withConfigurationRepository()
- .usingClass(InMemoryRepositorySource.class)
- .describedAs("Configuration Repository")
- .with("name").setTo("config repo")
- .and().build();
+ engine = new DnaConfiguration().withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Configuration Repository")
+ .with("name")
+ .setTo("config repo")
+ .and()
+ .build();
assertThat(engine.getRepositorySource("config repo"), is(notNullValue()));
assertThat(engine.getRepositorySource("config repo"), is(instanceOf(InMemoryRepositorySource.class)));
@@ -84,17 +85,23 @@
@Test
public void shouldAllowCreatingMultipleRepositories() throws Exception {
- engine = new DnaConfiguration()
- .withConfigurationRepository()
- .usingClass(InMemoryRepositorySource.class)
- .describedAs("Configuration Repository")
- .with("name").setTo("config repo")
- .and().addRepository("JCR")
- .usingClass(InMemoryRepositorySource.class)
- .describedAs("Backing Repository for JCR Implementation")
- .with("name").setTo("JCR")
- .and().build();
+ engine = new DnaConfiguration().withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Configuration Repository")
+ .with("name")
+ .setTo("config repo")
+ .and()
+ .addRepository("JCR")
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Backing Repository for JCR Implementation")
+ .with("name")
+ .setTo("JCR")
+ .and()
+ .build();
+ // Start the engine ...
+ engine.start();
+ // Verify the components are here ...
assertThat(engine.getRepositorySource("config repo"), is(notNullValue()));
assertThat(engine.getRepositorySource("config repo"), is(instanceOf(InMemoryRepositorySource.class)));
@@ -111,46 +118,52 @@
@Test
public void shouldAllowAddingMimeTypeDetectors() throws Exception {
- engine = new DnaConfiguration()
- .withConfigurationRepository()
- .usingClass(InMemoryRepositorySource.class)
- .describedAs("Configuration Repository")
- .with("name").setTo("config repo")
- .and().addMimeTypeDetector("default")
- .usingClass(MockMimeTypeDetector.class)
- .describedAs("Default MimeTypeDetector")
- .with("mimeType").setTo("mock")
- .and().build();
+ engine = new DnaConfiguration().withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Configuration Repository")
+ .with("name")
+ .setTo("config repo")
+ .and()
+ .addMimeTypeDetector("default")
+ .usingClass(MockMimeTypeDetector.class)
+ .describedAs("Default MimeTypeDetector")
+ .with("mimeType")
+ .setTo("mock")
+ .and()
+ .build();
assertThat(engine.getRepositorySource("config repo"), is(notNullValue()));
assertThat(engine.getRepositorySource("config repo"), is(instanceOf(InMemoryRepositorySource.class)));
RepositoryLibrary library = engine.getRepositoryService().getRepositorySourceManager();
MimeTypeDetectors detectors = library.getMimeTypeDetectors();
-
+
assertThat(detectors.mimeTypeOf("test", new ByteArrayInputStream("This is useless data".getBytes())), is("mock"));
}
-
+
@Test
public void shouldAllowAddingSequencers() throws Exception {
- engine = new DnaConfiguration()
- .withConfigurationRepository()
- .usingClass(InMemoryRepositorySource.class)
- .describedAs("Configuration Repository")
- .with("name").setTo("config repo")
- .and().addSequencer("Mock Sequencer A")
- .usingClass(MockSequencerA.class)
- .describedAs("A Mock Sequencer")
- .sequencingFrom("/**").andOutputtingTo("/")
- .and().build();
+ engine = new DnaConfiguration().withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Configuration Repository")
+ .with("name")
+ .setTo("config repo")
+ .and()
+ .addSequencer("Mock Sequencer A")
+ .usingClass(MockSequencerA.class)
+ .describedAs("A Mock Sequencer")
+ .sequencingFrom("/**")
+ .andOutputtingTo("/")
+ .and()
+ .build();
assertThat(engine.getRepositorySource("config repo"), is(notNullValue()));
assertThat(engine.getRepositorySource("config repo"), is(instanceOf(InMemoryRepositorySource.class)));
SequencingService sequencer = engine.getSequencingService();
assertThat(sequencer.getStatistics().getNumberOfNodesSequenced(), is(0L));
-
- NodeChanges changes = NodeChanges.create("", Arrays.asList(new Event[] { }));
+
+ NodeChanges changes = NodeChanges.create("", Arrays.asList(new Event[] {}));
sequencer.onNodeChanges(changes);
assertThat(sequencer.getStatistics().getNumberOfNodesSequenced(), is(0L));
@@ -159,33 +172,32 @@
stub(e1.getType()).toReturn(Event.NODE_ADDED);
stub(e1.getPath()).toReturn("/test");
stub(e1.getUserID()).toReturn("Test");
-
-// changes = NodeChanges.create("", Arrays.asList(new Event[] { e1, }));
-// sequencer.onNodeChanges(changes);
-//
-// // Shutdown the engine to force all pending tasks to complete
-// engine.shutdown();
-//
-// assertThat(sequencer.getStatistics().getNumberOfNodesSequenced(), is(1L));
- }
+ // changes = NodeChanges.create("", Arrays.asList(new Event[] { e1, }));
+ // sequencer.onNodeChanges(changes);
+ //
+ // // Shutdown the engine to force all pending tasks to complete
+ // engine.shutdown();
+ //
+ // assertThat(sequencer.getStatistics().getNumberOfNodesSequenced(), is(1L));
+ }
+
public static class MockMimeTypeDetector implements MimeTypeDetector {
private String mimeType = "";
-
+
public MockMimeTypeDetector() {
-
+
}
- public void setMimeType(String mimeType) {
+ public void setMimeType( String mimeType ) {
this.mimeType = mimeType;
}
-
+
public String mimeTypeOf( String name,
InputStream is ) {
return mimeType;
}
}
-
}
17 years
DNA SVN: r848 - trunk/dna-graph/src/main/java/org/jboss/dna/graph.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-23 12:29:28 -0400 (Thu, 23 Apr 2009)
New Revision: 848
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
Log:
DNA-381 The Graph API should allow creating a node if it does not already exist
Added "createIfMissing(...)" methods that mirror the "create(...)" methods, but which use a different NodeConflictBehavior setting.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-04-23 16:25:30 UTC (rev 847)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-04-23 16:29:28 UTC (rev 848)
@@ -945,7 +945,8 @@
}
/**
- * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
+ * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
+ * the repository immediately.
* <p>
* If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
* to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
@@ -966,6 +967,131 @@
}
/**
+ * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
+ * the repository immediately.
+ * <p>
+ * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
+ * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
+ * parent or new node.
+ * </p>
+ *
+ * @param atPath the path to the node that is to be created.
+ * @return an object that may be used to start another request
+ */
+ public GetNodeConjunction<Graph> createIfMissing( String atPath ) {
+ Path at = createPath(atPath);
+ Path parent = at.getParent();
+ Name child = at.getLastSegment().getName();
+ Location location = requests.createNode(Location.create(parent),
+ getCurrentWorkspaceName(),
+ child,
+ EMPTY_PROPERTIES,
+ NodeConflictBehavior.DO_NOT_REPLACE).getActualLocationOfNode();
+ return new GetNodeOrReturnGraph(location);
+ }
+
+ /**
+ * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
+ * the repository immediately.
+ * <p>
+ * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
+ * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
+ * parent or new node.
+ * </p>
+ *
+ * @param at the path to the node that is to be created.
+ * @return an object that may be used to start another request
+ */
+ public GetNodeConjunction<Graph> createIfMissing( final Path at ) {
+ Path parent = at.getParent();
+ Name child = at.getLastSegment().getName();
+ Location location = requests.createNode(Location.create(parent),
+ getCurrentWorkspaceName(),
+ child,
+ EMPTY_PROPERTIES,
+ NodeConflictBehavior.DO_NOT_REPLACE).getActualLocationOfNode();
+ return new GetNodeOrReturnGraph(location);
+ }
+
+ /**
+ * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
+ * the repository immediately.
+ * <p>
+ * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
+ * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
+ * parent or new node.
+ * </p>
+ *
+ * @param atPath the path to the node that is to be created.
+ * @param properties the properties for the new node
+ * @return an object that may be used to start another request
+ */
+ public GetNodeConjunction<Graph> createIfMissing( String atPath,
+ Property... properties ) {
+ Path at = createPath(atPath);
+ Path parent = at.getParent();
+ Name child = at.getLastSegment().getName();
+ Location location = requests.createNode(Location.create(parent),
+ getCurrentWorkspaceName(),
+ child,
+ properties,
+ NodeConflictBehavior.UPDATE).getActualLocationOfNode();
+ return new GetNodeOrReturnGraph(location);
+ }
+
+ /**
+ * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
+ * the repository immediately.
+ * <p>
+ * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
+ * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
+ * parent or new node.
+ * </p>
+ *
+ * @param at the path to the node that is to be created.
+ * @param properties the properties for the new node
+ * @return an object that may be used to start another request
+ */
+ public GetNodeConjunction<Graph> createIfMissing( Path at,
+ Property... properties ) {
+ CheckArg.isNotNull(at, "at");
+ Path parent = at.getParent();
+ Name child = at.getLastSegment().getName();
+ Location location = requests.createNode(Location.create(parent),
+ getCurrentWorkspaceName(),
+ child,
+ properties,
+ NodeConflictBehavior.UPDATE).getActualLocationOfNode();
+ return new GetNodeOrReturnGraph(location);
+ }
+
+ /**
+ * Begin the request to create a node located at the supplied path, if the node does not exist. This request is submitted to
+ * the repository immediately.
+ * <p>
+ * If you have the {@link Location} of the parent (for the new node) from a previous request, it is better and more efficient
+ * to use {@link #createUnder(Location)}. However, this method work just as well if all you have is the {@link Path} to the
+ * parent or new node.
+ * </p>
+ *
+ * @param at the path to the node that is to be created.
+ * @param properties the properties for the new node
+ * @return an object that may be used to start another request
+ */
+ public GetNodeConjunction<Graph> createIfMissing( Path at,
+ Iterable<Property> properties ) {
+ CheckArg.isNotNull(at, "at");
+ Path parent = at.getParent();
+ Name child = at.getLastSegment().getName();
+ Location location = requests.createNode(Location.create(parent),
+ getCurrentWorkspaceName(),
+ child,
+ properties.iterator(),
+ NodeConflictBehavior.UPDATE).getActualLocationOfNode();
+ return new GetNodeOrReturnGraph(location);
+ }
+
+ /**
* Begin the request to create a node under the existing parent node at the supplied location. Use this method if you are
* creating a node when you have the {@link Location} of a parent from a previous request.
* <p>
@@ -2901,11 +3027,12 @@
public On<BatchConjunction> to( Object firstValue,
Object... otherValues ) {
- firstValue = convertReferenceValue(firstValue);
+ Object[] values = new Object[otherValues.length + 1];
+ values[0] = convertReferenceValue(firstValue);
for (int i = 0, len = otherValues.length; i != len; ++i) {
- otherValues[i] = convertReferenceValue(otherValues[i]);
+ values[i + 1] = convertReferenceValue(otherValues[i]);
}
- return set(getContext().getPropertyFactory().create(propertyName, firstValue, otherValues));
+ return set(getContext().getPropertyFactory().create(propertyName, values));
}
public On<BatchConjunction> to( Iterable<?> values ) {
@@ -4699,6 +4826,37 @@
public interface BatchConjunction extends Conjunction<Batch>, Executable<Node> {
}
+ public interface GetNodeConjunction<Next> extends Conjunction<Next> {
+ Node andReturn();
+ }
+
+ protected class GetNodeOrReturnGraph implements GetNodeConjunction<Graph> {
+ private final Location location;
+
+ GetNodeOrReturnGraph( Location location ) {
+ assert location != null;
+ this.location = location;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.Graph.Conjunction#and()
+ */
+ public Graph and() {
+ return Graph.this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.Graph.GetNodeConjunction#andReturn()
+ */
+ public Node andReturn() {
+ return and().getNodeAt(location);
+ }
+ }
+
// ----------------------------------------------------------------------------------------------------------------
// Node Implementation
// ----------------------------------------------------------------------------------------------------------------
17 years
DNA SVN: r847 - trunk/dna-common/src/main/java/org/jboss/dna/common/text.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-23 12:25:30 -0400 (Thu, 23 Apr 2009)
New Revision: 847
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/text/Inflector.java
Log:
DNA-380 The inflector is not lowercasing the first character in the 'camelCase(...)' method
Corrected the camelCase(...) method to lowercase the first character per the JavaDoc.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/text/Inflector.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/text/Inflector.java 2009-04-22 14:05:41 UTC (rev 846)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/text/Inflector.java 2009-04-23 16:25:30 UTC (rev 847)
@@ -297,14 +297,13 @@
return replaceAllWithUppercase(result, "(^|_)(.)", 2);
}
if (lowerCaseAndUnderscoredWord.length() < 2) return lowerCaseAndUnderscoredWord;
- return "" + lowerCaseAndUnderscoredWord.charAt(0)
+ return "" + Character.toLowerCase(lowerCaseAndUnderscoredWord.charAt(0))
+ camelCase(lowerCaseAndUnderscoredWord, true, delimiterChars).substring(1);
}
/**
- * Makes an underscored form from the expression in the string (the reverse of the
- * {@link #camelCase(String, boolean, char[]) camelCase} method. Also changes any characters that match the supplied
- * delimiters into underscore.
+ * Makes an underscored form from the expression in the string (the reverse of the {@link #camelCase(String, boolean, char[])
+ * camelCase} method. Also changes any characters that match the supplied delimiters into underscore.
* <p>
* Examples:
*
@@ -491,9 +490,9 @@
* other backreferences.
* <p>
* The Java {@link Pattern regular expression processing} does not use the preprocessing directives <code>\l</code>,
- * <code>\u</code>, <code>\L</code>, and <code>\U</code>. If so, such directives could be used in the replacement
- * string to uppercase or lowercase the backreferences. For example, <code>\L1</code> would lowercase the first
- * backreference, and <code>\u3</code> would uppercase the 3rd backreference.
+ * <code>\u</code>, <code>\L</code>, and <code>\U</code>. If so, such directives could be used in the replacement string
+ * to uppercase or lowercase the backreferences. For example, <code>\L1</code> would lowercase the first backreference, and
+ * <code>\u3</code> would uppercase the 3rd backreference.
* </p>
*
* @param input
17 years
DNA SVN: r846 - in trunk/dna-repository/src: main/java/org/jboss/dna/repository/mimetype and 3 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-22 10:05:41 -0400 (Wed, 22 Apr 2009)
New Revision: 846
Added:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfigurationException.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java
Modified:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/mimetype/MimeTypeDetectorConfig.java
trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
trunk/dna-repository/src/test/java/org/jboss/dna/repository/mimetype/AbstractMimeTypeTest.java
Log:
DNA-58 Create repository configuration and component
Applied the second patch, which added DnaConfiguration and DnaEngine classes (along with test cases), and the MimeTypeDetectorConfig class (and its test cases).
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java 2009-04-22 14:05:41 UTC (rev 846)
@@ -0,0 +1,917 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.Reflection;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.mimetype.MimeTypeDetector;
+import org.jboss.dna.graph.property.PathExpression;
+import org.jboss.dna.graph.sequencer.StreamSequencer;
+import org.jboss.dna.repository.mimetype.MimeTypeDetectorConfig;
+import org.jboss.dna.repository.sequencer.Sequencer;
+import org.jboss.dna.repository.sequencer.SequencerConfig;
+import org.jboss.dna.repository.sequencer.StreamSequencerAdapter;
+
+/**
+ */
+@Immutable
+public class DnaConfiguration {
+
+ protected RepositorySource configurationSource;
+ protected String configurationSourceDescription;
+ protected Graph configuration;
+ private final ExecutionContext context;
+
+ /**
+ * Mapping of repository names to configured repositories
+ */
+ protected final Map<String, DnaRepositoryDetails> repositories;
+ protected final Map<String, DnaMimeTypeDetectorDetails> mimeTypeDetectors;
+ protected final Map<String, DnaSequencerDetails> sequencers;
+
+ /**
+ * Create a new configuration for DNA.
+ */
+ public DnaConfiguration() {
+ this(new ExecutionContext());
+ }
+
+ /**
+ * Specify a new {@link ExecutionContext} that should be used for this DNA instance.
+ *
+ * @param context the new context, or null if a default-constructed execution context should be used
+ */
+ public DnaConfiguration( ExecutionContext context ) {
+ this.context = context;
+ this.repositories = new HashMap<String, DnaRepositoryDetails>();
+ this.mimeTypeDetectors = new HashMap<String, DnaMimeTypeDetectorDetails>();
+ this.sequencers = new HashMap<String, DnaSequencerDetails>();
+
+ // Set up the default configuration repository ...
+ this.configurationSource = createDefaultConfigurationSource();
+
+ }
+
+ private DnaConfiguration( DnaConfiguration source ) {
+ this.configuration = source.configuration;
+ this.configurationSource = source.configurationSource;
+ this.context = source.context;
+ this.configurationSourceDescription = source.configurationSourceDescription;
+ this.repositories = new HashMap<String, DnaRepositoryDetails>(source.repositories);
+ this.mimeTypeDetectors = new HashMap<String, DnaMimeTypeDetectorDetails>(source.mimeTypeDetectors);
+ this.sequencers = new HashMap<String, DnaSequencerDetails>(source.sequencers);
+ }
+
+ private DnaConfiguration with( String repositoryName,
+ DnaRepositoryDetails details ) {
+ DnaConfiguration newConfig = new DnaConfiguration(this);
+ newConfig.repositories.put(repositoryName, details);
+
+ return newConfig;
+ }
+
+ protected ExecutionContext getExecutionContext() {
+ return this.context;
+ }
+
+ protected Graph getConfiguration() {
+ if (this.configuration == null) {
+ this.configuration = Graph.create(configurationSource, context);
+ }
+ return this.configuration;
+ }
+
+ /**
+ * Method that is used to set up the default configuration repository source. By default, this method sets up the
+ * {@link InMemoryRepositorySource} loaded from the classpath.
+ *
+ * @return the default repository source
+ */
+ protected RepositorySource createDefaultConfigurationSource() {
+ this.withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class.getName())
+ .loadedFromClasspath()
+ .describedAs("Configuration Repository")
+ .with("name")
+ .setTo("Configuration");
+ return configurationSource;
+ }
+
+ /**
+ * Specify that this configuration should use a particular {@link RepositorySource} for its configuration repository. By
+ * default each configuration uses an internal transient repository for its configuration, but using this method will make the
+ * configuration use a different repository (that is perhaps shared with other processes).
+ *
+ * @return the interface for choosing the class, which returns the interface used to configure the repository source that will
+ * be used for the configuration repository; never null
+ */
+ public ChooseClass<RepositorySource, RepositoryDetails> withConfigurationRepository() {
+ return addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME);
+ }
+
+ /**
+ * Add a new {@link RepositorySource repository} for this configuration. The new repository will have the supplied name, and
+ * if the name of an existing repository is used, this will replace the existing repository configuration.
+ *
+ * @param name the name of the new repository that is to be added
+ * @return the interface for choosing the class, which returns the interface used to configure the repository source; never
+ * null
+ * @throws IllegalArgumentException if the repository name is null, empty, or otherwise invalid
+ * @see #addRepository(RepositorySource)
+ */
+ public ChooseClass<RepositorySource, RepositoryDetails> addRepository( final String name ) {
+ return new ClassChooser<RepositorySource, RepositoryDetails>() {
+
+ @Override
+ protected RepositoryDetails getComponentBuilder( String className,
+ String... classpath ) {
+ try {
+ Class<?> clazz = Class.forName(className);
+ Object newInstance = clazz.newInstance();
+ assert newInstance instanceof RepositorySource;
+
+ DnaRepositoryDetails details = new DnaRepositoryDetails((RepositorySource)newInstance);
+ DnaConfiguration.this.repositories.put(name, details);
+
+ return details;
+ } catch (Exception ex) {
+ throw new DnaConfigurationException(ex);
+ }
+ }
+ };
+ }
+
+ /**
+ * Add a new {@link RepositorySource repository} for this configuration. The new repository will have the supplied name, and
+ * if the name of an existing repository is used, this will replace the existing repository configuration.
+ *
+ * @param source the {@link RepositorySource} instance that should be used
+ * @return this configuration object, for method-chaining purposes
+ * @throws IllegalArgumentException if the repository source reference is null
+ * @see #addRepository(String)
+ */
+ public DnaConfiguration addRepository( RepositorySource source ) {
+ return this.with(source.getName(), new DnaRepositoryDetails(source));
+ }
+
+ /**
+ * Add a new {@link Sequencer sequencer} to this configuration. The new sequencer will have the supplied name, and if the name
+ * of an existing sequencer is used, this will replace the existing sequencer configuration.
+ *
+ * @param name the name of the new sequencer
+ * @return the interface for choosing the class, which returns the interface used to configure the sequencer; never null
+ * @throws IllegalArgumentException if the sequencer name is null, empty, or otherwise invalid
+ */
+ public ChooseClass<Sequencer, SequencerDetails> addSequencer( final String name ) {
+ return new ClassChooser<Sequencer, SequencerDetails>() {
+
+ @Override
+ protected SequencerDetails getComponentBuilder( String className,
+ String... classpath ) {
+ try {
+ Class<?> clazz = Class.forName(className);
+ Object newInstance = clazz.newInstance();
+ assert newInstance instanceof Sequencer;
+
+ DnaSequencerDetails details = new DnaSequencerDetails(name, (Sequencer)newInstance, classpath);
+ DnaConfiguration.this.sequencers.put(name, details);
+
+ return details;
+ } catch (Exception ex) {
+ throw new DnaConfigurationException(ex);
+ }
+ }
+ };
+ }
+
+ /**
+ * Add a new {@link StreamSequencer sequencer} to this configuration. The new stream sequencer will have the supplied name,
+ * and if the name of an existing sequencer is used, this will replace the existing sequencer configuration.
+ *
+ * @param name the name of the new sequencer
+ * @return the interface for choosing the class, which returns the interface used to configure the stream sequencer; never
+ * null
+ * @throws IllegalArgumentException if the sequencer name is null, empty, or otherwise invalid
+ */
+ public ChooseClass<StreamSequencer, SequencerDetails> addStreamSequencer( final String name ) {
+ return new ClassChooser<StreamSequencer, SequencerDetails>() {
+
+ @Override
+ protected SequencerDetails getComponentBuilder( String className,
+ String... classpath ) {
+ try {
+ Class<?> clazz = Class.forName(className);
+ Object newInstance = clazz.newInstance();
+ assert newInstance instanceof StreamSequencer;
+
+ DnaSequencerDetails details = new DnaSequencerDetails(
+ name,
+ new StreamSequencerAdapter((StreamSequencer)newInstance),
+ classpath);
+ DnaConfiguration.this.sequencers.put(name, details);
+
+ return details;
+ } catch (Exception ex) {
+ throw new DnaConfigurationException(ex);
+ }
+ }
+ };
+ }
+
+ /**
+ * Add a new {@link MimeTypeDetector MIME type detector} to this configuration. The new detector will have the supplied name,
+ * and if the name of an existing detector is used, this will replace the existing detector configuration.
+ *
+ * @param name the name of the new detector
+ * @return the interface for choosing the class, which returns the interface used to configure the detector; never null
+ * @throws IllegalArgumentException if the detector name is null, empty, or otherwise invalid
+ */
+ public ChooseClass<MimeTypeDetector, MimeTypeDetectorDetails> addMimeTypeDetector( final String name ) {
+ return new ClassChooser<MimeTypeDetector, MimeTypeDetectorDetails>() {
+
+ @Override
+ protected MimeTypeDetectorDetails getComponentBuilder( String className,
+ String... classpath ) {
+ try {
+ Class<?> clazz = Class.forName(className);
+ Object newInstance = clazz.newInstance();
+ assert newInstance instanceof MimeTypeDetector;
+
+ DnaMimeTypeDetectorDetails details = new DnaMimeTypeDetectorDetails(name, (MimeTypeDetector)newInstance,
+ classpath);
+ DnaConfiguration.this.mimeTypeDetectors.put(name, details);
+
+ return details;
+ } catch (Exception ex) {
+ throw new DnaConfigurationException(ex);
+ }
+ }
+ };
+ }
+
+ /**
+ * Complete this configuration and create the corresponding engine.
+ *
+ * @return the new engine configured by this instance
+ */
+ public DnaEngine build() {
+ return new DnaEngine(this);
+ }
+
+ /**
+ * Interface used to configure a {@link RepositorySource repository}.
+ */
+ public interface RepositoryDetails
+ extends SetDescription<RepositoryDetails>, SetProperties<RepositoryDetails>, ConfigurationBuilder {
+
+ RepositorySource getRepositorySource();
+ }
+
+ /**
+ * Local implementation of the {@link MimeTypeDetectorDetails} interface that tracks all of the user-provided configuration
+ * details.
+ */
+ protected class DnaMimeTypeDetectorDetails implements MimeTypeDetectorDetails {
+ final MimeTypeDetector mimeTypeDetector;
+ private String name;
+ private String description;
+ private Map<String, Object> properties;
+ private String className;
+ private String[] classpath;
+
+ protected DnaMimeTypeDetectorDetails( String name,
+ MimeTypeDetector mimeTypeDetector,
+ String[] classpath ) {
+ this.mimeTypeDetector = mimeTypeDetector;
+ this.name = name;
+ this.description = mimeTypeDetector.getClass().getName();
+ this.properties = new HashMap<String, Object>();
+ this.className = mimeTypeDetector.getClass().getName();
+ this.classpath = classpath;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ protected String getDescription() {
+ return description;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
+ */
+ public MimeTypeDetectorDetails describedAs( String description ) {
+ this.description = description;
+ return this;
+ }
+
+ public PropertySetter<MimeTypeDetectorDetails> with( final String propertyName ) {
+ return new MappingPropertySetter<MimeTypeDetectorDetails>(propertyName, this);
+ }
+
+ public MimeTypeDetector getMimeTypeDetector() {
+ return mimeTypeDetector;
+ }
+
+ MimeTypeDetectorConfig getMimeTypeDetectorConfig() {
+ return new MimeTypeDetectorConfig(name, description, properties, className, classpath);
+ }
+
+ public DnaConfiguration and() {
+ return DnaConfiguration.this;
+ }
+
+ }
+
+ /**
+ * Local implementation of the {@link RepositoryDetails} interface that tracks all of the user-provided configuration details.
+ */
+ protected class DnaRepositoryDetails implements RepositoryDetails {
+ private final RepositorySource source;
+ private final String description;
+ private Map<String, Object> properties;
+
+ protected DnaRepositoryDetails( RepositorySource source ) {
+ this.source = source;
+ this.description = source.getName();
+ this.properties = new HashMap<String, Object>();
+ }
+
+ protected DnaRepositoryDetails( RepositorySource source,
+ String description ) {
+ this.source = source;
+ this.description = description;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ protected String getDescription() {
+ return description;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
+ */
+ public RepositoryDetails describedAs( String description ) {
+ return new DnaRepositoryDetails(this.source, description);
+ }
+
+ public PropertySetter<RepositoryDetails> with( final String propertyName ) {
+ return new BeanPropertySetter<RepositoryDetails>(source, propertyName, this);
+ }
+
+ public RepositorySource getRepositorySource() {
+ return source;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
+ */
+ public DnaConfiguration and() {
+ return DnaConfiguration.this;
+ }
+ }
+
+ /**
+ * Local implementation of the {@link SequencerDetails} interface that tracks all of the user-provided configuration details.
+ */
+ protected class DnaSequencerDetails implements SequencerDetails {
+ private final Sequencer sequencer;
+ private String name;
+ private String description;
+ private Map<String, Object> properties;
+ private String className;
+ private String[] classpath;
+ final List<PathExpression> sourcePathExpressions;
+ final List<PathExpression> targetPathExpressions;
+
+ protected DnaSequencerDetails( String name,
+ Sequencer sequencer,
+ String[] classpath ) {
+ this.sequencer = sequencer;
+ this.name = name;
+ this.description = sequencer.getClass().getName();
+ this.properties = new HashMap<String, Object>();
+ this.className = sequencer.getClass().getName();
+ this.classpath = classpath;
+ this.sourcePathExpressions = new ArrayList<PathExpression>();
+ this.targetPathExpressions = new ArrayList<PathExpression>();
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ protected String getDescription() {
+ return description;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SetDescription#describedAs(java.lang.String)
+ */
+ public SequencerDetails describedAs( String description ) {
+ this.description = description;
+ return this;
+ }
+
+ public PropertySetter<SequencerDetails> with( final String propertyName ) {
+ return new MappingPropertySetter<SequencerDetails>(propertyName, this);
+ }
+
+ public Sequencer getSequencer() {
+ return sequencer;
+ }
+
+ SequencerConfig getSequencerConfig() {
+ return new SequencerConfig(this.name, this.description, this.properties, this.className, this.classpath);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ConfigurationBuilder#and()
+ */
+ public DnaConfiguration and() {
+ return DnaConfiguration.this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SequencerDetails#sequencingFrom(java.lang.String)
+ */
+ public PathExpressionOutput sequencingFrom( String inputExpressionPath ) {
+ return this.sequencingFrom(PathExpression.compile(inputExpressionPath));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.SequencerDetails#sequencingFrom(org.jboss.dna.graph.property.PathExpression)
+ */
+ public PathExpressionOutput sequencingFrom( final PathExpression inputExpressionPath ) {
+ final DnaSequencerDetails details = this;
+ return new PathExpressionOutput() {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.PathExpressionOutput#andOutputtingTo(java.lang.String)
+ */
+ public DnaSequencerDetails andOutputtingTo( final String outputExpressionPath ) {
+ details.sourcePathExpressions.add(inputExpressionPath);
+ details.targetPathExpressions.add(PathExpression.compile(outputExpressionPath));
+ return details;
+ }
+ };
+ }
+
+ }
+
+ /**
+ * Interface used to configure a {@link Sequencer sequencer}.
+ */
+ public interface SequencerDetails extends SetDescription<SequencerDetails>, ConfigurationBuilder {
+
+ /**
+ * Specify the input {@link PathExpression path expression} represented as a string, which determines when this sequencer
+ * will be executed.
+ *
+ * @param inputPathExpression the path expression for nodes that, when they change, will be passed as an input to the
+ * sequencer
+ * @return the interface used to specify the output path expression; never null
+ */
+ PathExpressionOutput sequencingFrom( String inputPathExpression );
+
+ /**
+ * Specify the input {@link PathExpression path expression}, which determines when this sequencer will be executed.
+ *
+ * @param inputPathExpression the path expression for nodes that, when they change, will be passed as an input to the
+ * sequencer
+ * @return the interface used to specify the output path expression; never null
+ */
+ PathExpressionOutput sequencingFrom( PathExpression inputPathExpression );
+ }
+
+ /**
+ * Interface used to specify the output path expression for a {@link SequencerDetails#sequencingFrom(PathExpression) sequencer
+ * configuration}.
+ */
+ public interface PathExpressionOutput {
+ /**
+ * Specify the output {@link PathExpression path expression}, which determines where this sequencer's output will be
+ * placed.
+ *
+ * @param outputExpression the path expression for the location(s) where output generated by the sequencer is to be placed
+ * @return the interface used to continue specifying the configuration of the sequencer
+ */
+ SequencerDetails andOutputtingTo( String outputExpression );
+ }
+
+ /**
+ * Interface used to configure a {@link MimeTypeDetector MIME type detector}.
+ */
+ public interface MimeTypeDetectorDetails
+ extends SetDescription<MimeTypeDetectorDetails>, SetProperties<MimeTypeDetectorDetails>, ConfigurationBuilder {
+ }
+
+ /**
+ * Interface for configuring the JavaBean-style properties of an object.
+ *
+ * @param <ReturnType> the interface returned after the property has been set.
+ * @author Randall Hauch
+ */
+ public interface SetProperties<ReturnType> {
+ /**
+ * Specify the name of the JavaBean-style property that is to be set. The value may be set using the interface returned by
+ * this method.
+ *
+ * @param beanPropertyName the name of the JavaBean-style property (e.g., "retryLimit")
+ * @return the interface used to set the value for the property; never null
+ */
+ PropertySetter<ReturnType> with( String beanPropertyName );
+ }
+
+ /**
+ * The interface used to set the value for a JavaBean-style property.
+ *
+ * @param <ReturnType> the interface returned from these methods
+ * @author Randall Hauch
+ * @see SetProperties#with(String)
+ */
+ public interface PropertySetter<ReturnType> {
+ /**
+ * Set the property value to an integer.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( int value );
+
+ /**
+ * Set the property value to a long number.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( long value );
+
+ /**
+ * Set the property value to a short.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( short value );
+
+ /**
+ * Set the property value to a boolean.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( boolean value );
+
+ /**
+ * Set the property value to a float.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( float value );
+
+ /**
+ * Set the property value to a double.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( double value );
+
+ /**
+ * Set the property value to a string.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( String value );
+
+ /**
+ * Set the property value to an object.
+ *
+ * @param value the new value for the property
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType setTo( Object value );
+ }
+
+ /**
+ * The interface used to configure the class used for a component.
+ *
+ * @param <ComponentClassType> the class or interface that the component is to implement
+ * @param <ReturnType> the interface returned from these methods
+ */
+ public interface ChooseClass<ComponentClassType, ReturnType> {
+
+ /**
+ * Specify the name of the class that should be instantiated for the instance. The classpath information will need to be
+ * defined using the returned interface.
+ *
+ * @param classname the name of the class that should be instantiated
+ * @return the interface used to define the classpath information; never null
+ * @throws IllegalArgumentException if the class name is null, empty, blank, or not a valid class name
+ */
+ LoadedFrom<ReturnType> usingClass( String classname );
+
+ /**
+ * Specify the class that should be instantiated for the instance. Because the class is already available to this class
+ * loader, there is no need to specify the classloader information.
+ *
+ * @param clazz the class that should be instantiated
+ * @return the next component to continue configuration; never null
+ * @throws IllegalArgumentException if the class reference is null
+ */
+ ReturnType usingClass( Class<? extends ComponentClassType> clazz );
+ }
+
+ /**
+ * The interface used to set a description on a component.
+ *
+ * @param <ReturnType> the interface returned from these methods
+ */
+ public interface SetDescription<ReturnType> {
+ /**
+ * Specify the description of this component.
+ *
+ * @param description the description; may be null or empty
+ * @return the next component to continue configuration; never null
+ */
+ ReturnType describedAs( String description );
+ }
+
+ /**
+ * Interface for specifying from where the component's class is to be loaded.
+ *
+ * @param <ReturnType> the interface returned from these methods
+ */
+ public interface LoadedFrom<ReturnType> {
+ /**
+ * Specify the names of the classloaders that form the classpath for the component, from which the component's class (and
+ * its dependencies) can be loaded. The names correspond to the names supplied to the
+ * {@link ExecutionContext#getClassLoader(String...)} methods.
+ *
+ * @param classPathNames the names for the classloaders, as passed to the {@link ClassLoaderFactory} implementation (e.g.,
+ * the {@link ExecutionContext}).
+ * @return the next component to continue configuration; never null
+ * @see #loadedFromClasspath()
+ * @see ExecutionContext#getClassLoader(String...)
+ */
+ ReturnType loadedFrom( String... classPathNames );
+
+ /**
+ * Specify that the component (and its dependencies) will be found on the current (or
+ * {@link Thread#getContextClassLoader() current context}) classloader.
+ *
+ * @return the next component to continue configuration; never null
+ * @see #loadedFrom(String...)
+ * @see ExecutionContext#getClassLoader(String...)
+ */
+ ReturnType loadedFromClasspath();
+ }
+
+ /**
+ * Interface for classes that can return a reference to their DNA configuration.
+ */
+ public interface ConfigurationBuilder {
+
+ Map<String, Object> getProperties();
+
+ /**
+ * Return a reference to the enclosing configuration so that it can be built or further configured.
+ *
+ * @return a reference to the enclosing configuration
+ */
+ DnaConfiguration and();
+ }
+
+ /**
+ * Abstract implementation of {@link ChooseClass} that has a single abstract method to obtain the interface that should be
+ * returned when the class name and classpath have been selected.
+ *
+ * @param <ComponentClass> the type of the component that is being chosen
+ * @param <ReturnType> the interface that should be returned when the class name and classpath have been chosen.
+ * @author Randall Hauch
+ */
+ protected abstract class ClassChooser<ComponentClass, ReturnType> implements ChooseClass<ComponentClass, ReturnType> {
+
+ protected abstract ReturnType getComponentBuilder( String className,
+ String... classpath );
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ChooseClass#usingClass(java.lang.String)
+ */
+ public LoadedFrom<ReturnType> usingClass( final String classname ) {
+ CheckArg.isNotEmpty(classname, "classname");
+ return new LoadedFrom<ReturnType>() {
+ public ReturnType loadedFromClasspath() {
+ return getComponentBuilder(classname);
+ }
+
+ public ReturnType loadedFrom( String... classpath ) {
+ return getComponentBuilder(classname, classpath);
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.DnaConfiguration.ChooseClass#usingClass(java.lang.Class)
+ */
+ public ReturnType usingClass( Class<? extends ComponentClass> clazz ) {
+ CheckArg.isNotNull(clazz, "clazz");
+ return getComponentBuilder(clazz.getName());
+ }
+ }
+
+ /**
+ * Utility method to instantiate a class.
+ *
+ * @param <T> the interface or superclass that the instantiated object is to implement
+ * @param interfaceType the interface or superclass type that the instantiated object is to implement
+ * @param className the name of the class
+ * @param classloaderNames the names of the class loaders
+ * @return the new instance
+ */
+ @SuppressWarnings( "unchecked" )
+ protected <T> T instantiate( Class<T> interfaceType,
+ String className,
+ String... classloaderNames ) {
+ // Load the class and create the instance ...
+ try {
+ Class<?> clazz = getExecutionContext().getClassLoader(classloaderNames).loadClass(className);
+ return (T)clazz.newInstance();
+ } catch (Throwable err) {
+ I18n msg = RepositoryI18n.errorCreatingInstanceOfClass;
+ throw new DnaConfigurationException(msg.text(className, err.getMessage()), err);
+ }
+ }
+
+ /**
+ * Reusable implementation of {@link PropertySetter} that sets the JavaBean-style property using reflection.
+ *
+ * @param <ReturnType>
+ * @author Randall Hauch
+ */
+ protected class BeanPropertySetter<ReturnType> implements PropertySetter<ReturnType> {
+ private final Object javaBean;
+ private final String beanPropertyName;
+ private final ReturnType returnObject;
+
+ protected BeanPropertySetter( Object javaBean,
+ String beanPropertyName,
+ ReturnType returnObject ) {
+ assert javaBean != null;
+ assert beanPropertyName != null;
+ assert returnObject != null;
+ this.javaBean = javaBean;
+ this.beanPropertyName = beanPropertyName;
+ this.returnObject = returnObject;
+ }
+
+ public ReturnType setTo( boolean value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( int value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( long value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( short value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( float value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( double value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( String value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( Object value ) {
+ // Set the JavaBean-style property on the RepositorySource instance ...
+ Reflection reflection = new Reflection(javaBean.getClass());
+ try {
+ reflection.invokeSetterMethodOnTarget(beanPropertyName, javaBean, value);
+ } catch (Throwable err) {
+ I18n msg = RepositoryI18n.errorSettingJavaBeanPropertyOnInstanceOfClass;
+ throw new DnaConfigurationException(msg.text(beanPropertyName, javaBean.getClass(), err.getMessage()), err);
+ }
+ return returnObject;
+ }
+ }
+
+ /**
+ * Reusable implementation of {@link PropertySetter} that aggregates the properties to set to be placed into a map
+ *
+ * @param <ReturnType>
+ * @author Randall Hauch
+ */
+ protected class MappingPropertySetter<ReturnType extends ConfigurationBuilder> implements PropertySetter<ReturnType> {
+ private final String beanPropertyName;
+ private final ReturnType returnObject;
+
+ protected MappingPropertySetter( String beanPropertyName,
+ ReturnType returnObject ) {
+ assert beanPropertyName != null;
+ assert returnObject != null;
+ this.beanPropertyName = beanPropertyName;
+ this.returnObject = returnObject;
+ }
+
+ public ReturnType setTo( boolean value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( int value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( long value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( short value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( float value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( double value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( String value ) {
+ return setTo((Object)value);
+ }
+
+ public ReturnType setTo( Object value ) {
+ returnObject.getProperties().put(beanPropertyName, value);
+ return returnObject;
+ }
+ }
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfiguration.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfigurationException.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfigurationException.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfigurationException.java 2009-04-22 14:05:41 UTC (rev 846)
@@ -0,0 +1,65 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository;
+
+/**
+ * @author Randall Hauch
+ */
+public class DnaConfigurationException extends RuntimeException {
+
+ /**
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public DnaConfigurationException() {
+ }
+
+ /**
+ * @param message
+ */
+ public DnaConfigurationException( String message ) {
+ super(message);
+
+ }
+
+ /**
+ * @param cause
+ */
+ public DnaConfigurationException( Throwable cause ) {
+ super(cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public DnaConfigurationException( String message,
+ Throwable cause ) {
+ super(message, cause);
+
+ }
+
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaConfigurationException.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java 2009-04-22 14:05:41 UTC (rev 846)
@@ -0,0 +1,152 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.repository.DnaConfiguration.DnaMimeTypeDetectorDetails;
+import org.jboss.dna.repository.DnaConfiguration.DnaRepositoryDetails;
+import org.jboss.dna.repository.DnaConfiguration.DnaSequencerDetails;
+import org.jboss.dna.repository.observation.ObservationService;
+import org.jboss.dna.repository.sequencer.SequencingService;
+import org.jboss.dna.repository.service.AdministeredService;
+
+/**
+ * @author Randall Hauch
+ */
+@Immutable
+public class DnaEngine {
+
+ public static final String CONFIGURATION_REPOSITORY_NAME = "dna:configuration";
+
+ private final ExecutionContext context;
+ private final List<AdministeredService> services;
+
+ private final RepositoryService repositoryService;
+ private final ObservationService observationService;
+ private final SequencingService sequencingService;
+ private final ExecutorService executorService;
+
+ private final RepositoryConnectionFactory connectionFactory;
+
+ DnaEngine( DnaConfiguration configuration ) {
+ this.context = new ExecutionContext();
+
+ DnaRepositoryDetails configSource = configuration.repositories.get(CONFIGURATION_REPOSITORY_NAME);
+ assert configSource != null : "Must specify a repository source named " + CONFIGURATION_REPOSITORY_NAME;
+
+ // Use a magic number for now
+ executorService = new ScheduledThreadPoolExecutor(10);
+
+ observationService = null; // new ObservationService(null);
+
+ RepositoryLibrary library = new RepositoryLibrary();
+ for (DnaRepositoryDetails details : configuration.repositories.values()) {
+ // Adding configuration source to the library until proven wrong!
+ library.addSource(details.getRepositorySource());
+ }
+
+ for (DnaMimeTypeDetectorDetails details : configuration.mimeTypeDetectors.values()) {
+ library.getMimeTypeDetectors().addDetector(details.getMimeTypeDetectorConfig());
+ }
+ repositoryService = new RepositoryService(library, configSource.getRepositorySource().getName(), "", context);
+
+ sequencingService = new SequencingService();
+ sequencingService.setExecutorService(executorService);
+ for (DnaSequencerDetails details : configuration.sequencers.values()) {
+ sequencingService.addSequencer(details.getSequencerConfig());
+ }
+
+ this.services = Arrays.asList(new AdministeredService[] { /* observationService, */repositoryService, sequencingService,});
+
+ connectionFactory = new RepositoryConnectionFactory() {
+ public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+ RepositorySource source = DnaEngine.this.getRepositorySource(sourceName);
+ if (sourceName == null) {
+ throw new RepositorySourceException(sourceName);
+ }
+
+ return source.getConnection();
+ }
+ };
+ }
+
+ /*
+ * Lookup methods
+ */
+ public final ExecutionContext getExecutionContext() {
+ return context;
+ }
+
+ public final RepositorySource getRepositorySource( String repositoryName ) {
+ return repositoryService.getRepositorySourceManager().getSource(repositoryName);
+ }
+
+ public final RepositoryConnectionFactory getRepositoryConnectionFactory() {
+ return connectionFactory;
+ }
+
+ public final RepositoryService getRepositoryService() {
+ return repositoryService;
+ }
+
+ public final ObservationService getObservationService() {
+ return observationService;
+ }
+
+ public final SequencingService getSequencingService() {
+ return sequencingService;
+ }
+
+ /*
+ * Lifecycle methods
+ */
+
+ public void start() {
+ for (AdministeredService service : services) {
+ service.getAdministrator().start();
+ }
+ }
+
+ public void shutdown() {
+ for (AdministeredService service : services) {
+ service.getAdministrator().shutdown();
+ }
+
+ try {
+ executorService.awaitTermination(10 * 60, TimeUnit.SECONDS); // No TimeUnit.MINUTES in JDK 5
+ } catch (InterruptedException ie) {
+ // Reset the thread's status and continue this method ...
+ Thread.interrupted();
+ }
+ executorService.shutdown();
+ }
+}
Property changes on: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2009-04-22 13:38:14 UTC (rev 845)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2009-04-22 14:05:41 UTC (rev 846)
@@ -1,137 +1,142 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
-* See the AUTHORS.txt file in the distribution for a full listing of
-* individual contributors.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.repository;
-
-import java.util.Locale;
-import java.util.Set;
-import org.jboss.dna.common.i18n.I18n;
-
-/**
- * @author Randall Hauch
- * @author John Verhaeg
- */
-public final class RepositoryI18n {
-
- // Services and Repository
- public static I18n invalidStateString;
- public static I18n serviceShutdowAndMayNotBeStarted;
- public static I18n serviceShutdowAndMayNotBePaused;
- public static I18n serviceNotShutdowAndMayNotBeTerminated;
- public static I18n unableToFindRepositoryInJndi;
- public static I18n unableToRegisterRepositoryInJndi;
- public static I18n unableToUnregisterRepositoryInJndi;
- public static I18n unableToRemoveRepository;
- public static I18n unableToFindRepositoryWithName;
- public static I18n errorProcessingEvents;
- public static I18n errorFindingPropertyNameInPropertyAddedEvent;
- public static I18n errorFindingPropertyNameInPropertyChangedEvent;
- public static I18n errorFindingPropertyNameInPropertyRemovedEvent;
-
- // Rules
- public static I18n unableToObtainJsr94RuleAdministrator;
- public static I18n errorUsingJsr94RuleAdministrator;
- public static I18n unableToObtainJsr94ServiceProvider;
- public static I18n errorAddingOrUpdatingRuleSet;
- public static I18n errorRollingBackRuleSetAfterUpdateFailed;
- public static I18n errorReadingRulesAndProperties;
- public static I18n errorDeregisteringRuleSetBeforeUpdatingIt;
- public static I18n errorRecreatingRuleSet;
- public static I18n errorRemovingRuleSet;
- public static I18n errorRemovingRuleSetUponShutdown;
- public static I18n unableToFindRuleSet;
- public static I18n errorExecutingRuleSetWithGlobalsAndFacts;
- public static I18n unableToBuildRuleSetRegularExpressionPattern;
-
- public static I18n errorObtainingSessionToRepositoryWorkspace;
- public static I18n errorWritingProblemsOnRuleSet;
-
- public static I18n federationServiceName;
- public static I18n observationServiceName;
- public static I18n ruleServiceName;
-
- // Sequencing
- public static I18n sequencingServiceName;
- public static I18n unableToChangeExecutionContextWhileRunning;
- public static I18n unableToStartSequencingServiceWithoutExecutionContext;
- public static I18n errorWhileSequencingNode;
- public static I18n errorInRepositoryWhileSequencingNode;
- public static I18n errorFindingSequencersToRunAgainstNode;
- public static I18n errorInRepositoryWhileFindingSequencersToRunAgainstNode;
- public static I18n executionContextHasBeenClosed;
- public static I18n unableToFindPropertyForSequencing;
-
- // Properties
- public static I18n errorReadingPropertiesFromContainerNode;
- public static I18n requiredPropertyOnNodeWasExpectedToBeStringValue;
- public static I18n optionalPropertyOnNodeWasExpectedToBeStringValue;
- public static I18n requiredPropertyOnNodeWasExpectedToBeStringArrayValue;
- public static I18n optionalPropertyOnNodeWasExpectedToBeStringArrayValue;
- public static I18n requiredPropertyOnNodeCouldNotBeRead;
- public static I18n optionalPropertyOnNodeCouldNotBeRead;
- public static I18n requiredPropertyIsMissingFromNode;
- public static I18n errorGettingRequiredPropertyFromNode;
- public static I18n errorGettingOptionalPropertyFromNode;
- public static I18n errorClosingBinaryStreamForPropertyFromNode;
- public static I18n requiredNodeDoesNotExistRelativeToNode;
- public static I18n errorGettingNodeRelativeToNode;
- public static I18n unknownPropertyValueType;
-
- // Path expressions
- public static I18n pathExpressionIsInvalid;
- public static I18n pathExpressionMayNotBeBlank;
- public static I18n pathExpressionHasInvalidSelect;
- public static I18n pathExpressionHasInvalidMatch;
-
- // Observation
- public static I18n errorUnregisteringWorkspaceListenerWhileShuttingDownObservationService;
-
- // General
- public static I18n invalidRepositoryNodePath;
- public static I18n unableToLoadClassUsingClasspath;
- public static I18n unableToInstantiateClassUsingClasspath;
- public static I18n unableToAccessClassUsingClasspath;
-
- // Repository
- public static I18n errorStartingRepositoryService;
-
- static {
- try {
- I18n.initialize(RepositoryI18n.class);
- } catch (final Exception err) {
- System.err.println(err);
- }
- }
-
- public static Set<Locale> getLocalizationProblemLocales() {
- return I18n.getLocalizationProblemLocales(RepositoryI18n.class);
- }
-
- public static Set<String> getLocalizationProblems() {
- return I18n.getLocalizationProblems(RepositoryI18n.class);
- }
-
- public static Set<String> getLocalizationProblems( Locale locale ) {
- return I18n.getLocalizationProblems(RepositoryI18n.class, locale);
- }
-}
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+* See the AUTHORS.txt file in the distribution for a full listing of
+* individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository;
+
+import java.util.Locale;
+import java.util.Set;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author Randall Hauch
+ * @author John Verhaeg
+ */
+public final class RepositoryI18n {
+
+ // Configuration
+ public static I18n errorCreatingInstanceOfClass;
+ public static I18n errorCreatingInstanceOfClassUsingClassLoaders;
+ public static I18n errorSettingJavaBeanPropertyOnInstanceOfClass;
+
+ // Services and Repository
+ public static I18n invalidStateString;
+ public static I18n serviceShutdowAndMayNotBeStarted;
+ public static I18n serviceShutdowAndMayNotBePaused;
+ public static I18n serviceNotShutdowAndMayNotBeTerminated;
+ public static I18n unableToFindRepositoryInJndi;
+ public static I18n unableToRegisterRepositoryInJndi;
+ public static I18n unableToUnregisterRepositoryInJndi;
+ public static I18n unableToRemoveRepository;
+ public static I18n unableToFindRepositoryWithName;
+ public static I18n errorProcessingEvents;
+ public static I18n errorFindingPropertyNameInPropertyAddedEvent;
+ public static I18n errorFindingPropertyNameInPropertyChangedEvent;
+ public static I18n errorFindingPropertyNameInPropertyRemovedEvent;
+
+ // Rules
+ public static I18n unableToObtainJsr94RuleAdministrator;
+ public static I18n errorUsingJsr94RuleAdministrator;
+ public static I18n unableToObtainJsr94ServiceProvider;
+ public static I18n errorAddingOrUpdatingRuleSet;
+ public static I18n errorRollingBackRuleSetAfterUpdateFailed;
+ public static I18n errorReadingRulesAndProperties;
+ public static I18n errorDeregisteringRuleSetBeforeUpdatingIt;
+ public static I18n errorRecreatingRuleSet;
+ public static I18n errorRemovingRuleSet;
+ public static I18n errorRemovingRuleSetUponShutdown;
+ public static I18n unableToFindRuleSet;
+ public static I18n errorExecutingRuleSetWithGlobalsAndFacts;
+ public static I18n unableToBuildRuleSetRegularExpressionPattern;
+
+ public static I18n errorObtainingSessionToRepositoryWorkspace;
+ public static I18n errorWritingProblemsOnRuleSet;
+
+ public static I18n federationServiceName;
+ public static I18n observationServiceName;
+ public static I18n ruleServiceName;
+
+ // Sequencing
+ public static I18n sequencingServiceName;
+ public static I18n unableToChangeExecutionContextWhileRunning;
+ public static I18n unableToStartSequencingServiceWithoutExecutionContext;
+ public static I18n errorWhileSequencingNode;
+ public static I18n errorInRepositoryWhileSequencingNode;
+ public static I18n errorFindingSequencersToRunAgainstNode;
+ public static I18n errorInRepositoryWhileFindingSequencersToRunAgainstNode;
+ public static I18n executionContextHasBeenClosed;
+ public static I18n unableToFindPropertyForSequencing;
+
+ // Properties
+ public static I18n errorReadingPropertiesFromContainerNode;
+ public static I18n requiredPropertyOnNodeWasExpectedToBeStringValue;
+ public static I18n optionalPropertyOnNodeWasExpectedToBeStringValue;
+ public static I18n requiredPropertyOnNodeWasExpectedToBeStringArrayValue;
+ public static I18n optionalPropertyOnNodeWasExpectedToBeStringArrayValue;
+ public static I18n requiredPropertyOnNodeCouldNotBeRead;
+ public static I18n optionalPropertyOnNodeCouldNotBeRead;
+ public static I18n requiredPropertyIsMissingFromNode;
+ public static I18n errorGettingRequiredPropertyFromNode;
+ public static I18n errorGettingOptionalPropertyFromNode;
+ public static I18n errorClosingBinaryStreamForPropertyFromNode;
+ public static I18n requiredNodeDoesNotExistRelativeToNode;
+ public static I18n errorGettingNodeRelativeToNode;
+ public static I18n unknownPropertyValueType;
+
+ // Path expressions
+ public static I18n pathExpressionIsInvalid;
+ public static I18n pathExpressionMayNotBeBlank;
+ public static I18n pathExpressionHasInvalidSelect;
+ public static I18n pathExpressionHasInvalidMatch;
+
+ // Observation
+ public static I18n errorUnregisteringWorkspaceListenerWhileShuttingDownObservationService;
+
+ // General
+ public static I18n invalidRepositoryNodePath;
+ public static I18n unableToLoadClassUsingClasspath;
+ public static I18n unableToInstantiateClassUsingClasspath;
+ public static I18n unableToAccessClassUsingClasspath;
+
+ // Repository
+ public static I18n errorStartingRepositoryService;
+
+ static {
+ try {
+ I18n.initialize(RepositoryI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(RepositoryI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(RepositoryI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(RepositoryI18n.class, locale);
+ }
+}
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/mimetype/MimeTypeDetectorConfig.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/mimetype/MimeTypeDetectorConfig.java 2009-04-22 13:38:14 UTC (rev 845)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/mimetype/MimeTypeDetectorConfig.java 2009-04-22 14:05:41 UTC (rev 846)
@@ -23,6 +23,7 @@
*/
package org.jboss.dna.repository.mimetype;
+import java.util.Map;
import org.jboss.dna.common.component.ComponentConfig;
/**
@@ -32,8 +33,9 @@
public MimeTypeDetectorConfig( String name,
String description,
+ Map<String, Object> properties,
String classname,
String[] classpath ) {
- super(name, description, classname, classpath);
+ super(name, description, properties, classname, classpath);
}
}
Modified: trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
===================================================================
--- trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2009-04-22 13:38:14 UTC (rev 845)
+++ trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2009-04-22 14:05:41 UTC (rev 846)
@@ -21,6 +21,10 @@
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
#
+errorCreatingInstanceOfClass = Attempt to create instance of {0} resulted in error: {1}
+errorCreatingInstanceOfClassUsingClassLoaders = Attempt to create instance of {0} using classloader path {1} resulted in error: {2}
+errorSettingJavaBeanPropertyOnInstanceOfClass = Attempt to set {0} property on {1} instance resulted in error: {2}
+
invalidStateString = Invalid state parameter "{0}"
serviceShutdowAndMayNotBeStarted = The {0} has been shutdown and may not be (re)started
serviceShutdowAndMayNotBePaused = The {0} has been shutdown and my not be paused
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java 2009-04-22 14:05:41 UTC (rev 846)
@@ -0,0 +1,215 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.mimetype.MimeTypeDetector;
+import org.jboss.dna.repository.DnaConfiguration.DnaSequencerDetails;
+import org.jboss.dna.repository.sequencer.MockSequencerA;
+import org.jboss.dna.repository.sequencer.MockSequencerB;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class DnaConfigurationTest {
+
+ private ExecutionContext context;
+ private DnaConfiguration configuration;
+
+ @Before
+ public void beforeEach() {
+ context = new ExecutionContext();
+ configuration = new DnaConfiguration();
+ }
+
+ @Test
+ public void shouldAllowCreatingWithNoArguments() {
+ configuration = new DnaConfiguration();
+ }
+
+ @Test
+ public void shouldAllowCreatingWithSpecifiedExecutionContext() {
+ configuration = new DnaConfiguration(context);
+ }
+
+ @Test
+ public void shouldAllowSpecifyingConfigurationRepository() {
+ DnaConfiguration config = configuration.withConfigurationRepository()
+ .usingClass("org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource")
+ .loadedFromClasspath()
+ .describedAs("description")
+ .with("retryLimit")
+ .setTo(5)
+ .with("name")
+ .setTo("repository name")
+ .and();
+ assertThat(config, is(notNullValue()));
+ assertThat(config.repositories.get(null), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowAddingRepositorySourceInstance() {
+ RepositorySource newSource = mock(RepositorySource.class);
+ configuration.addRepository(newSource);
+ }
+
+ @Test
+ public void shouldAllowAddingRepositorySourceByClassNameAndSettingProperties() {
+ DnaConfiguration config = configuration.addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME)
+ .usingClass("org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource")
+ .loadedFromClasspath()
+ .describedAs("description")
+ .with("retryLimit")
+ .setTo(5)
+ .with("name")
+ .setTo("repository name")
+ .and();
+ assertThat(config, is(notNullValue()));
+
+ RepositorySource source = config.repositories.get(DnaEngine.CONFIGURATION_REPOSITORY_NAME).getRepositorySource();
+ assertThat(source, is(notNullValue()));
+ assertThat(source, is(instanceOf(InMemoryRepositorySource.class)));
+
+ InMemoryRepositorySource isource = (InMemoryRepositorySource)source;
+ assertThat(isource.getRetryLimit(), is(5));
+ assertThat(isource.getName(), is("repository name"));
+ }
+
+ @Test
+ public void shouldAllowAddingRepositorySourceByClassReferenceAndSettingProperties() {
+ DnaConfiguration config = configuration.addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME)
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("description")
+ .with("retryLimit")
+ .setTo(5)
+ .with("name")
+ .setTo("repository name")
+ .and();
+
+ assertThat(config, is(notNullValue()));
+ assertThat(config.repositories.get(null), is(nullValue()));
+
+ RepositorySource source = config.repositories.get(DnaEngine.CONFIGURATION_REPOSITORY_NAME).getRepositorySource();
+ assertThat(source, is(notNullValue()));
+ assertThat(source, is(instanceOf(InMemoryRepositorySource.class)));
+
+ InMemoryRepositorySource isource = (InMemoryRepositorySource)source;
+ assertThat(isource.getRetryLimit(), is(5));
+ assertThat(isource.getName(), is("repository name"));
+ }
+
+ @Test
+ public void shouldAllowOverwritingRepositorySourceByRepositoryName() {
+ DnaConfiguration config = configuration.addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME)
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("description")
+ .with("retryLimit")
+ .setTo(3)
+ .and()
+ .addRepository(DnaEngine.CONFIGURATION_REPOSITORY_NAME)
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("description")
+ .with("name")
+ .setTo("repository name")
+ .and();
+
+ assertThat(config, is(notNullValue()));
+ assertThat(config.repositories.get(null), is(nullValue()));
+
+ RepositorySource source = config.repositories.get(DnaEngine.CONFIGURATION_REPOSITORY_NAME).getRepositorySource();
+ assertThat(source, is(notNullValue()));
+ assertThat(source, is(instanceOf(InMemoryRepositorySource.class)));
+
+ InMemoryRepositorySource isource = (InMemoryRepositorySource)source;
+ // This relies on the default retry limit for an InMemoryRepositorySource being 0
+ // If the original source was not overwritten, this would be 3
+ assertThat(isource.getRetryLimit(), is(0));
+ assertThat(isource.getName(), is("repository name"));
+ }
+
+ @Test
+ public void shouldAllowAddingMimeTypeDetector() {
+ RepositorySource newSource = mock(RepositorySource.class);
+ MimeTypeDetector newDetector = mock(MimeTypeDetector.class);
+ DnaConfiguration config = configuration.addRepository(newSource)
+ .addMimeTypeDetector("default")
+ .usingClass(newDetector.getClass())
+ .describedAs("default mime type detector")
+ .and();
+
+ assertThat(config, is(notNullValue()));
+ assertThat(config.mimeTypeDetectors.get("default").getMimeTypeDetector(), instanceOf(MimeTypeDetector.class));
+ assertThat(config.mimeTypeDetectors.get("invalid name"), is(nullValue()));
+ assertThat(config.mimeTypeDetectors.get("default").getDescription(), is("default mime type detector"));
+ }
+
+ @Test
+ public void shouldAllowAddingSequencer() {
+ RepositorySource newSource = mock(RepositorySource.class);
+
+ DnaConfiguration config = configuration.addRepository(newSource)
+ .addSequencer("sequencerA")
+ .usingClass(MockSequencerA.class)
+ .describedAs("Mock Sequencer A")
+ .sequencingFrom("/foo/source")
+ .andOutputtingTo("/foo/target")
+ .sequencingFrom("/bar/source")
+ .andOutputtingTo("/bar/target")
+ .and()
+ .addSequencer("sequencerB")
+ .usingClass(MockSequencerB.class)
+ .sequencingFrom("/baz/source")
+ .andOutputtingTo("/baz/target")
+ .describedAs("Mock Sequencer B")
+ .and();
+
+ assertThat(config, is(notNullValue()));
+ assertThat(config.sequencers.get("default"), is(nullValue()));
+ assertThat(config.sequencers.get("sequencerA").getSequencer(), instanceOf(MockSequencerA.class));
+ assertThat(config.sequencers.get("sequencerB").getSequencer(), instanceOf(MockSequencerB.class));
+
+ DnaSequencerDetails detailsA = config.sequencers.get("sequencerA");
+ assertThat(detailsA.getDescription(), is("Mock Sequencer A"));
+ assertThat(detailsA.sourcePathExpressions.size(), is(2));
+ assertThat(detailsA.sourcePathExpressions.get(0).toString(), is("/foo/source"));
+ assertThat(detailsA.targetPathExpressions.get(0).toString(), is("/foo/target"));
+ assertThat(detailsA.sourcePathExpressions.get(1).toString(), is("/bar/source"));
+ assertThat(detailsA.targetPathExpressions.get(1).toString(), is("/bar/target"));
+
+ DnaSequencerDetails detailsB = config.sequencers.get("sequencerB");
+ assertThat(detailsB.getDescription(), is("Mock Sequencer B"));
+ assertThat(detailsB.sourcePathExpressions.size(), is(1));
+ assertThat(detailsB.sourcePathExpressions.get(0).toString(), is("/baz/source"));
+ assertThat(detailsB.targetPathExpressions.get(0).toString(), is("/baz/target"));
+ }
+
+}
Property changes on: trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaConfigurationTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java 2009-04-22 14:05:41 UTC (rev 846)
@@ -0,0 +1,191 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository;
+
+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 static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import javax.jcr.observation.Event;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.mimetype.MimeTypeDetector;
+import org.jboss.dna.repository.mimetype.MimeTypeDetectors;
+import org.jboss.dna.repository.observation.NodeChanges;
+import org.jboss.dna.repository.sequencer.MockSequencerA;
+import org.jboss.dna.repository.sequencer.SequencingService;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+
+public class DnaEngineTest {
+
+ private DnaEngine engine;
+
+ @Before
+ public void beforeEach() {
+ }
+
+ @Test
+ public void shouldAllowCreatingWithEmptyConfig() {
+ engine = new DnaConfiguration().build();
+ }
+
+ @Test
+ public void shouldAllowCreatingWithConfigRepository() throws InterruptedException {
+ engine = new DnaConfiguration()
+ .withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Configuration Repository")
+ .with("name").setTo("config repo")
+ .and().build();
+
+ assertThat(engine.getRepositorySource("config repo"), is(notNullValue()));
+ assertThat(engine.getRepositorySource("config repo"), is(instanceOf(InMemoryRepositorySource.class)));
+
+ RepositoryLibrary library = engine.getRepositoryService().getRepositorySourceManager();
+ assertThat(library.getConnectionPool("config repo").getInUseCount(), is(0));
+
+ RepositoryConnection connection = library.getConnectionPool("config repo").getConnection();
+ assertThat(connection.ping(500, TimeUnit.MILLISECONDS), is(true));
+ connection.close();
+
+ }
+
+ @Test
+ public void shouldAllowCreatingMultipleRepositories() throws Exception {
+ engine = new DnaConfiguration()
+ .withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Configuration Repository")
+ .with("name").setTo("config repo")
+ .and().addRepository("JCR")
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Backing Repository for JCR Implementation")
+ .with("name").setTo("JCR")
+ .and().build();
+
+ assertThat(engine.getRepositorySource("config repo"), is(notNullValue()));
+ assertThat(engine.getRepositorySource("config repo"), is(instanceOf(InMemoryRepositorySource.class)));
+
+ assertThat(engine.getRepositorySource("JCR"), is(notNullValue()));
+ assertThat(engine.getRepositorySource("JCR"), is(instanceOf(InMemoryRepositorySource.class)));
+ assertThat(engine.getRepositorySource("JCR").getName(), is("JCR"));
+
+ RepositoryLibrary library = engine.getRepositoryService().getRepositorySourceManager();
+ RepositoryConnection connection = library.getConnectionPool("JCR").getConnection();
+ assertThat(connection.ping(500, TimeUnit.MILLISECONDS), is(true));
+ connection.close();
+
+ }
+
+ @Test
+ public void shouldAllowAddingMimeTypeDetectors() throws Exception {
+ engine = new DnaConfiguration()
+ .withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Configuration Repository")
+ .with("name").setTo("config repo")
+ .and().addMimeTypeDetector("default")
+ .usingClass(MockMimeTypeDetector.class)
+ .describedAs("Default MimeTypeDetector")
+ .with("mimeType").setTo("mock")
+ .and().build();
+
+ assertThat(engine.getRepositorySource("config repo"), is(notNullValue()));
+ assertThat(engine.getRepositorySource("config repo"), is(instanceOf(InMemoryRepositorySource.class)));
+
+ RepositoryLibrary library = engine.getRepositoryService().getRepositorySourceManager();
+ MimeTypeDetectors detectors = library.getMimeTypeDetectors();
+
+ assertThat(detectors.mimeTypeOf("test", new ByteArrayInputStream("This is useless data".getBytes())), is("mock"));
+ }
+
+ @Test
+ public void shouldAllowAddingSequencers() throws Exception {
+ engine = new DnaConfiguration()
+ .withConfigurationRepository()
+ .usingClass(InMemoryRepositorySource.class)
+ .describedAs("Configuration Repository")
+ .with("name").setTo("config repo")
+ .and().addSequencer("Mock Sequencer A")
+ .usingClass(MockSequencerA.class)
+ .describedAs("A Mock Sequencer")
+ .sequencingFrom("/**").andOutputtingTo("/")
+ .and().build();
+
+ assertThat(engine.getRepositorySource("config repo"), is(notNullValue()));
+ assertThat(engine.getRepositorySource("config repo"), is(instanceOf(InMemoryRepositorySource.class)));
+
+ SequencingService sequencer = engine.getSequencingService();
+ assertThat(sequencer.getStatistics().getNumberOfNodesSequenced(), is(0L));
+
+ NodeChanges changes = NodeChanges.create("", Arrays.asList(new Event[] { }));
+ sequencer.onNodeChanges(changes);
+
+ assertThat(sequencer.getStatistics().getNumberOfNodesSequenced(), is(0L));
+
+ Event e1 = mock(Event.class);
+ stub(e1.getType()).toReturn(Event.NODE_ADDED);
+ stub(e1.getPath()).toReturn("/test");
+ stub(e1.getUserID()).toReturn("Test");
+
+// changes = NodeChanges.create("", Arrays.asList(new Event[] { e1, }));
+// sequencer.onNodeChanges(changes);
+//
+// // Shutdown the engine to force all pending tasks to complete
+// engine.shutdown();
+//
+// assertThat(sequencer.getStatistics().getNumberOfNodesSequenced(), is(1L));
+
+ }
+
+ public static class MockMimeTypeDetector implements MimeTypeDetector {
+ private String mimeType = "";
+
+ public MockMimeTypeDetector() {
+
+ }
+
+ public void setMimeType(String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+ public String mimeTypeOf( String name,
+ InputStream is ) {
+ return mimeType;
+ }
+ }
+
+
+}
Property changes on: trunk/dna-repository/src/test/java/org/jboss/dna/repository/DnaEngineTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/mimetype/AbstractMimeTypeTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/mimetype/AbstractMimeTypeTest.java 2009-04-22 13:38:14 UTC (rev 845)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/mimetype/AbstractMimeTypeTest.java 2009-04-22 14:05:41 UTC (rev 846)
@@ -28,6 +28,7 @@
import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.InputStream;
+import java.util.Collections;
import org.jboss.dna.graph.mimetype.MimeTypeDetector;
import org.junit.After;
import org.junit.Before;
@@ -45,7 +46,7 @@
protected AbstractMimeTypeTest( Class<? extends MimeTypeDetector> detector ) {
assertThat(detector, notNullValue());
- this.config = new MimeTypeDetectorConfig("MIME-Type Detector", "MIME-Type Detector", detector.getName(), null);
+ this.config = new MimeTypeDetectorConfig("MIME-Type Detector", "MIME-Type Detector", Collections.<String, Object>emptyMap(), detector.getName(), null);
}
@Before
17 years
DNA SVN: r845 - in trunk: dna-common/src/test/java/org/jboss/dna/common/component and 3 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-22 09:38:14 -0400 (Wed, 22 Apr 2009)
New Revision: 845
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentConfig.java
trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentLibrary.java
trunk/dna-common/src/test/java/org/jboss/dna/common/component/ComponentConfigTest.java
trunk/dna-common/src/test/java/org/jboss/dna/common/component/SampleComponentConfig.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSet.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer/SequencerConfig.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/SequencerConfigTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/SequencingServiceTest.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/StreamSequencerAdapterTest.java
Log:
DNA-58 Create repository configuration and component
Applied the first patch ("") and a small part of the second (""), which enhanced ComponentConfig to allow properties that are set reflectively on the components when they are instantiated. Subclasses of ComponentConfig were also modified, as were the test cases.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentConfig.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentConfig.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentConfig.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -25,7 +25,9 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.util.CheckArg;
@@ -41,38 +43,73 @@
private final String description;
private final String componentClassname;
private final List<String> classpath;
+ private final Map<String, Object> properties;
private final long timestamp;
/**
* Create a component configuration.
+ *
* @param name the name of the configuration, which is considered to be a unique identifier
* @param description the description
* @param classname the name of the Java class used for the component
* @param classpath the optional classpath (defined in a way compatible with a {@link ClassLoaderFactory}
* @throws IllegalArgumentException if the name is null, empty or blank, or if the classname is null, empty or not a valid
- * Java classname
+ * Java classname
*/
- public ComponentConfig( String name, String description, String classname, String... classpath ) {
- this(name, description, System.currentTimeMillis(), classname, classpath);
+ public ComponentConfig( String name,
+ String description,
+ String classname,
+ String... classpath ) {
+ this(name, description, System.currentTimeMillis(), Collections.<String, Object>emptyMap(), classname, classpath);
}
/**
* Create a component configuration.
+ *
* @param name the name of the configuration, which is considered to be a unique identifier
* @param description the description
+ * @param properties the mapping of properties to values that should be set through reflection after a component is
+ * instantiated with this configuration information
+ * @param classname the name of the Java class used for the component
+ * @param classpath the optional classpath (defined in a way compatible with a {@link ClassLoaderFactory}
+ * @throws IllegalArgumentException if the name is null, empty or blank, or if the class name is null, empty or not a valid
+ * Java class name
+ */
+ public ComponentConfig( String name,
+ String description,
+ Map<String, Object> properties,
+ String classname,
+ String... classpath ) {
+ this(name, description, System.currentTimeMillis(), properties, classname, classpath);
+ }
+
+ /**
+ * Create a component configuration.
+ *
+ * @param name the name of the configuration, which is considered to be a unique identifier
+ * @param description the description
* @param timestamp the timestamp that this component was last changed
+ * @param properties the mapping of properties to values that should be set through reflection after a component is
+ * instantiated with this configuration information
* @param classname the name of the Java class used for the component
* @param classpath the optional classpath (defined in a way compatible with a {@link ClassLoaderFactory}
* @throws IllegalArgumentException if the name is null, empty or blank, or if the classname is null, empty or not a valid
- * Java classname
+ * Java classname
*/
- public ComponentConfig( String name, String description, long timestamp, String classname, String... classpath ) {
+ public ComponentConfig( String name,
+ String description,
+ long timestamp,
+ Map<String, Object> properties,
+ String classname,
+ String... classpath ) {
CheckArg.isNotEmpty(name, "name");
this.name = name.trim();
this.description = description != null ? description.trim() : "";
this.componentClassname = classname;
this.classpath = buildList(classpath);
this.timestamp = timestamp;
+ this.properties = properties != null ? Collections.unmodifiableMap(new HashMap<String, Object>(properties)) : Collections.<String, Object>emptyMap();
+
// Check the classname is a valid classname ...
if (!ClassUtil.isFullyQualifiedClassname(classname)) {
throw new IllegalArgumentException(CommonI18n.componentClassnameNotValid.text(classname, name));
@@ -95,6 +132,7 @@
/**
* Get the name of this component.
+ *
* @return the component name; never null, empty or blank
*/
public String getName() {
@@ -103,6 +141,7 @@
/**
* Get the description for this component
+ *
* @return the description
*/
public String getDescription() {
@@ -111,6 +150,7 @@
/**
* Get the fully-qualified name of the Java class used for instances of this component
+ *
* @return the Java class name of this component; never null or empty and always a valid Java class name
*/
public String getComponentClassname() {
@@ -119,6 +159,7 @@
/**
* Get the classpath defined in terms of strings compatible with a {@link ClassLoaderFactory}.
+ *
* @return the classpath; never null but possibly empty
*/
public List<String> getComponentClasspath() {
@@ -127,6 +168,7 @@
/**
* Get the classpath defined as an array of strings compatible with a {@link ClassLoaderFactory}.
+ *
* @return the classpath as an array; never null but possibly empty
*/
public String[] getComponentClasspathArray() {
@@ -135,6 +177,7 @@
/**
* Get the system timestamp when this configuration object was created.
+ *
* @return the timestamp
*/
public long getTimestamp() {
@@ -142,6 +185,15 @@
}
/**
+ * Get the (unmodifiable) properties to be set through reflection on components of this type after instantiation
+ *
+ * @return the properties to be set through reflection on components of this type after instantiation; never null
+ */
+ public Map<String, Object> getProperties() {
+ return this.properties;
+ }
+
+ /**
* {@inheritDoc}
*/
public int compareTo( ComponentConfig that ) {
@@ -177,10 +229,11 @@
/**
* Determine whether this component has changed with respect to the supplied component. This method basically checks all
* attributes, whereas {@link #equals(Object) equals} only checks the {@link #getClass() type} and {@link #getName()}.
+ *
* @param component the component to be compared with this one
* @return true if this componet and the supplied component have some changes, or false if they are exactly equivalent
* @throws IllegalArgumentException if the supplied component reference is null or is not the same {@link #getClass() type} as
- * this object
+ * this object
*/
public boolean hasChanged( ComponentConfig component ) {
CheckArg.isNotNull(component, "component");
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentLibrary.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentLibrary.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/component/ComponentLibrary.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -26,6 +26,7 @@
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
@@ -35,6 +36,7 @@
import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.SystemFailureException;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.Reflection;
/**
* Maintains the list of component instances for the system. This class does not actively update the component configurations, but
@@ -255,6 +257,14 @@
if (newInstance instanceof Component) {
((Component<ConfigType>)newInstance).setConfiguration(config);
}
+
+ if (config.getProperties() != null) {
+ for (Map.Entry<String, Object> entry : config.getProperties().entrySet()) {
+ // Set the JavaBean-style property on the RepositorySource instance ...
+ Reflection reflection = new Reflection(newInstance.getClass());
+ reflection.invokeSetterMethodOnTarget(entry.getKey(), newInstance, entry.getValue());
+ }
+ }
} catch (Throwable e) {
throw new SystemFailureException(e);
}
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/component/ComponentConfigTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/component/ComponentConfigTest.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/ComponentConfigTest.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -26,6 +26,7 @@
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
+import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
@@ -111,4 +112,12 @@
assertThat(configA.getComponentClasspathArray().length, is(0));
}
+ @Test
+ public void shouldSetValidProperty() {
+ configA = new ComponentConfig("configA", validDescription, System.currentTimeMillis(), Collections.<String, Object>singletonMap("name", "test name"), MockComponentA.class.getName(), (String[])null);
+ assertThat(configA.getComponentClasspath().size(), is(0));
+ assertThat(configA.getComponentClasspathArray().length, is(0));
+ assertThat(configA.getProperties().size(), is(1));
+ assertThat(configA.getProperties().get("name").toString(), is("test name"));
+ }
}
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/component/SampleComponentConfig.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/component/SampleComponentConfig.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/component/SampleComponentConfig.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -23,6 +23,8 @@
*/
package org.jboss.dna.common.component;
+import java.util.Map;
+
/**
* @author Randall Hauch
*/
@@ -36,11 +38,12 @@
* @param name
* @param description
* @param timestamp
+ * @param properties
* @param classname
* @param classpath
*/
- public SampleComponentConfig( String name, String description, long timestamp, String classname, String[] classpath ) {
- super(name, description, timestamp, classname, classpath);
+ public SampleComponentConfig( String name, String description, long timestamp, Map<String, Object> properties, String classname, String[] classpath ) {
+ super(name, description, timestamp, properties, classname, classpath);
}
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSet.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSet.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleSet.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -26,7 +26,6 @@
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.rules.RuleServiceProvider;
@@ -39,6 +38,7 @@
/**
* A description of a set of rules compatible with a JSR-94 rule engine.
+ *
* @author Randall Hauch
*/
@Immutable
@@ -47,10 +47,10 @@
private final String providerUri;
private final String ruleSetUri;
private final String rules;
- private final Map<String, Object> properties;
/**
* Create a JSR-94 rule set definition.
+ *
* @param name the name of the rule set, which is considered the unique identifier
* @param description the description
* @param classname the name of the Java class used for the component
@@ -59,12 +59,19 @@
* @param ruleSetUri the URI of the JSR-94 {@link RuleExecutionSet} represented by this object; if null, the name is used
* @param rules the string containing the rules in a provider-specific language
* @param properties the provider-specific properties, whose values should be strings or byte arrays (the latter if the
- * provider expects an {@link Reader} with the value)
+ * provider expects an {@link Reader} with the value)
* @throws IllegalArgumentException if any of the name, classname, provider URI, or rules parameters are null, empty or blank,
- * or if the classname is not a valid Java classname
+ * or if the classname is not a valid Java classname
*/
- public RuleSet( String name, String description, String classname, String[] classpath, String providerUri, String ruleSetUri, String rules, Map<String, Object> properties ) {
- super(name, description, System.currentTimeMillis(), classname, classpath);
+ public RuleSet( String name,
+ String description,
+ String classname,
+ String[] classpath,
+ String providerUri,
+ String ruleSetUri,
+ String rules,
+ Map<String, Object> properties ) {
+ super(name, description, System.currentTimeMillis(), properties, classname, classpath);
if (ruleSetUri == null) ruleSetUri = name.trim();
CheckArg.isNotEmpty(ruleSetUri, "rule set URI");
CheckArg.isNotEmpty(providerUri, "provider URI");
@@ -72,12 +79,11 @@
this.providerUri = providerUri;
this.ruleSetUri = ruleSetUri;
this.rules = rules;
- if (properties == null) properties = Collections.emptyMap();
- this.properties = Collections.unmodifiableMap(properties);
}
/**
* Get the URI of the JSR-94 {@link RuleServiceProvider} implementation that should be used.
+ *
* @return the URI of the JSR-94 implementation; never null, empty or blank
*/
public String getProviderUri() {
@@ -86,6 +92,7 @@
/**
* Get the URI of this rule set. The value must be valid as defined by JSR-94 {@link RuleExecutionSet}.
+ *
* @return the rule set's URI; never null, empty or blank
*/
public String getRuleSetUri() {
@@ -94,6 +101,7 @@
/**
* Get the rules defined in terms of the language reqired by the {@link #getProviderUri() provider}.
+ *
* @return the rules for this rule set
*/
public String getRules() {
@@ -101,27 +109,18 @@
}
/**
- * Get this rule set's properties as an unmodifiable map. Note that the values of these properties are either strings if the
- * value is to be {@link #getExecutionSetProperties() passed} literally, or a byte array if the value is to be
- * {@link #getExecutionSetProperties() passed} as an InputStream.
- * @return the unmodifiable properties; never null but possible empty
- */
- public Map<String, Object> getProperties() {
- return this.properties;
- }
-
- /**
* Get the properties for this rule set that can be passed to an {@link RuleExecutionSetProvider}'s
* {@link RuleExecutionSetProvider#createRuleExecutionSet(String, Map) createRuleExecutionSet} method.
* <p>
* This method converts any byte array value in the {@link #getProperties() properties} into an {@link Reader}. Since
* {@link ByteArrayInputStream} is used, there is no need to close these stream.
* </p>
+ *
* @return the properties; never null but possible empty
*/
public Map<Object, Object> getExecutionSetProperties() {
Map<Object, Object> props = new HashMap<Object, Object>();
- for (Map.Entry<String, Object> entry : this.properties.entrySet()) {
+ for (Map.Entry<String, Object> entry : getProperties().entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof byte[]) {
@@ -149,6 +148,7 @@
*/
@Override
public RuleSet clone() {
- return new RuleSet(this.getName(), this.getDescription(), this.getComponentClassname(), this.getComponentClasspathArray(), this.providerUri, this.ruleSetUri, this.rules, this.properties);
+ return new RuleSet(getName(), getDescription(), getComponentClassname(), getComponentClasspathArray(), this.providerUri,
+ this.ruleSetUri, this.rules, getProperties());
}
}
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer/SequencerConfig.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer/SequencerConfig.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer/SequencerConfig.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -26,6 +26,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
+import java.util.Map;
import java.util.Set;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.component.ComponentConfig;
@@ -38,12 +39,12 @@
private final Set<SequencerPathExpression> pathExpressions;
- public SequencerConfig( String name, String description, String classname, String[] classpath, String... pathExpressions ) {
- this(name, description, System.currentTimeMillis(), classname, classpath, pathExpressions);
+ public SequencerConfig( String name, String description, Map<String, Object> properties, String classname, String[] classpath, String... pathExpressions ) {
+ this(name, description, System.currentTimeMillis(), properties, classname, classpath, pathExpressions);
}
- public SequencerConfig( String name, String description, long timestamp, String classname, String[] classpath, String... pathExpressions ) {
- super(name, description, timestamp, classname, classpath);
+ public SequencerConfig( String name, String description, long timestamp, Map<String, Object> properties, String classname, String[] classpath, String... pathExpressions ) {
+ super(name, description, timestamp, properties, classname, classpath);
this.pathExpressions = buildPathExpressionSet(pathExpressions);
}
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/SequencerConfigTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/SequencerConfigTest.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/SequencerConfigTest.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -24,6 +24,7 @@
package org.jboss.dna.repository.sequencer;
+import java.util.Collections;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import org.jboss.dna.repository.sequencer.SequencerConfig;
@@ -51,47 +52,47 @@
this.validClassname = MockSequencerA.class.getName();
this.validPathExpressions = new String[] {"/a/b/c/d[e/@attribute] => ."};
this.validMavenIds = new String[] {"com.acme:configA:1.0,com.acme:configB:1.0"};
- this.configA = new SequencerConfig("configA", validDescription, MockSequencerA.class.getName(), validMavenIds,
+ this.configA = new SequencerConfig("configA", validDescription, Collections.<String, Object>emptyMap(), MockSequencerA.class.getName(), validMavenIds,
validPathExpressions);
- this.configB = new SequencerConfig("configB", validDescription, MockSequencerB.class.getName(), validMavenIds,
+ this.configB = new SequencerConfig("configB", validDescription, Collections.<String, Object>emptyMap(), MockSequencerB.class.getName(), validMavenIds,
validPathExpressions);
- this.configA2 = new SequencerConfig("conFigA", validDescription, MockSequencerA.class.getName(), validMavenIds,
+ this.configA2 = new SequencerConfig("conFigA", validDescription, Collections.<String, Object>emptyMap(), MockSequencerA.class.getName(), validMavenIds,
validPathExpressions);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowNullNameInConstructor() {
- new SequencerConfig(null, validDescription, validClassname, validMavenIds, validPathExpressions);
+ new SequencerConfig(null, validDescription, Collections.<String, Object>emptyMap(), validClassname, validMavenIds, validPathExpressions);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowEmptyNameInConstructor() {
- new SequencerConfig("", validDescription, validClassname, validMavenIds, validPathExpressions);
+ new SequencerConfig("", validDescription, Collections.<String, Object>emptyMap(), validClassname, validMavenIds, validPathExpressions);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowBlankNameInConstructor() {
- new SequencerConfig(" \t", validDescription, validClassname, validMavenIds, validPathExpressions);
+ new SequencerConfig(" \t", validDescription, Collections.<String, Object>emptyMap(), validClassname, validMavenIds, validPathExpressions);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowNullClassNameInConstructor() {
- new SequencerConfig(validName, validDescription, null, validMavenIds, validPathExpressions);
+ new SequencerConfig(validName, validDescription, Collections.<String, Object>emptyMap(), null, validMavenIds, validPathExpressions);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowEmptyClassNameInConstructor() {
- new SequencerConfig(validName, validDescription, "", validMavenIds, validPathExpressions);
+ new SequencerConfig(validName, validDescription, Collections.<String, Object>emptyMap(), "", validMavenIds, validPathExpressions);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowBlankClassNameInConstructor() {
- new SequencerConfig(validName, validDescription, " \t", validMavenIds, validPathExpressions);
+ new SequencerConfig(validName, validDescription, Collections.<String, Object>emptyMap(), " \t", validMavenIds, validPathExpressions);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowInvalidClassNameInConstructor() {
- new SequencerConfig(validName, validDescription, "12.this is not a valid classname", validMavenIds, validPathExpressions);
+ new SequencerConfig(validName, validDescription, Collections.<String, Object>emptyMap(), "12.this is not a valid classname", validMavenIds, validPathExpressions);
}
@Test
@@ -118,7 +119,7 @@
@Test
public void shouldHaveNonNullPathExpressionCollectionWhenThereAreNoPathExpressions() {
- configA = new SequencerConfig("configA", validDescription, validClassname, validMavenIds);
+ configA = new SequencerConfig("configA", validDescription, Collections.<String, Object>emptyMap(), validClassname, validMavenIds);
assertThat(configA.getPathExpressions().size(), is(0));
}
@@ -130,7 +131,7 @@
@Test
public void shouldGetNonNullSequencerClasspathWhenEmpty() {
- configA = new SequencerConfig("configA", validDescription, validClassname, null, validPathExpressions);
+ configA = new SequencerConfig("configA", validDescription, Collections.<String, Object>emptyMap(), validClassname, null, validPathExpressions);
assertThat(configA.getComponentClasspath().size(), is(0));
assertThat(configA.getComponentClasspathArray().length, is(0));
}
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/SequencingServiceTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/SequencingServiceTest.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/SequencingServiceTest.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.hasItem;
import java.io.IOException;
+import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -306,7 +307,7 @@
String classname = MockSequencerA.class.getName();
String[] classpath = null;
String[] pathExpressions = {"/testnodeC/testnodeD/@description => ."};
- SequencerConfig configA = new SequencerConfig(name, desc, classname, classpath, pathExpressions);
+ SequencerConfig configA = new SequencerConfig(name, desc, Collections.<String, Object>emptyMap(), classname, classpath, pathExpressions);
sequencingService.addSequencer(configA);
// Start the repository and get a session ...
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/StreamSequencerAdapterTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/StreamSequencerAdapterTest.java 2009-04-22 09:41:25 UTC (rev 844)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencer/StreamSequencerAdapterTest.java 2009-04-22 13:38:14 UTC (rev 845)
@@ -69,7 +69,7 @@
private StreamSequencer streamSequencer;
private StreamSequencerAdapter sequencer;
private String[] validExpressions = {"/a/* => /output"};
- private SequencerConfig validConfig = new SequencerConfig("name", "desc", "something.class", null, validExpressions);
+ private SequencerConfig validConfig = new SequencerConfig("name", "desc", Collections.<String, Object>emptyMap(), "something.class", null, validExpressions);
private JcrTools tools;
private Session session;
private SequencerOutputMap sequencerOutput;
17 years
DNA SVN: r844 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/property/basic and 3 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-22 05:41:25 -0400 (Wed, 22 Apr 2009)
New Revision: 844
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/ChildPath.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
Log:
DNA-364 Session.move Is Not Implemented
Applied the patch, which implements the spec and passes the TCK unit tests.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-04-22 09:22:16 UTC (rev 843)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-04-22 09:41:25 UTC (rev 844)
@@ -196,9 +196,9 @@
InMemoryNode newParent = workspace.getNode(newParentPath);
workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace, newParent);
assert node.getParent() == newParent;
- Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName().getName());
+ Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
Location oldLocation = getActualLocation(request.from().getPath(), node);
- Location newLocation = Location.create(newPath, node.getUuid());
+ Location newLocation = Location.create(newPath, newParent.getUuid());
request.setActualLocations(oldLocation, newLocation);
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/ChildPath.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/ChildPath.java 2009-04-22 09:22:16 UTC (rev 843)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/ChildPath.java 2009-04-22 09:41:25 UTC (rev 844)
@@ -109,7 +109,7 @@
@Override
public Segment getSegment( int index ) {
if (index == (size - 1)) return child;
- return parent.getSegment(index - 1);
+ return parent.getSegment(index);
}
/**
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java 2009-04-22 09:22:16 UTC (rev 843)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java 2009-04-22 09:41:25 UTC (rev 844)
@@ -265,7 +265,9 @@
*/
public boolean changes( String workspace,
Path path ) {
- return this.workspaceName.equals(workspace) && into.hasPath() && into.getPath().isAtOrBelow(path);
+ return this.workspaceName.equals(workspace)
+ && (into.hasPath() && into.getPath().isAtOrBelow(path)
+ || from.hasPath() && from.getPath().isAtOrBelow(path));
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java 2009-04-22 09:22:16 UTC (rev 843)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java 2009-04-22 09:41:25 UTC (rev 844)
@@ -99,7 +99,7 @@
|| uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW;
this.session = session;
- this.currentNode = (AbstractJcrNode)session.getNode(parentPath);
+ this.currentNode = session.getNode(parentPath);
this.uuidBehavior = uuidBehavior;
this.saveMode = saveMode;
@@ -273,9 +273,9 @@
uuid = UUID.fromString(rawUuid.get(0).getString());
}
- AbstractJcrNode newNode = parentNode.addNode(currentNodeName,
- currentProps.get(primaryTypeName).get(0).getString(),
- uuid);
+ AbstractJcrNode newNode = parentNode.addNode(currentNodeName, currentProps.get(primaryTypeName)
+ .get(0)
+ .getString(), uuid);
for (Map.Entry<String, List<Value>> entry : currentProps.entrySet()) {
if (entry.getKey().equals(primaryTypeName)) {
@@ -325,8 +325,9 @@
ByteArrayInputStream is = new ByteArrayInputStream(Base64.decode(s, Base64.URL_SAFE));
currentProps.get(currentPropName).add(session.getValueFactory().createValue(is));
} else {
- currentProps.get(currentPropName).add(session.getValueFactory().createValue(SYSTEM_VIEW_NAME_DECODER.decode(s),
- currentPropType));
+ currentProps.get(currentPropName).add(session.getValueFactory()
+ .createValue(SYSTEM_VIEW_NAME_DECODER.decode(s),
+ currentPropType));
}
} catch (RepositoryException re) {
throw new EnclosingSAXException(re);
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-22 09:22:16 UTC (rev 843)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-04-22 09:41:25 UTC (rev 844)
@@ -62,6 +62,7 @@
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.ValueFactories;
import org.jboss.dna.graph.property.basic.LocalNamespaceRegistry;
import org.jboss.dna.jcr.JcrContentHandler.EnclosingSAXException;
@@ -420,7 +421,7 @@
* @throws PathNotFoundException if the path could not be found
* @throws RepositoryException if there is a problem
*/
- Node getNode( Path path ) throws RepositoryException, PathNotFoundException {
+ AbstractJcrNode getNode( Path path ) throws RepositoryException, PathNotFoundException {
if (path.isRoot()) return cache.findJcrRootNode();
return cache.findJcrNode(null, path.relativeTo(rootPath));
}
@@ -678,12 +679,30 @@
/**
* {@inheritDoc}
*
- * @throws UnsupportedOperationException always
* @see javax.jcr.Session#move(java.lang.String, java.lang.String)
*/
public void move( String srcAbsPath,
- String destAbsPath ) {
- throw new UnsupportedOperationException();
+ String destAbsPath ) throws ItemExistsException, RepositoryException {
+ CheckArg.isNotNull(srcAbsPath, "srcAbsPath");
+ CheckArg.isNotNull(destAbsPath, "destAbsPath");
+
+ PathFactory pathFactory = executionContext.getValueFactories().getPathFactory();
+ Path destPath = pathFactory.create(destAbsPath);
+
+ Path.Segment newNodeName = destPath.getSegment(destPath.size() - 1);
+ // Doing a literal test here because the path factory will canonicalize "/node[1]" to "/node"
+ if (destAbsPath.endsWith("]")) {
+ throw new RepositoryException();
+ }
+
+ AbstractJcrNode sourceNode = getNode(pathFactory.create(srcAbsPath));
+ AbstractJcrNode newParentNode = getNode(destPath.getParent());
+
+ if (newParentNode.hasNode(newNodeName.getString(executionContext.getNamespaceRegistry()))) {
+ throw new ItemExistsException();
+ }
+
+ newParentNode.editor().moveToBeChild(sourceNode.nodeUuid, newNodeName.getName());
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java 2009-04-22 09:22:16 UTC (rev 843)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyDefinitionId.java 2009-04-22 09:41:25 UTC (rev 844)
@@ -74,7 +74,7 @@
private final String stringRepresentation;
/**
- * Create a new identifier for a propety definition.
+ * Create a new identifier for a property definition.
*
* @param nodeTypeName the name of the node type; may not be null
* @param propertyDefinitionName the name of the property definition, which may be a {@link #ANY_NAME residual property}; may
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-22 09:22:16 UTC (rev 843)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-04-22 09:41:25 UTC (rev 844)
@@ -445,6 +445,7 @@
* newly created node will have it's parent's UUID in branchUuids, but not the new node's uuid.
*/
Set<UUID> uuidsUnderBranch = new HashSet<UUID>();
+ LinkedList<UUID> peersToCheck = new LinkedList<UUID>();
for (UUID branchUuid : branchUuids) {
uuidsUnderBranch.add(branchUuid);
ChangedNodeInfo changedNode = changedNodes.get(branchUuid);
@@ -452,10 +453,22 @@
for (ChildNode childNode : changedNode.getChildren()) {
uuidsUnderBranch.add(childNode.getUuid());
}
+
+ Collection<UUID> peers = changedNode.getPeers();
+ if (peers != null) peersToCheck.addAll(peers);
}
}
+ /*
+ * Need to check that any peers in a Session.move operation are both in the save
+ */
+ for (UUID peerUuid : peersToCheck) {
+ if (!uuidsUnderBranch.contains(peerUuid)) {
+ throw new ConstraintViolationException();
+ }
+ }
+
// Now execute the branch ...
Graph.Batch branchBatch = store.batch(new BatchRequestBuilder(branchRequests));
try {
@@ -899,6 +912,7 @@
* list of children. This method automatically disconnects the node from its current parent.
*
* @param nodeUuid the UUID of the existing node; may not be null
+ * @param newNodeName
* @return the representation of the newly-added child, which includes the {@link ChildNode#getSnsIndex()
* same-name-sibling index}
* @throws ItemNotFoundException if the specified child node could be found in the session or workspace
@@ -906,7 +920,7 @@
* @throws ConstraintViolationException if moving the node into this node violates this node's definition
* @throws RepositoryException if any other error occurs while reading information from the repository
*/
- public ChildNode moveToBeChild( UUID nodeUuid )
+ public ChildNode moveToBeChild( UUID nodeUuid, Name newNodeName )
throws ItemNotFoundException, InvalidItemStateException, ConstraintViolationException, RepositoryException {
if (nodeUuid.equals(node.getUuid()) || isAncestor(nodeUuid)) {
@@ -942,8 +956,8 @@
if (!definition.getId().equals(node.getDefinitionId())) {
// The node definition changed, so try to set the property ...
try {
- JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, definition.getId()
- .getString());
+ JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING,
+ definition.getId().getString());
setProperty(DnaLexicon.NODE_DEFINITON, value);
} catch (ConstraintViolationException e) {
// We can't set this property on the node (according to the node definition).
@@ -959,14 +973,18 @@
// Remove the node from the current parent and add it to this ...
child = existingParentInfo.removeChild(nodeUuid, pathFactory);
- ChildNode newChild = node.addChild(child.getName(), child.getUuid(), pathFactory);
+ ChildNode newChild = node.addChild(newNodeName, child.getUuid(), pathFactory);
// Set the child's changed representation to point to this node as its parent ...
existingNodeInfo.setParent(node.getUuid());
-
+
+ // Set up the peer relationship between the two nodes that must be saved together
+ node.addPeer(existingParent);
+ existingParentInfo.addPeer(node.getUuid());
+
// Now, record the operation to do this ...
operations.move(existingNodeEditor.currentLocation).into(currentLocation);
-
+
return newChild;
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java 2009-04-22 09:22:16 UTC (rev 843)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java 2009-04-22 09:41:25 UTC (rev 844)
@@ -86,6 +86,8 @@
*/
private NodeDefinitionId changedDefinitionId;
+ private List<UUID> peers;
+
/**
* Create an immutable NodeInfo instance.
*
@@ -97,6 +99,35 @@
}
/**
+ * Returns the peer nodes for this changed node.
+ * <p>
+ * Peer nodes are nodes that must be saved with this node (e.g., the other changed node in a
+ * {@link javax.jcr.Session#move(String, String)} operation.
+ * </p>
+ *
+ * @return a collection of the UUIDs for any other nodes that must be saved with this node; may be null
+ */
+ public final Collection<UUID> getPeers() {
+ return peers;
+ }
+
+ /**
+ * Adds a peer node to this change.
+ * <p>
+ * Peer nodes are nodes that must be saved with this node (e.g., the other changed node in a
+ * {@link javax.jcr.Session#move(String, String)} operation.
+ * </p>
+ *
+ * @param peerUuid the UUID of the peer node
+ */
+ public void addPeer( UUID peerUuid ) {
+ if (peers == null) {
+ peers = new LinkedList<UUID>();
+ }
+ peers.add(peerUuid);
+ }
+
+ /**
* Return the original node information. May be null if this is a new node.
*
* @return the original node information
17 years
DNA SVN: r843 - trunk/dna-jcr/src/main/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-22 05:22:16 -0400 (Wed, 22 Apr 2009)
New Revision: 843
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
Log:
DNA-377 AbstractJcrNode.addNode(String relPath) Throws Wrong Exception if relPath Has Form PropertyName/NodeName
Applied the patch that handles a path of exactly 2 segments, so that the proper exception is thrown.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-22 08:49:23 UTC (rev 842)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-04-22 09:22:16 UTC (rev 843)
@@ -963,23 +963,30 @@
editor = cache.getEditorFor(parentInfo.getUuid());
} catch (PathNotFoundException e) {
// We're going to throw an exception ... the question is which one ...
- if (parentPath.size() > 1) {
- // Per the TCK, if relPath references a property, then we have to throw a ConstraintViolationException
- // So, if we can't find the parent, try for the parent's parent and see if the last segment of the parent's
- // path contains a property ...
- Path grandparentPath = parentPath.getParent();
- assert grandparentPath != null;
- try {
- NodeInfo grandparentInfo = cache.findNodeInfo(nodeUuid, grandparentPath); // throws PathNotFoundException
- if (grandparentInfo.getProperty(parentPath.getLastSegment().getName()) != null) {
- // Need to throw a ConstraintViolationException since the request was to add a child to
- // a property ...
- throw new ConstraintViolationException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
- }
- } catch (PathNotFoundException e2) {
- // eat, since the original exception is what we want ...
+ try {
+ NodeInfo grandparentInfo;
+ if (parentPath.size() > 1) {
+ // Per the TCK, if relPath references a property, then we have to throw a ConstraintViolationException
+ // So, if we can't find the parent, try for the parent's parent and see if the last segment of the parent's
+ // path contains a property ...
+ Path grandparentPath = parentPath.getParent();
+ assert grandparentPath != null;
+
+ grandparentInfo = cache.findNodeInfo(nodeUuid, grandparentPath); // throws PathNotFoundException
}
+ else {
+ grandparentInfo = this.nodeInfo();
+ }
+
+ if (grandparentInfo.getProperty(parentPath.getLastSegment().getName()) != null) {
+ // Need to throw a ConstraintViolationException since the request was to add a child to
+ // a property ...
+ throw new ConstraintViolationException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
+ }
+ } catch (PathNotFoundException e2) {
+ // eat, since the original exception is what we want ...
}
+
// Otherwise, just throw the PathNotFoundException ...
throw e;
}
17 years
DNA SVN: r842 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector and 12 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-22 04:49:23 -0400 (Wed, 22 Apr 2009)
New Revision: 842
Added:
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySourceCapabilities.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/AbstractConnectorTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheWorkspaces.java
trunk/extensions/dna-connector-jbosscache/src/main/resources/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.properties
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java
trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/SVNRepositorySource.java
Log:
DNA-375 Enhance MoveBranchRequest to take a new name, analogous to how CopyBranchRequest works
Changed the connector API's MoveBranchRequest to have a new desiredName() field, and changed the writable connectors to implement these new semantics. Also expose this through the Graph API. Added several tests to the connector unit test framework to test for these additional move behaviors.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -436,10 +436,11 @@
return new MoveAction<Conjunction<Graph>>(this.nextGraph, from) {
@Override
protected Conjunction<Graph> submit( Locations from,
- Location into ) {
+ Location into,
+ Name newName ) {
String workspaceName = getCurrentWorkspaceName();
do {
- requests.moveBranch(from.getLocation(), into, workspaceName);
+ requests.moveBranch(from.getLocation(), into, workspaceName, newName);
} while ((from = from.next()) != null);
return and();
}
@@ -1066,7 +1067,10 @@
public SetValuesTo<Conjunction<Graph>> on( final Location location ) {
return new SetValuesTo<Conjunction<Graph>>() {
public Conjunction<Graph> to( Node value ) {
- return to(value.getLocation());
+ Reference ref = (Reference)convertReferenceValue(value);
+ Property property = getContext().getPropertyFactory().create(propertyName, ref);
+ requests.setProperty(location, getCurrentWorkspaceName(), property);
+ return nextGraph;
}
public Conjunction<Graph> to( Location value ) {
@@ -2023,10 +2027,11 @@
return new MoveAction<BatchConjunction>(this.nextRequests, from) {
@Override
protected BatchConjunction submit( Locations from,
- Location into ) {
+ Location into,
+ Name newName ) {
String workspaceName = getCurrentWorkspaceName();
do {
- requestQueue.moveBranch(from.getLocation(), into, workspaceName);
+ requestQueue.moveBranch(from.getLocation(), into, workspaceName, newName);
} while ((from = from.next()) != null);
return and();
}
@@ -3343,6 +3348,18 @@
Node node = (Node)value;
UUID uuid = node.getLocation().getUuid();
if (uuid == null) {
+ // Look for a property ...
+ Property uuidProperty = node.getProperty(DnaLexicon.UUID);
+ if (uuidProperty != null) {
+ uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getFirstValue());
+ } else {
+ uuidProperty = node.getProperty(JcrLexicon.UUID);
+ if (uuidProperty != null) {
+ uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getFirstValue());
+ }
+ }
+ }
+ if (uuid == null) {
String nodeString = node.getLocation().getString(getContext().getNamespaceRegistry());
String msg = GraphI18n.unableToCreateReferenceToNodeWithoutUuid.text(nodeString);
throw new IllegalArgumentException(msg);
@@ -3559,6 +3576,30 @@
}
/**
+ * A component that defines a new name for a node.
+ *
+ * @param <Next> The interface that is to be returned when this request is completed
+ * @author Randall Hauch
+ */
+ public interface AsName<Next> {
+ /**
+ * Finish the request by specifying the new name.
+ *
+ * @param newName the new name
+ * @return the interface for additional requests or actions
+ */
+ Next as( String newName );
+
+ /**
+ * Finish the request by specifying the new name.
+ *
+ * @param newName the new name
+ * @return the interface for additional requests or actions
+ */
+ Next as( Name newName );
+ }
+
+ /**
* A interface that is used to add more locations that are to be copied/moved.
*
* @param <Next> The interface that is to be returned when this request is completed
@@ -3632,7 +3673,7 @@
* @param <Next> The interface that is to be returned when this request is completed
* @author Randall Hauch
*/
- public interface Move<Next> extends Into<Next>, And<Move<Next>> {
+ public interface Move<Next> extends AsName<Into<Next>>, Into<Next>, And<Move<Next>> {
}
/**
@@ -5190,11 +5231,16 @@
/*package*/Path createPath( String path ) {
return Graph.this.getContext().getValueFactories().getPathFactory().create(path);
}
+
+ /*package*/Name createName( String name ) {
+ return Graph.this.getContext().getValueFactories().getNameFactory().create(name);
+ }
}
@NotThreadSafe
protected abstract class MoveAction<T> extends AbstractAction<T> implements Move<T> {
private final Locations from;
+ private Name newName;
/*package*/MoveAction( T afterConjunction,
Location from ) {
@@ -5238,39 +5284,55 @@
return this;
}
+ public Into<T> as( Name newName ) {
+ this.newName = newName;
+ return this;
+ }
+
/**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.Graph.AsName#as(java.lang.String)
+ */
+ public Into<T> as( String newName ) {
+ return as(createName(newName));
+ }
+
+ /**
* Submit any requests to move the targets into the supplied parent location
*
* @param from the location(s) that are being moved; never null
* @param into the parent location
+ * @param newName the new name for the node being moved; may be null
* @return this object, for method chaining
*/
protected abstract T submit( Locations from,
- Location into );
+ Location into,
+ Name newName );
public T into( Location into ) {
- return submit(from, into);
+ return submit(from, into, newName);
}
public T into( Path into ) {
- return submit(from, Location.create(into));
+ return submit(from, Location.create(into), newName);
}
public T into( UUID into ) {
- return submit(from, Location.create(into));
+ return submit(from, Location.create(into), newName);
}
public T into( Property firstIdProperty,
Property... additionalIdProperties ) {
- return submit(from, Location.create(firstIdProperty, additionalIdProperties));
+ return submit(from, Location.create(firstIdProperty, additionalIdProperties), newName);
}
public T into( Property into ) {
- return submit(from, Location.create(into));
+ return submit(from, Location.create(into), newName);
}
public T into( String into ) {
- return submit(from, Location.create(createPath(into)));
+ return submit(from, Location.create(createPath(into)), newName);
}
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySourceCapabilities.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySourceCapabilities.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySourceCapabilities.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -55,32 +55,41 @@
*/
public static final boolean DEFAULT_SUPPORT_CREATING_WORKSPACES = false;
+ /**
+ * The default support for creating workspaces is {@value} .
+ */
+ public static final boolean DEFAULT_SUPPORT_REFERENCES = true;
+
private boolean sameNameSiblings;
private boolean updates;
private boolean events;
private boolean creatingWorkspaces;
+ private boolean references;
/**
* Create a capabilities object using the defaults, .
*/
public RepositorySourceCapabilities() {
this(DEFAULT_SUPPORT_SAME_NAME_SIBLINGS, DEFAULT_SUPPORT_UPDATES, DEFAULT_SUPPORT_EVENTS,
- DEFAULT_SUPPORT_CREATING_WORKSPACES);
+ DEFAULT_SUPPORT_CREATING_WORKSPACES, DEFAULT_SUPPORT_REFERENCES);
}
public RepositorySourceCapabilities( boolean supportsSameNameSiblings,
boolean supportsUpdates ) {
- this(supportsSameNameSiblings, supportsUpdates, DEFAULT_SUPPORT_EVENTS, DEFAULT_SUPPORT_CREATING_WORKSPACES);
+ this(supportsSameNameSiblings, supportsUpdates, DEFAULT_SUPPORT_EVENTS, DEFAULT_SUPPORT_CREATING_WORKSPACES,
+ DEFAULT_SUPPORT_REFERENCES);
}
public RepositorySourceCapabilities( boolean supportsSameNameSiblings,
boolean supportsUpdates,
boolean supportsEvents,
- boolean supportsCreatingWorkspaces ) {
+ boolean supportsCreatingWorkspaces,
+ boolean supportsReferences ) {
this.sameNameSiblings = supportsSameNameSiblings;
this.updates = supportsUpdates;
this.events = supportsEvents;
this.creatingWorkspaces = supportsCreatingWorkspaces;
+ this.references = supportsReferences;
}
/**
@@ -104,6 +113,15 @@
}
/**
+ * Return whether the source supports references by identifiers.
+ *
+ * @return true if references are supported, or false otherwise
+ */
+ public boolean supportsReferences() {
+ return references;
+ }
+
+ /**
* Return whether the source supports events through {@link RepositorySourceListener}s.
*
* @return true if events are supported, or false if the source is not capable of generating events
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -342,11 +342,13 @@
*
* @param context
* @param node the node to be moved; may not be the {@link Workspace#getRoot() root}
+ * @param desiredNewName the new name for the node, if it is to be changed; may be null
* @param newWorkspace the workspace containing the new parent node
* @param newParent the new parent; may not be the {@link Workspace#getRoot() root}
*/
public void moveNode( ExecutionContext context,
InMemoryNode node,
+ Name desiredNewName,
Workspace newWorkspace,
InMemoryNode newParent ) {
assert context != null;
@@ -355,16 +357,22 @@
assert newWorkspace.getRoot().equals(newParent) != true;
assert this.getRoot().equals(node) != true;
InMemoryNode oldParent = node.getParent();
+ Name oldName = node.getName().getName();
if (oldParent != null) {
if (oldParent.equals(newParent)) return;
boolean removed = oldParent.getChildren().remove(node);
assert removed == true;
node.setParent(null);
- correctSameNameSiblingIndexes(context, oldParent, node.getName().getName());
+ correctSameNameSiblingIndexes(context, oldParent, oldName);
}
node.setParent(newParent);
+ Name newName = oldName;
+ if (desiredNewName != null) {
+ newName = desiredNewName;
+ node.setName(context.getValueFactories().getPathFactory().createSegment(desiredNewName, 1));
+ }
newParent.getChildren().add(node);
- correctSameNameSiblingIndexes(context, newParent, node.getName().getName());
+ correctSameNameSiblingIndexes(context, newParent, newName);
// If the node was moved to a new workspace...
if (!this.equals(newWorkspace)) {
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -71,7 +71,8 @@
*/
public static final int DEFAULT_RETRY_LIMIT = 0;
- protected static final RepositorySourceCapabilities CAPABILITIES = new RepositorySourceCapabilities(true, true, false, true);
+ protected static final RepositorySourceCapabilities CAPABILITIES = new RepositorySourceCapabilities(true, true, false, true,
+ true);
protected static final String ROOT_NODE_UUID = "rootNodeUuid";
protected static final String SOURCE_NAME = "sourceName";
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -192,11 +192,11 @@
InMemoryNode node = getTargetNode(workspace, request, request.from());
if (node == null) return;
// Look up the new parent, which must exist ...
- Path newPath = request.into().getPath();
- Path newParentPath = newPath.getParent();
+ Path newParentPath = request.into().getPath();
InMemoryNode newParent = workspace.getNode(newParentPath);
- node.setParent(newParent);
- newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
+ workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace, newParent);
+ assert node.getParent() == newParent;
+ Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName().getName());
Location oldLocation = getActualLocation(request.from().getPath(), node);
Location newLocation = Location.create(newPath, node.getUuid());
request.setActualLocations(oldLocation, newLocation);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -619,6 +619,23 @@
* @param from the location of the top node in the existing branch that is to be moved
* @param into the location of the existing node into which the branch should be moved
* @param workspaceName the name of the workspace
+ * @param newNameForNode the new name for the node being moved, or null if the name of the original should be used
+ * @return this builder for method chaining; never null
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public BatchRequestBuilder moveBranch( Location from,
+ Location into,
+ String workspaceName,
+ Name newNameForNode ) {
+ return add(new MoveBranchRequest(from, into, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ }
+
+ /**
+ * Create a request to move a branch from one location into another.
+ *
+ * @param from the location of the top node in the existing branch that is to be moved
+ * @param into the location of the existing node into which the branch should be moved
+ * @param workspaceName the name of the workspace
* @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
* location
* @return this builder for method chaining; never null
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -27,6 +27,7 @@
import org.jboss.dna.graph.GraphI18n;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.NodeConflictBehavior;
+import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
/**
@@ -43,6 +44,7 @@
private final Location from;
private final Location into;
private final String workspaceName;
+ private final Name desiredNameForNode;
private final NodeConflictBehavior conflictBehavior;
private Location actualOldLocation;
private Location actualNewLocation;
@@ -58,7 +60,7 @@
public MoveBranchRequest( Location from,
Location into,
String workspaceName ) {
- this(from, into, workspaceName, DEFAULT_CONFLICT_BEHAVIOR);
+ this(from, into, workspaceName, null, DEFAULT_CONFLICT_BEHAVIOR);
}
/**
@@ -67,6 +69,22 @@
* @param from the location of the top node in the existing branch that is to be moved
* @param into the location of the existing node into which the branch should be moved
* @param workspaceName the name of the workspace
+ * @param newNameForMovedNode the new name for the node being moved, or null if the name of the original should be used
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public MoveBranchRequest( Location from,
+ Location into,
+ String workspaceName,
+ Name newNameForMovedNode ) {
+ this(from, into, workspaceName, newNameForMovedNode, DEFAULT_CONFLICT_BEHAVIOR);
+ }
+
+ /**
+ * Create a request to move a branch from one location into another.
+ *
+ * @param from the location of the top node in the existing branch that is to be moved
+ * @param into the location of the existing node into which the branch should be moved
+ * @param workspaceName the name of the workspace
* @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
* location
* @throws IllegalArgumentException if any of the parameters are null
@@ -75,6 +93,25 @@
Location into,
String workspaceName,
NodeConflictBehavior conflictBehavior ) {
+ this(from, into, workspaceName, null, conflictBehavior);
+ }
+
+ /**
+ * Create a request to move a branch from one location into another.
+ *
+ * @param from the location of the top node in the existing branch that is to be moved
+ * @param into the location of the existing node into which the branch should be moved
+ * @param workspaceName the name of the workspace
+ * @param newNameForMovedNode the new name for the node being moved, or null if the name of the original should be used
+ * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
+ * location
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public MoveBranchRequest( Location from,
+ Location into,
+ String workspaceName,
+ Name newNameForMovedNode,
+ NodeConflictBehavior conflictBehavior ) {
CheckArg.isNotNull(from, "from");
CheckArg.isNotNull(into, "into");
CheckArg.isNotNull(workspaceName, "workspaceName");
@@ -82,6 +119,7 @@
this.from = from;
this.into = into;
this.workspaceName = workspaceName;
+ this.desiredNameForNode = newNameForMovedNode;
this.conflictBehavior = conflictBehavior;
}
@@ -113,6 +151,15 @@
}
/**
+ * Get the name of the copy if it is to be different than that of the original.
+ *
+ * @return the desired name of the copy, or null if the name of the original is to be used
+ */
+ public Name desiredName() {
+ return desiredNameForNode;
+ }
+
+ /**
* Get the expected behavior when copying the branch and the {@link #into() destination} already has a node with the same
* name.
*
@@ -150,7 +197,9 @@
*/
public boolean hasNoEffect() {
if (into.hasPath() && into.hasIdProperties() == false && from.hasPath()) {
- return from.getPath().getParent().equals(into.getPath());
+ if (!from.getPath().getParent().equals(into.getPath())) return false;
+ if (desiredName() != null && !desiredName().equals(from.getPath().getLastSegment().getName())) return false;
+ return true;
}
// Can't be determined for certain
return false;
@@ -160,8 +209,8 @@
* Sets the actual and complete location of the node being renamed and its new location. This method must be called when
* processing the request, and the actual location must have a {@link Location#getPath() path}.
*
- * @param oldLocation the actual location of the node before being renamed
- * @param newLocation the actual location of the new copy of the node
+ * @param oldLocation the actual location of the node before being moved
+ * @param newLocation the actual new location of the node
* @throws IllegalArgumentException if the either location is null, if the old location does not represent the
* {@link Location#isSame(Location) same location} as the {@link #from() from location}, if the new location does not
* represent the {@link Location#isSame(Location) same location} as the {@link #into() into location}, or if the
@@ -169,20 +218,25 @@
*/
public void setActualLocations( Location oldLocation,
Location newLocation ) {
+ CheckArg.isNotNull(oldLocation, "oldLocation");
+ CheckArg.isNotNull(newLocation, "newLocation");
if (!from.isSame(oldLocation)) { // not same if actual is null
throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(oldLocation, from));
}
- if (!into.isSame(newLocation, false)) { // not same if actual is null
- throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(newLocation, into));
- }
- assert oldLocation != null;
- assert newLocation != null;
if (!oldLocation.hasPath()) {
throw new IllegalArgumentException(GraphI18n.actualOldLocationMustHavePath.text(oldLocation));
}
if (!newLocation.hasPath()) {
throw new IllegalArgumentException(GraphI18n.actualNewLocationMustHavePath.text(newLocation));
}
+ if (into().hasPath() && !newLocation.getPath().getParent().isSameAs(into.getPath())) {
+ throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(newLocation, into));
+ }
+ Name actualNewName = newLocation.getPath().getLastSegment().getName();
+ Name expectedNewName = desiredName() != null ? desiredName() : oldLocation.getPath().getLastSegment().getName();
+ if (!actualNewName.equals(expectedNewName)) {
+ throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(newLocation, into));
+ }
this.actualNewLocation = newLocation;
}
@@ -249,6 +303,10 @@
*/
@Override
public String toString() {
- return "move branch " + from() + " in the \"" + workspaceName + "\" workspace into " + into();
+ if (desiredName() != null) {
+ return "move branch " + from() + " in the \"" + inWorkspace() + "\" workspace into " + into() + " with name "
+ + desiredName();
+ }
+ return "move branch " + from() + " in the \"" + inWorkspace() + "\" workspace into " + into();
}
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -466,6 +466,23 @@
* @param from the location of the top node in the existing branch that is to be moved
* @param into the location of the existing node into which the branch should be moved
* @param workspaceName the name of the workspace
+ * @param newNameForNode the new name for the node being moved, or null if the name of the original should be used
+ * @return the request; never null
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public MoveBranchRequest moveBranch( Location from,
+ Location into,
+ String workspaceName,
+ Name newNameForNode ) {
+ return process(new MoveBranchRequest(from, into, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ }
+ /**
+ * Create a request to move a branch from one location into another.
+ *
+ * @param from the location of the top node in the existing branch that is to be moved
+ * @param into the location of the existing node into which the branch should be moved
+ * @param workspaceName the name of the workspace
+ * @param newNameForNode the new name for the node being moved, or null if the name of the original should be used
* @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
* location
* @return the request; never null
@@ -474,8 +491,28 @@
public MoveBranchRequest moveBranch( Location from,
Location into,
String workspaceName,
+ Name newNameForNode,
NodeConflictBehavior conflictBehavior ) {
if (conflictBehavior == null) conflictBehavior = MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR;
+ return process(new MoveBranchRequest(from, into, workspaceName, newNameForNode, conflictBehavior));
+ }
+
+ /**
+ * Create a request to move a branch from one location into another.
+ *
+ * @param from the location of the top node in the existing branch that is to be moved
+ * @param into the location of the existing node into which the branch should be moved
+ * @param workspaceName the name of the workspace
+ * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
+ * location
+ * @return the request; never null
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public MoveBranchRequest moveBranch( Location from,
+ Location into,
+ String workspaceName,
+ NodeConflictBehavior conflictBehavior ) {
+ if (conflictBehavior == null) conflictBehavior = MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR;
return process(new MoveBranchRequest(from, into, workspaceName, conflictBehavior));
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -93,6 +93,8 @@
private ExecutionContext context;
private Path validPath;
private String validPathString;
+ private Name validName;
+ private String validNameString;
private UUID validUuid;
private Property validIdProperty1;
private Property validIdProperty2;
@@ -120,6 +122,8 @@
validPathString = "/a/b/c";
validUuid = UUID.randomUUID();
validPath = createPath(validPathString);
+ validNameString = "theName";
+ validName = createName(validNameString);
Name idProperty1Name = createName("id1");
Name idProperty2Name = createName("id2");
validIdProperty1 = context.getPropertyFactory().create(idProperty1Name, "1");
@@ -978,6 +982,15 @@
}
@Test
+ public void shouldMoveAndRenameNodesThroughMultipleMoveRequests() {
+ graph.move(validPath).as(validName).into(validIdProperty1, validIdProperty2).and().move(validUuid).into(validPathString);
+ assertThat(numberOfExecutions, is(2));
+ assertNextRequestIsMove(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
+ assertNextRequestIsMove(Location.create(validUuid), Location.create(createPath(validPathString)));
+ assertNoMoreRequests();
+ }
+
+ @Test
public void shouldIgnoreIncompleteRequests() {
graph.move(validPath); // missing 'into(...)'
assertNoMoreRequests();
@@ -1081,8 +1094,33 @@
@Override
public void process( MoveBranchRequest request ) {
- // Just update the actual location
- request.setActualLocations(actualLocationOf(request.from()), actualLocationOf(request.into()));
+ // Just update the actual location ...
+ Name newName = request.desiredName();
+ if (newName == null && request.from().hasPath()) newName = request.from().getPath().getLastSegment().getName();
+ if (newName == null) newName = context.getValueFactories().getNameFactory().create("d");
+ // Figure out the new name and path (if needed)...
+ Path newPath = null;
+ if (request.into().hasPath()) {
+ newPath = context.getValueFactories().getPathFactory().create(request.into().getPath(), newName);
+ } else if (request.from().hasPath()) {
+ newPath = context.getValueFactories().getPathFactory().create("/a/b/c");
+ newPath = context.getValueFactories().getPathFactory().create(newPath, newName);
+ } else {
+ newPath = context.getValueFactories().getPathFactory().create("/a/b/c");
+ newPath = context.getValueFactories().getPathFactory().create(newPath, newName);
+ }
+ // Figure out the old name and path ...
+ Path oldPath = null;
+ if (request.from().hasPath()) {
+ oldPath = request.from().getPath();
+ } else {
+ oldPath = context.getValueFactories().getPathFactory().create("/x/y/z");
+ oldPath = context.getValueFactories().getPathFactory().create(oldPath, newName);
+ }
+ Location fromLocation = request.from().hasIdProperties() ? Location.create(oldPath, request.from().getIdProperties()) : Location.create(oldPath);
+ Location intoLocation = request.into().hasIdProperties() ? Location.create(newPath, request.into().getIdProperties()) : Location.create(newPath);
+
+ request.setActualLocations(fromLocation, intoLocation);
}
@Override
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -239,7 +239,7 @@
assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
- workspace.moveNode(context, node_b, workspace, node_d);
+ workspace.moveNode(context, node_b, null, workspace, node_d);
assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
@@ -249,7 +249,7 @@
assertThat(workspace.getNode(pathFactory.create("/d/b[2]")), is(sameInstance(node_b)));
assertThat(workspace.getNode(pathFactory.create("/d/b[2]/c")), is(sameInstance(node_c)));
- workspace.moveNode(context, node_b, workspace, node_e);
+ workspace.moveNode(context, node_b, null, workspace, node_e);
assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
@@ -302,7 +302,7 @@
assertThat(new_workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(new_node_b2)));
// Move 'workspace::/a/b' into 'newWorkspace::/d'
- workspace.moveNode(context, node_b, new_workspace, new_node_d);
+ workspace.moveNode(context, node_b, null, new_workspace, new_node_d);
assertThat(workspace.getNodesByUuid().size(), is(5));
assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
@@ -579,7 +579,9 @@
@Test
public void shouldCreateRepositoryStructure() {
- workspace.createNode(context, "/a").setProperty(context, "name", "value").setProperty(context, "desc", "Some description");
+ workspace.createNode(context, "/a")
+ .setProperty(context, "name", "value")
+ .setProperty(context, "desc", "Some description");
workspace.createNode(context, "/a/b").setProperty(context, "name", "value2").setProperty(context,
"desc",
"Some description 2");
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/AbstractConnectorTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/AbstractConnectorTest.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/AbstractConnectorTest.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -38,8 +38,10 @@
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.jboss.dna.common.statistic.Stopwatch;
+import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.Node;
import org.jboss.dna.graph.Subgraph;
@@ -84,6 +86,7 @@
private static List<RepositoryConnection> openConnections;
private static boolean running;
private static Location rootLocation;
+ private static UUID rootUuid;
public void startRepository() throws Exception {
if (!running) {
@@ -141,6 +144,7 @@
} finally {
running = false;
rootLocation = null;
+ rootUuid = null;
}
}
}
@@ -292,11 +296,24 @@
}
protected UUID getRootNodeUuid() {
- if (rootLocation == null) {
+ if (rootUuid == null) {
Node root = graph.getNodeAt("/");
rootLocation = root.getLocation();
+ rootUuid = rootLocation.getUuid();
+ if (rootUuid == null) {
+ Property uuid = root.getProperty(DnaLexicon.UUID);
+ if (uuid != null) {
+ rootUuid = context.getValueFactories().getUuidFactory().create(uuid.getFirstValue());
+ }
+ }
+ if (rootUuid == null) {
+ Property uuid = root.getProperty(JcrLexicon.UUID);
+ if (uuid != null) {
+ rootUuid = context.getValueFactories().getUuidFactory().create(uuid.getFirstValue());
+ }
+ }
}
- return rootLocation.getUuid();
+ return rootUuid;
}
protected String string( Object value ) {
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -105,9 +105,19 @@
@Test
public void shouldAddChildrenAndSettingProperties() {
- graph.batch().set("propA").to("valueA").on("/").and().create("/a").with("propB", "valueB").and("propC", "valueC").and().create("/b").with("propD",
- "valueD").and("propE",
- "valueE").execute();
+ graph.batch()
+ .set("propA")
+ .to("valueA")
+ .on("/")
+ .and()
+ .create("/a")
+ .with("propB", "valueB")
+ .and("propC", "valueC")
+ .and()
+ .create("/b")
+ .with("propD", "valueD")
+ .and("propE", "valueE")
+ .execute();
// Now look up the root node ...
Node root = graph.getNodeAt("/");
assertThat(root, is(notNullValue()));
@@ -608,50 +618,54 @@
boolean batch = true;
createSubgraph(graph, initialPath, depth, numChildrenPerNode, numPropertiesPerNode, batch, sw, System.out, null);
- // Create some references between nodes that aren't involved with the copy ...
- graph.set("refProp").on("/node1").to(graph.getNodeAt("/node1/node3"));
- graph.set("refProp").on("/node1/node1").to(graph.getNodeAt("/node3/node2")); // will soon be /node3/node2[1]
+ if (source.getCapabilities().supportsReferences()) {
+ // Create some references between nodes that aren't involved with the copy ...
+ graph.set("refProp").on("/node1").to(graph.getNodeAt("/node1/node3"));
+ graph.set("refProp").on("/node1/node1").to(graph.getNodeAt("/node3/node2")); // will soon be /node3/node2[1]
- // Create some "inward" references from nodes that are NOT being copied to nodes that are being copied ...
- graph.set("refProp").on("/node1/node2").to(graph.getNodeAt("/node2/node2"));
- graph.set("refProp").on("/node1/node3").to(graph.getNodeAt("/node2/node2"));
+ // Create some "inward" references from nodes that are NOT being copied to nodes that are being copied ...
+ graph.set("refProp").on("/node1/node2").to(graph.getNodeAt("/node2/node2"));
+ graph.set("refProp").on("/node1/node3").to(graph.getNodeAt("/node2/node2"));
- // Create some "outward" references from nodes that are being copied to nodes that are NOT being copied ...
- graph.set("refProp").on("/node2/node1").to(graph.getNodeAt("/node1/node1"));
- graph.set("refProp").on("/node2/node3").to(graph.getNodeAt("/node1/node2"));
+ // Create some "outward" references from nodes that are being copied to nodes that are NOT being copied ...
+ graph.set("refProp").on("/node2/node1").to(graph.getNodeAt("/node1/node1"));
+ graph.set("refProp").on("/node2/node3").to(graph.getNodeAt("/node1/node2"));
- // Create some "internal" references between nodes that are being copied ...
- graph.set("refProp").on("/node2/node2").to(graph.getNodeAt("/node2/node2/node1"));
- graph.set("refProp").on("/node2/node3/node1").to(graph.getNodeAt("/node2/node2/node1"));
+ // Create some "internal" references between nodes that are being copied ...
+ graph.set("refProp").on("/node2/node2").to(graph.getNodeAt("/node2/node2/node1"));
+ graph.set("refProp").on("/node2/node3/node1").to(graph.getNodeAt("/node2/node2/node1"));
- // Verify the references are there ...
- assertReference("/node1", "refProp", "/node1/node3");
- assertReference("/node1/node1", "refProp", "/node3/node2");
- assertReference("/node1/node2", "refProp", "/node2/node2");
- assertReference("/node1/node3", "refProp", "/node2/node2");
- assertReference("/node2/node1", "refProp", "/node1/node1");
- assertReference("/node2/node3", "refProp", "/node1/node2");
- assertReference("/node2/node2", "refProp", "/node2/node2/node1");
- assertReference("/node2/node3/node1", "refProp", "/node2/node2/node1");
+ // Verify the references are there ...
+ assertReference("/node1", "refProp", "/node1/node3");
+ assertReference("/node1/node1", "refProp", "/node3/node2");
+ assertReference("/node1/node2", "refProp", "/node2/node2");
+ assertReference("/node1/node3", "refProp", "/node2/node2");
+ assertReference("/node2/node1", "refProp", "/node1/node1");
+ assertReference("/node2/node3", "refProp", "/node1/node2");
+ assertReference("/node2/node2", "refProp", "/node2/node2/node1");
+ assertReference("/node2/node3/node1", "refProp", "/node2/node2/node1");
+ }
// Copy a branches ...
graph.copy("/node2").into("/node3");
- // Verify the references are still there ...
- assertReference("/node1", "refProp", "/node1/node3");
- assertReference("/node1/node1", "refProp", "/node3/node2[1]");
- assertReference("/node1/node2", "refProp", "/node2/node2");
- assertReference("/node1/node3", "refProp", "/node2/node2");
- assertReference("/node2/node1", "refProp", "/node1/node1");
- assertReference("/node2/node3", "refProp", "/node1/node2");
- assertReference("/node2/node2", "refProp", "/node2/node2/node1");
- assertReference("/node2/node3/node1", "refProp", "/node2/node2/node1");
+ if (source.getCapabilities().supportsReferences()) {
+ // Verify the references are still there ...
+ assertReference("/node1", "refProp", "/node1/node3");
+ assertReference("/node1/node1", "refProp", "/node3/node2[1]");
+ assertReference("/node1/node2", "refProp", "/node2/node2");
+ assertReference("/node1/node3", "refProp", "/node2/node2");
+ assertReference("/node2/node1", "refProp", "/node1/node1");
+ assertReference("/node2/node3", "refProp", "/node1/node2");
+ assertReference("/node2/node2", "refProp", "/node2/node2/node1");
+ assertReference("/node2/node3/node1", "refProp", "/node2/node2/node1");
- // And verify that we have a few new (outward and internal) references in the copy ...
- assertReference("/node3/node2[2]/node1", "refProp", "/node1/node1"); // outward
- assertReference("/node3/node2[2]/node3", "refProp", "/node1/node2"); // outward
- assertReference("/node3/node2[2]/node2", "refProp", "/node3/node2[2]/node2/node1"); // internal
- assertReference("/node3/node2[2]/node3/node1", "refProp", "/node3/node2[2]/node2/node1"); // internal
+ // And verify that we have a few new (outward and internal) references in the copy ...
+ assertReference("/node3/node2[2]/node1", "refProp", "/node1/node1"); // outward
+ assertReference("/node3/node2[2]/node3", "refProp", "/node1/node2"); // outward
+ assertReference("/node3/node2[2]/node2", "refProp", "/node3/node2[2]/node2/node1"); // internal
+ assertReference("/node3/node2[2]/node3/node1", "refProp", "/node3/node2[2]/node2/node1"); // internal
+ }
// Now assert the structure ...
assertThat(graph.getChildren().of("/node1"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
@@ -730,9 +744,11 @@
"The quick brown fox jumped over the moon. What? "));
assertThat(subgraph.getNode("node2[2]/node1/node3"), hasProperty("property3",
"The quick brown fox jumped over the moon. What? "));
- assertThat(subgraph.getNode("node2[2]/node2").getChildren(), hasChildren(segment("node1"),
- segment("node2"),
- segment("node3")));
+ if (source.getCapabilities().supportsReferences()) {
+ assertThat(subgraph.getNode("node2[2]/node2").getChildren(), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ }
assertThat(subgraph.getNode("node2[2]/node2"), hasProperty("property1",
"The quick brown fox jumped over the moon. What? "));
assertThat(subgraph.getNode("node2[2]/node2"), hasProperty("property2",
@@ -760,9 +776,11 @@
"The quick brown fox jumped over the moon. What? "));
assertThat(subgraph.getNode("node2[2]/node2/node3"), hasProperty("property3",
"The quick brown fox jumped over the moon. What? "));
- assertThat(subgraph.getNode("node2[2]/node3").getChildren(), hasChildren(segment("node1"),
- segment("node2"),
- segment("node3")));
+ if (source.getCapabilities().supportsReferences()) {
+ assertThat(subgraph.getNode("node2[2]/node3").getChildren(), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ }
assertThat(subgraph.getNode("node2[2]/node3"), hasProperty("property1",
"The quick brown fox jumped over the moon. What? "));
assertThat(subgraph.getNode("node2[2]/node3"), hasProperty("property2",
@@ -805,4 +823,567 @@
}
}
+ @Test
+ public void shouldMoveNodes() {
+ // Create the tree (at total of 40 nodes, plus the extra 6 added later)...
+ // /
+ // /node1
+ // /node1/node1
+ // /node1/node1/node1
+ // /node1/node1/node2
+ // /node1/node1/node3
+ // /node1/node2
+ // /node1/node2/node1
+ // /node1/node2/node2
+ // /node1/node2/node3
+ // /node1/node3
+ // /node1/node3/node1
+ // /node1/node3/node2
+ // /node1/node3/node3
+ // /node2
+ // /node2/node1
+ // /node2/node1/node1
+ // /node2/node1/node2
+ // /node2/node1/node3
+ // /node2/node2
+ // /node2/node2/node1
+ // /node2/node2/node2
+ // /node2/node2/node3
+ // /node2/node3
+ // /node2/node3/node1
+ // /node2/node3/node2
+ // /node2/node3/node3
+ // /node3
+ // /node3/node1
+ // /node3/node1/node1
+ // /node3/node1/node2
+ // /node3/node1/node3
+ // /node3/node2
+ // /node3/node2/node1
+ // /node3/node2/node2
+ // /node3/node2/node3
+ // /node3/node3
+ // /node3/node3/node1
+ // /node3/node3/node2
+ // /node3/node3/node3
+ // /secondBranch1
+ // /secondBranch1/secondBranch1
+ // /secondBranch1/secondBranch2
+ // /secondBranch2
+ // /secondBranch2/secondBranch1
+ // /secondBranch2/secondBranch2
+
+ String initialPath = "";
+ int depth = 3;
+ int numChildrenPerNode = 3;
+ int numPropertiesPerNode = 3;
+ Stopwatch sw = new Stopwatch();
+ boolean batch = true;
+ createSubgraph(graph, initialPath, depth, numChildrenPerNode, numPropertiesPerNode, batch, sw, System.out, null);
+
+ // Delete two branches ...
+ graph.move("/node2").into("/node3");
+
+ // Now assert the structure ...
+ assertThat(graph.getChildren().of("/node1"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node1"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node2"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node3"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node3/node1"), hasChildren());
+
+ assertThat(graph.getChildren().of("/node3"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3"),
+ segment("node2[2]")));
+ assertThat(graph.getChildren().of("/node3/node2"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3/node1"), hasChildren());
+ assertThat(graph.getChildren().of("/node3/node2[2]"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node2[2]/node1"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node2[2]/node2"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node2[2]/node3"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node2[2]/node1/node1"), hasChildren());
+
+ Subgraph subgraph = graph.getSubgraphOfDepth(4).at("/node3");
+ assertThat(subgraph, is(notNullValue()));
+ assertThat(subgraph.getNode(".").getChildren(), hasChildren(segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("."), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]").getChildren(), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]").getChildren(), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("node2[2]"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1").getChildren(), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(subgraph.getNode("node2[2]/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node1/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node1/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node1/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node1/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node2/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node2/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node2/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node2/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node3/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node3/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2[2]/node3/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]/node3/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ }
+
+ @Test
+ public void shouldMoveAndRenameNodes() {
+ // Create the tree (at total of 40 nodes, plus the extra 6 added later)...
+ // /
+ // /node1
+ // /node1/node1
+ // /node1/node1/node1
+ // /node1/node1/node2
+ // /node1/node1/node3
+ // /node1/node2
+ // /node1/node2/node1
+ // /node1/node2/node2
+ // /node1/node2/node3
+ // /node1/node3
+ // /node1/node3/node1
+ // /node1/node3/node2
+ // /node1/node3/node3
+ // /node2
+ // /node2/node1
+ // /node2/node1/node1
+ // /node2/node1/node2
+ // /node2/node1/node3
+ // /node2/node2
+ // /node2/node2/node1
+ // /node2/node2/node2
+ // /node2/node2/node3
+ // /node2/node3
+ // /node2/node3/node1
+ // /node2/node3/node2
+ // /node2/node3/node3
+ // /node3
+ // /node3/node1
+ // /node3/node1/node1
+ // /node3/node1/node2
+ // /node3/node1/node3
+ // /node3/node2
+ // /node3/node2/node1
+ // /node3/node2/node2
+ // /node3/node2/node3
+ // /node3/node3
+ // /node3/node3/node1
+ // /node3/node3/node2
+ // /node3/node3/node3
+ // /secondBranch1
+ // /secondBranch1/secondBranch1
+ // /secondBranch1/secondBranch2
+ // /secondBranch2
+ // /secondBranch2/secondBranch1
+ // /secondBranch2/secondBranch2
+
+ String initialPath = "";
+ int depth = 3;
+ int numChildrenPerNode = 3;
+ int numPropertiesPerNode = 3;
+ Stopwatch sw = new Stopwatch();
+ boolean batch = true;
+ createSubgraph(graph, initialPath, depth, numChildrenPerNode, numPropertiesPerNode, batch, sw, System.out, null);
+
+ // Delete two branches ...
+ graph.move("/node2").as("node3").into("/node3");
+
+ // Now assert the structure ...
+ assertThat(graph.getChildren().of("/"), hasChildren(segment("node1"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node1"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node2"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node3"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node3/node1"), hasChildren());
+
+ assertThat(graph.getChildren().of("/node3"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3"),
+ segment("node3[2]")));
+ assertThat(graph.getChildren().of("/node3/node2"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3/node1"), hasChildren());
+ assertThat(graph.getChildren().of("/node3/node3[2]"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3[2]/node1"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3[2]/node2"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3[2]/node3"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3[2]/node1/node1"), hasChildren());
+
+ Subgraph subgraph = graph.getSubgraphOfDepth(4).at("/node3");
+ assertThat(subgraph, is(notNullValue()));
+ assertThat(subgraph.getNode(".").getChildren(), hasChildren(segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("."), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]").getChildren(), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]").getChildren(), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("node3[2]"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1").getChildren(), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(subgraph.getNode("node3[2]/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node1/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node1/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node1/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node1/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node2/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node2/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node2/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node2/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node3/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node3/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3[2]/node3/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3[2]/node3/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ }
+
+ @Test
+ public void shouldMoveAndRenameNodesToNameWithoutSameNameSibling() {
+ // Create the tree (at total of 40 nodes, plus the extra 6 added later)...
+ // /
+ // /node1
+ // /node1/node1
+ // /node1/node1/node1
+ // /node1/node1/node2
+ // /node1/node1/node3
+ // /node1/node2
+ // /node1/node2/node1
+ // /node1/node2/node2
+ // /node1/node2/node3
+ // /node1/node3
+ // /node1/node3/node1
+ // /node1/node3/node2
+ // /node1/node3/node3
+ // /node2
+ // /node2/node1
+ // /node2/node1/node1
+ // /node2/node1/node2
+ // /node2/node1/node3
+ // /node2/node2
+ // /node2/node2/node1
+ // /node2/node2/node2
+ // /node2/node2/node3
+ // /node2/node3
+ // /node2/node3/node1
+ // /node2/node3/node2
+ // /node2/node3/node3
+ // /node3
+ // /node3/node1
+ // /node3/node1/node1
+ // /node3/node1/node2
+ // /node3/node1/node3
+ // /node3/node2
+ // /node3/node2/node1
+ // /node3/node2/node2
+ // /node3/node2/node3
+ // /node3/node3
+ // /node3/node3/node1
+ // /node3/node3/node2
+ // /node3/node3/node3
+ // /secondBranch1
+ // /secondBranch1/secondBranch1
+ // /secondBranch1/secondBranch2
+ // /secondBranch2
+ // /secondBranch2/secondBranch1
+ // /secondBranch2/secondBranch2
+
+ String initialPath = "";
+ int depth = 3;
+ int numChildrenPerNode = 3;
+ int numPropertiesPerNode = 3;
+ Stopwatch sw = new Stopwatch();
+ boolean batch = true;
+ createSubgraph(graph, initialPath, depth, numChildrenPerNode, numPropertiesPerNode, batch, sw, System.out, null);
+
+ // Delete two branches ...
+ graph.move("/node2").as("nodeX").into("/node3");
+
+ // Now assert the structure ...
+ assertThat(graph.getChildren().of("/"), hasChildren(segment("node1"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node1"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node2"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node3"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node3/node1"), hasChildren());
+
+ assertThat(graph.getChildren().of("/node3"), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3"),
+ segment("nodeX")));
+ assertThat(graph.getChildren().of("/node3/node2"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3/node1"), hasChildren());
+ assertThat(graph.getChildren().of("/node3/nodeX"), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/nodeX/node1"),
+ hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/nodeX/node2"),
+ hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/nodeX/node3"),
+ hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(graph.getChildren().of("/node3/nodeX/node1/node1"), hasChildren());
+
+ Subgraph subgraph = graph.getSubgraphOfDepth(4).at("/node3");
+ assertThat(subgraph, is(notNullValue()));
+ assertThat(subgraph.getNode(".").getChildren(), hasChildren(segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("."), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]").getChildren(), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node3"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX").getChildren(), hasChildren(segment("node1"), segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("nodeX"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1").getChildren(), hasChildren(segment("node1"),
+ segment("node2"),
+ segment("node3")));
+ assertThat(subgraph.getNode("nodeX/node1"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node1/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node1/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node1/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node1/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node2/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node2/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node2/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node2/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3"), hasProperty("property2", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3"), hasProperty("property3", "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node3/node1"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node1"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node1"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node3/node2"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node2"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node2"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("nodeX/node3/node3"), hasProperty("property1",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node3"), hasProperty("property2",
+ "The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("nodeX/node3/node3"), hasProperty("property3",
+ "The quick brown fox jumped over the moon. What? "));
+ }
+
}
Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -88,6 +88,11 @@
*/
public static final boolean DEFAULT_SUPPORTS_UPDATES = false;
+ /**
+ * This source supports creating references.
+ */
+ protected static final boolean SUPPORTS_REFERENCES = false;
+
public static final int DEFAULT_RETRY_LIMIT = 0;
public static final int DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS = 60 * 5; // 5 minutes
@@ -96,10 +101,12 @@
private volatile int cacheTimeToLiveInMilliseconds = DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS * 1000;
private volatile String defaultWorkspace;
private volatile String[] predefinedWorkspaces = new String[] {};
- private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(SUPPORTS_SAME_NAME_SIBLINGS,
+ private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(
+ SUPPORTS_SAME_NAME_SIBLINGS,
DEFAULT_SUPPORTS_UPDATES,
SUPPORTS_EVENTS,
- DEFAULT_SUPPORTS_CREATING_WORKSPACES);
+ DEFAULT_SUPPORTS_CREATING_WORKSPACES,
+ SUPPORTS_REFERENCES);
private transient CachePolicy cachePolicy;
private transient CopyOnWriteArraySet<String> availableWorkspaceNames;
@@ -236,7 +243,8 @@
*/
public synchronized void setCreatingWorkspacesAllowed( boolean allowWorkspaceCreation ) {
capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), capabilities.supportsUpdates(),
- capabilities.supportsEvents(), allowWorkspaceCreation);
+ capabilities.supportsEvents(), allowWorkspaceCreation,
+ capabilities.supportsReferences());
}
/**
Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -39,6 +39,7 @@
public static I18n errorSerializingCachePolicyInSource;
public static I18n objectFoundInJndiWasNotCache;
public static I18n objectFoundInJndiWasNotCacheFactory;
+ public static I18n unableToDeleteBranch;
public static I18n unableToCloneWorkspaces;
public static I18n unableToCreateWorkspaces;
public static I18n unableToCreateWorkspace;
Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -35,9 +35,11 @@
import org.jboss.cache.Cache;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
+import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
@@ -256,8 +258,15 @@
Node<Name, Object> node = getNode(request, cache, nodePath);
if (node == null) return;
- node.getParent().removeChild(node.getFqn().getLastElement());
- request.setActualLocationOfNode(Location.create(nodePath));
+ Path.Segment nameOfRemovedNode = nodePath.getLastSegment();
+ Node<Name, Object> parent = node.getParent();
+ if (cache.removeNode(node.getFqn())) {
+ removeFromChildList(cache, parent, nameOfRemovedNode, getExecutionContext());
+ request.setActualLocationOfNode(Location.create(nodePath));
+ } else {
+ String msg = JBossCacheConnectorI18n.unableToDeleteBranch.text(getSourceName(), request.inWorkspace(), nodePath);
+ request.setError(new RepositorySourceException(msg));
+ }
}
@Override
@@ -275,12 +284,15 @@
if (newParent == null) return;
// Copy the branch and use the same UUIDs ...
- Path.Segment newSegment = copyNode(cache, node, newParent, null, true, true, null, null, getExecutionContext());
+ Name desiredName = request.desiredName();
+ Path.Segment newSegment = copyNode(cache, node, newParent, desiredName, true, true, null, null, getExecutionContext());
// Now delete the old node ...
Node<Name, Object> oldParent = node.getParent();
boolean removed = oldParent.removeChild(node.getFqn().getLastElement());
assert removed;
+ Path.Segment nameOfRemovedNode = nodePath.getLastSegment();
+ removeFromChildList(cache, oldParent, nameOfRemovedNode, getExecutionContext());
Path newPath = pathFactory.create(newParentPath, newSegment);
request.setActualLocations(Location.create(nodePath), Location.create(newPath));
@@ -516,6 +528,7 @@
// Copy the properties ...
copy.clearData();
copy.putAll(original.getData());
+ copy.remove(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST); // will be reset later ...
// Generate a new UUID for the new node, overwriting any existing value from the original ...
if (reuseOriginalUuids) uuidForCopyOfOriginal = uuidFactory.create(original.get(DnaLexicon.UUID));
@@ -635,6 +648,63 @@
return null;
}
+ /**
+ * Update the array of {@link Path.Segment path segments} for the children of the supplied node, based upon a node being
+ * removed. This array maintains the ordered list of children (since the {@link Cache} does not maintain the order). Invoking
+ * this method will change any existing children that a {@link Path.Segment#getName() name part} that matches the supplied
+ * <code>changedName</code> to have the appropriate {@link Path.Segment#getIndex() same-name sibling index}.
+ *
+ * @param cache the cache in which the parent exists ...
+ * @param parent the parent node; may not be null
+ * @param removedNode the segment of the node that was removed, which signals to look for node with the same name; may not be
+ * null
+ * @param context the execution context; may not be null
+ */
+ protected void removeFromChildList( Cache<Name, Object> cache,
+ Node<Name, Object> parent,
+ Path.Segment removedNode,
+ ExecutionContext context ) {
+ assert parent != null;
+ assert context != null;
+ Set<Node<Name, Object>> children = parent.getChildren();
+ if (children.isEmpty()) {
+ parent.put(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST, null); // replaces any existing value
+ return;
+ }
+
+ // Go through the children, looking for any children with the same name as the 'changedName'
+ Path.Segment[] childNames = (Path.Segment[])parent.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
+ assert childNames != null;
+ int snsIndex = removedNode.getIndex();
+ int index = 0;
+ Path.Segment[] newChildNames = new Path.Segment[childNames.length - 1];
+ for (Path.Segment childName : childNames) {
+ if (!childName.getName().equals(removedNode.getName())) {
+ newChildNames[index] = childName;
+ index++;
+ } else {
+ // The name matches ...
+ if (childName.getIndex() < snsIndex) {
+ // Just copy ...
+ newChildNames[index] = childName;
+ index++;
+ } else if (childName.getIndex() == snsIndex) {
+ // don't copy ...
+ } else {
+ // Append an updated segment ...
+ Path.Segment newSegment = context.getValueFactories()
+ .getPathFactory()
+ .createSegment(childName.getName(), childName.getIndex() - 1);
+ newChildNames[index] = newSegment;
+ // Replace the child with the correct FQN ...
+ changeNodeName(cache, parent, childName, newSegment, context);
+ index++;
+ }
+ }
+ }
+ parent.put(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST, newChildNames); // replaces any existing value
+ }
+
protected boolean checkChildren( Node<Name, Object> parent ) {
Path.Segment[] childNamesProperty = (Path.Segment[])parent.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
Set<Object> childNames = parent.getChildrenNames();
@@ -649,10 +719,8 @@
names.add((Path.Segment)name);
}
Collections.sort(names);
- // Logger.getLogger(getClass()).trace("Child list on {0} is: {1}",
- // parent.getFqn(),
- // StringUtil.readableString(childNamesProperty));
- // Logger.getLogger(getClass()).trace("Children of {0} is: {1}", parent.getFqn(), StringUtil.readableString(names));
+ Logger.getLogger(getClass()).trace("Child list on {0} is: {1}", parent.getFqn(), childNamesProperty);
+ Logger.getLogger(getClass()).trace("Children of {0} is: {1}", parent.getFqn(), names);
}
return result;
}
Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -112,7 +112,7 @@
private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
private volatile String defaultWorkspace;
private volatile String[] predefinedWorkspaces = new String[] {};
- private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(true, true, false, true);
+ private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(true, true, false, true, false);
private transient JBossCacheWorkspaces workspaces;
private transient Context jndiContext;
@@ -417,7 +417,8 @@
* @see #isCreatingWorkspacesAllowed()
*/
public synchronized void setCreatingWorkspacesAllowed( boolean allowWorkspaceCreation ) {
- capabilities = new RepositorySourceCapabilities(true, capabilities.supportsUpdates(), false, allowWorkspaceCreation);
+ capabilities = new RepositorySourceCapabilities(true, capabilities.supportsUpdates(), false, allowWorkspaceCreation,
+ capabilities.supportsReferences());
}
/**
Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheWorkspaces.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheWorkspaces.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheWorkspaces.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -241,7 +241,7 @@
} catch (ConfigurationException error) {
// The workspace name is probably not the name of a configuration ...
I18n msg = JBossCacheConnectorI18n.workspaceNameWasNotValidConfiguration;
- Logger.getLogger(getClass()).info(msg, workspaceName, error.getMessage());
+ Logger.getLogger(getClass()).debug(msg.text(workspaceName, error.getMessage()));
}
if (this.defaultCacheFactoryConfigurationName != null) {
@@ -253,7 +253,7 @@
if (this.workspaceNamesForConfigurationNameProblems.add(workspaceName)) {
// Log this problem only the first time ...
I18n msg = JBossCacheConnectorI18n.defaultCacheFactoryConfigurationNameWasNotValidConfiguration;
- Logger.getLogger(getClass()).warn(msg, workspaceName);
+ Logger.getLogger(getClass()).debug(msg.text(workspaceName));
}
}
}
Modified: trunk/extensions/dna-connector-jbosscache/src/main/resources/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.properties
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/resources/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.properties 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-jbosscache/src/main/resources/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.properties 2009-04-22 08:49:23 UTC (rev 842)
@@ -29,6 +29,7 @@
errorSerializingCachePolicyInSource = Error serializing a {0} instance owned by the {1} JBossCacheSource
objectFoundInJndiWasNotCache = Object in JNDI at {0} found by JBossCacheSource {1} was expected to be a org.jboss.cache.Cache<org.jboss.dna.graph.property.Name,Object> but instead was {2}
objectFoundInJndiWasNotCacheFactory = Object in JNDI at {0} found by JBossCacheSource {1} was expected to be a org.jboss.cache.CacheFactory<org.jboss.dna.graph.property.Name,Object> but instead was {2}
+unableToDeleteBranch = Error while deleting branch "{2}" from workspace "{1}" in the JBossCacheSource {0}
unableToCloneWorkspaces = The JBossCacheSource {0} does not allow creating workspaces, so unable to clone workspace "{1}" into "{2}"
unableToCreateWorkspaces = The JBossCacheSource {0} does not allow creating workspaces, so unable to create workspace "{1}"
unableToCreateWorkspace = Unable to create new workspace "{1}" in the JBossCacheSource {0}
Added: trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java (rev 0)
+++ trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -0,0 +1,79 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.jbosscache;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.io.IOException;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.test.WritableConnectorTest;
+import org.xml.sax.SAXException;
+
+/**
+ * @author Randall Hauch
+ */
+public class JBossCacheConnectorWritableTest extends WritableConnectorTest {
+
+ private Context mockJndi;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#setUpSource()
+ */
+ @Override
+ protected RepositorySource setUpSource() throws NamingException {
+ String[] predefinedWorkspaceNames = new String[] {"default"};
+ JBossCacheSource source = new JBossCacheSource();
+ source.setName("Test Repository");
+ source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
+ source.setNameOfDefaultWorkspace(predefinedWorkspaceNames[0]);
+ source.setCreatingWorkspacesAllowed(true);
+
+ // Set up the mock JNDI ...
+ mockJndi = mock(Context.class);
+ stub(mockJndi.lookup(anyString())).toReturn(null);
+ source.setContext(mockJndi);
+
+ Graph graph = Graph.create(source, context);
+ graph.useWorkspace("default");
+
+ return source;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws SAXException
+ * @throws IOException
+ * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#initializeContent(org.jboss.dna.graph.Graph)
+ */
+ @Override
+ protected void initializeContent( Graph graph ) throws IOException, SAXException {
+ }
+}
Property changes on: trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -132,6 +132,10 @@
*/
protected static final boolean SUPPORTS_SAME_NAME_SIBLINGS = true;
/**
+ * This source supports creating references.
+ */
+ protected static final boolean SUPPORTS_REFERENCES = true;
+ /**
* This source supports udpates by default, but each instance may be configured to {@link #setSupportsUpdates(boolean) be
* read-only or updateable}.
*/
@@ -191,10 +195,12 @@
private volatile boolean referentialIntegrityEnforced = DEFAULT_ENFORCE_REFERENTIAL_INTEGRITY;
private volatile String defaultWorkspace = DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
private volatile String[] predefinedWorkspaces = new String[] {};
- private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(SUPPORTS_SAME_NAME_SIBLINGS,
+ private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(
+ SUPPORTS_SAME_NAME_SIBLINGS,
DEFAULT_SUPPORTS_UPDATES,
SUPPORTS_EVENTS,
- DEFAULT_SUPPORTS_CREATING_WORKSPACES);
+ DEFAULT_SUPPORTS_CREATING_WORKSPACES,
+ SUPPORTS_REFERENCES);
private volatile String modelName;
private transient Model model;
private transient DataSource dataSource;
@@ -251,7 +257,8 @@
*/
public synchronized void setSupportsUpdates( boolean supportsUpdates ) {
capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), supportsUpdates,
- capabilities.supportsEvents(), capabilities.supportsCreatingWorkspaces());
+ capabilities.supportsEvents(), capabilities.supportsCreatingWorkspaces(),
+ capabilities.supportsReferences());
}
/**
@@ -379,7 +386,8 @@
*/
public synchronized void setCreatingWorkspacesAllowed( boolean allowWorkspaceCreation ) {
capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), capabilities.supportsUpdates(),
- capabilities.supportsEvents(), allowWorkspaceCreation);
+ capabilities.supportsEvents(), allowWorkspaceCreation,
+ capabilities.supportsReferences());
}
/**
@@ -848,7 +856,8 @@
Context context = new InitialContext();
dataSource = (DataSource)context.lookup(this.dataSourceJndiName);
} catch (Throwable t) {
- Logger.getLogger(getClass()).error(t, JpaConnectorI18n.errorFindingDataSourceInJndi, name, dataSourceJndiName);
+ Logger.getLogger(getClass())
+ .error(t, JpaConnectorI18n.errorFindingDataSourceInJndi, name, dataSourceJndiName);
}
}
Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -1368,41 +1368,67 @@
// Now we know that the new parent is not the existing parent ...
final int oldIndex = fromEntity.getIndexInParent();
+ // Make sure the child name is set correctly ...
+ String childOldLocalName = fromEntity.getChildName();
+ String childLocalName = null;
+ NamespaceEntity ns = null;
+ Name childName = request.desiredName();
+ if (childName != null) {
+ childLocalName = request.desiredName().getLocalName();
+ String childNsUri = childName.getNamespaceUri();
+ ns = namespaces.get(childNsUri, true);
+ } else {
+ childName = oldPath.getLastSegment().getName();
+ childLocalName = fromEntity.getChildName();
+ ns = fromEntity.getChildNamespace();
+ }
+
// Find the largest SNS index in the existing ChildEntity objects with the same name ...
- String childLocalName = fromEntity.getChildName();
- NamespaceEntity ns = fromEntity.getChildNamespace();
Query query = entities.createNamedQuery("ChildEntity.findMaximumSnsIndex");
query.setParameter("workspaceId", workspaceId);
- query.setParameter("parentUuidString", toUuidString);
+ query.setParameter("parentUuid", toUuidString);
query.setParameter("ns", ns.getId());
query.setParameter("childName", childLocalName);
int nextSnsIndex = 1;
try {
- nextSnsIndex = (Integer)query.getSingleResult();
+ Integer index = (Integer)query.getSingleResult();
+ if (index != null) nextSnsIndex = index.intValue() + 1;
} catch (NoResultException e) {
}
// Find the largest child index in the existing ChildEntity objects ...
query = entities.createNamedQuery("ChildEntity.findMaximumChildIndex");
query.setParameter("workspaceId", workspaceId);
- query.setParameter("parentUuidString", toUuidString);
+ query.setParameter("parentUuid", toUuidString);
int nextIndexInParent = 1;
try {
- nextIndexInParent = (Integer)query.getSingleResult() + 1;
+ Integer index = (Integer)query.getSingleResult();
+ if (index != null) nextIndexInParent = index + 1;
} catch (NoResultException e) {
}
- // Move the child entity to be under the new parent ...
- fromEntity.setId(new ChildId(workspaceId, toUuidString, fromUuidString));
- fromEntity.setIndexInParent(nextIndexInParent);
- fromEntity.setSameNameSiblingIndex(nextSnsIndex);
+ ChildId movedId = new ChildId(workspaceId, toUuidString, fromUuidString);
+ if (fromEntity.getId().equals(movedId)) {
+ // The node is being renamed, but not moved ...
+ fromEntity.setChildName(childLocalName);
+ fromEntity.setChildNamespace(ns);
+ fromEntity.setIndexInParent(nextIndexInParent);
+ fromEntity.setSameNameSiblingIndex(nextSnsIndex);
+ } else {
+ // We won't be able to move the entity to a different parent, because that would involve
+ // changing the PK for the entity, which is not possible. Instead, we have to create a
+ // new entity with the same identity information, then delete 'fromEntity'
+ ChildEntity movedEntity = new ChildEntity(movedId, nextIndexInParent, ns, childLocalName, nextSnsIndex);
+ movedEntity.setAllowsSameNameChildren(fromEntity.getAllowsSameNameChildren());
+ entities.persist(movedEntity);
+ entities.remove(fromEntity);
+ }
// Flush the entities to the database ...
entities.flush();
// Determine the new location ...
Path newParentPath = actualIntoLocation.location.getPath();
- Name childName = oldPath.getLastSegment().getName();
Path newPath = pathFactory.create(newParentPath, childName, nextSnsIndex);
actualNewLocation = actualOldLocation.with(newPath);
@@ -1410,7 +1436,7 @@
ChildEntity.adjustSnsIndexesAndIndexesAfterRemoving(entities,
workspaceId,
oldParentUuid,
- childLocalName,
+ childOldLocalName,
ns.getId(),
oldIndex);
Modified: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/SVNRepositorySource.java
===================================================================
--- trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/SVNRepositorySource.java 2009-04-20 20:21:21 UTC (rev 841)
+++ trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/SVNRepositorySource.java 2009-04-22 08:49:23 UTC (rev 842)
@@ -89,6 +89,10 @@
*/
protected static final boolean SUPPORTS_CREATING_WORKSPACES = false;
/**
+ * This source supports creating references.
+ */
+ protected static final boolean SUPPORTS_REFERENCES = false;
+ /**
* This source supports udpates by default, but each instance may be configured to {@link #setSupportsUpdates(boolean) be
* read-only or updateable}.
*/
@@ -115,7 +119,8 @@
private RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(SUPPORTS_SAME_NAME_SIBLINGS,
DEFAULT_SUPPORTS_UPDATES,
SUPPORTS_EVENTS,
- SUPPORTS_CREATING_WORKSPACES);
+ SUPPORTS_CREATING_WORKSPACES,
+ SUPPORTS_REFERENCES);
private transient Context jndiContext;
private transient RepositoryContext repositoryContext;
@@ -259,7 +264,8 @@
*/
public synchronized void setSupportsUpdates( boolean supportsUpdates ) {
capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), supportsUpdates,
- capabilities.supportsEvents(), capabilities.supportsCreatingWorkspaces());
+ capabilities.supportsEvents(), capabilities.supportsCreatingWorkspaces(),
+ capabilities.supportsReferences());
}
/**
17 years
DNA SVN: r841 - in trunk: dna-graph/src/test/java/org/jboss/dna/graph/sequencer and 15 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-20 16:21:21 -0400 (Mon, 20 Apr 2009)
New Revision: 841
Added:
trunk/extensions/dna-sequencer-cnd/src/main/java/
trunk/extensions/dna-sequencer-cnd/src/main/java/org/
trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/
trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/
trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/
trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/
trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencer.java
trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencerI18n.java
trunk/extensions/dna-sequencer-cnd/src/main/resources/
trunk/extensions/dna-sequencer-cnd/src/main/resources/org/
trunk/extensions/dna-sequencer-cnd/src/main/resources/org/jboss/
trunk/extensions/dna-sequencer-cnd/src/main/resources/org/jboss/dna/
trunk/extensions/dna-sequencer-cnd/src/main/resources/org/jboss/dna/sequencer/
trunk/extensions/dna-sequencer-cnd/src/main/resources/org/jboss/dna/sequencer/cnd/
trunk/extensions/dna-sequencer-cnd/src/main/resources/org/jboss/dna/sequencer/cnd/CndSequencerI18n.properties
trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndSequencerI18nTest.java
trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndSequencerTest.java
Removed:
trunk/extensions/dna-sequencer-cnd/src/main/antlr/
trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndParseFilesTest.java
trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndParserTest.java
Modified:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencer/MockSequencerContext.java
trunk/extensions/dna-sequencer-cnd/.classpath
trunk/extensions/dna-sequencer-cnd/.project
trunk/extensions/dna-sequencer-cnd/pom.xml
trunk/pom.xml
Log:
DNA-363 Define node types via CND files
Changed the DNA CND Sequencer to use the new CND importer.
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencer/MockSequencerContext.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencer/MockSequencerContext.java 2009-04-20 19:07:48 UTC (rev 840)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/sequencer/MockSequencerContext.java 2009-04-20 20:21:21 UTC (rev 841)
@@ -26,7 +26,6 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.collection.SimpleProblems;
import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.sequencer.SequencerContext;
/**
* @author John Verhaeg
@@ -39,4 +38,15 @@
getNamespaceRegistry().register("dnadtd", "http://www.jboss.org/dna/dtd/1.0");
getNamespaceRegistry().register("dnaxml", "http://www.jboss.org/dna/xml/1.0");
}
+
+ public MockSequencerContext( String inputPath ) {
+ this(new ExecutionContext(), inputPath);
+ }
+
+ public MockSequencerContext( ExecutionContext context,
+ String inputPath ) {
+ super(context, context.getValueFactories().getPathFactory().create(inputPath), null, null, new SimpleProblems());
+ getNamespaceRegistry().register("dnadtd", "http://www.jboss.org/dna/dtd/1.0");
+ getNamespaceRegistry().register("dnaxml", "http://www.jboss.org/dna/xml/1.0");
+ }
}
Modified: trunk/extensions/dna-sequencer-cnd/.classpath
===================================================================
--- trunk/extensions/dna-sequencer-cnd/.classpath 2009-04-20 19:07:48 UTC (rev 840)
+++ trunk/extensions/dna-sequencer-cnd/.classpath 2009-04-20 20:21:21 UTC (rev 841)
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
- <classpathentry kind="src" path="target/generated-sources/antlr"/>
- <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
- <classpathentry kind="src" path="src/main/antlr"/>
- <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="output" path="target/classes"/>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
</classpath>
Modified: trunk/extensions/dna-sequencer-cnd/.project
===================================================================
--- trunk/extensions/dna-sequencer-cnd/.project 2009-04-20 19:07:48 UTC (rev 840)
+++ trunk/extensions/dna-sequencer-cnd/.project 2009-04-20 20:21:21 UTC (rev 841)
@@ -15,16 +15,6 @@
<arguments>
</arguments>
</buildCommand>
- <buildCommand>
- <name>org.antlr.eclipse.core.warningcleanerbuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.antlr.eclipse.core.smapbuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
Modified: trunk/extensions/dna-sequencer-cnd/pom.xml
===================================================================
--- trunk/extensions/dna-sequencer-cnd/pom.xml 2009-04-20 19:07:48 UTC (rev 840)
+++ trunk/extensions/dna-sequencer-cnd/pom.xml 2009-04-20 20:21:21 UTC (rev 841)
@@ -19,14 +19,27 @@
<groupId>org.jboss.dna</groupId>
<artifactId>dna-graph</artifactId>
</dependency>
- <dependency>
- <groupId>org.antlr</groupId>
- <artifactId>antlr-runtime</artifactId>
- <version>3.0.1</version>
- </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-cnd</artifactId>
+ </dependency>
<!-- Testing -->
<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>${pom.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>${pom.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
@@ -35,20 +48,4 @@
<artifactId>hamcrest-library</artifactId>
</dependency>
</dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>antlr3-maven-plugin</artifactId>
- <version>1.0</version>
- <executions>
- <execution>
- <goals>
- <goal>antlr</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
</project>
\ No newline at end of file
Added: trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencer.java
===================================================================
--- trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencer.java (rev 0)
+++ trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencer.java 2009-04-20 20:21:21 UTC (rev 841)
@@ -0,0 +1,121 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.sequencer.cnd;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import org.jboss.dna.cnd.CndImporter;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.io.Destination;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.sequencer.SequencerContext;
+import org.jboss.dna.graph.sequencer.SequencerOutput;
+import org.jboss.dna.graph.sequencer.StreamSequencer;
+
+/**
+ *
+ */
+public class CndSequencer implements StreamSequencer {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.sequencer.StreamSequencer#sequence(java.io.InputStream,
+ * org.jboss.dna.graph.sequencer.SequencerOutput, org.jboss.dna.graph.sequencer.SequencerContext)
+ */
+ public void sequence( InputStream stream,
+ SequencerOutput output,
+ SequencerContext context ) {
+ // Create the destination that forwards to the sequencer output ...
+ Destination destination = new OutputDestination(output, context);
+ // Use the CND importer ...
+ Path root = context.getValueFactories().getPathFactory().createRootPath();
+ CndImporter importer = new CndImporter(destination, root);
+ String resourceName = context.getInputPath().getString(context.getNamespaceRegistry());
+ try {
+ importer.importFrom(stream, context.getProblems(), resourceName);
+ } catch (IOException e) {
+ context.getProblems().addError(e, CndSequencerI18n.errorSequencingCndContent, e.getLocalizedMessage());
+ }
+ }
+
+ protected class OutputDestination implements Destination {
+ private final SequencerOutput output;
+ private final SequencerContext context;
+
+ protected OutputDestination( SequencerOutput output,
+ SequencerContext context ) {
+ this.output = output;
+ this.context = context;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#getExecutionContext()
+ */
+ public ExecutionContext getExecutionContext() {
+ return context;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#create(org.jboss.dna.graph.property.Path, java.util.List)
+ */
+ public void create( Path path,
+ List<Property> properties ) {
+ for (Property property : properties) {
+ output.setProperty(path, property.getName(), property.getValues());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#create(org.jboss.dna.graph.property.Path,
+ * org.jboss.dna.graph.property.Property, org.jboss.dna.graph.property.Property[])
+ */
+ public void create( Path path,
+ Property firstProperty,
+ Property... additionalProperties ) {
+ output.setProperty(path, firstProperty.getName(), firstProperty.getValues());
+ for (Property property : additionalProperties) {
+ output.setProperty(path, property.getName(), property.getValues());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.io.Destination#submit()
+ */
+ public void submit() {
+ // nothing to call on the sequencer output ...
+ }
+ }
+
+}
Added: trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencerI18n.java
===================================================================
--- trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencerI18n.java (rev 0)
+++ trunk/extensions/dna-sequencer-cnd/src/main/java/org/jboss/dna/sequencer/cnd/CndSequencerI18n.java 2009-04-20 20:21:21 UTC (rev 841)
@@ -0,0 +1,57 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+* See the AUTHORS.txt file in the distribution for a full listing of
+* individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.sequencer.cnd;
+
+import java.util.Locale;
+import java.util.Set;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author Randall Hauch
+ */
+public final class CndSequencerI18n {
+
+ public static I18n sequencerTaskName;
+ public static I18n errorSequencingCndContent;
+
+ static {
+ try {
+ I18n.initialize(CndSequencerI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(CndSequencerI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(CndSequencerI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(CndSequencerI18n.class, locale);
+ }
+}
Added: trunk/extensions/dna-sequencer-cnd/src/main/resources/org/jboss/dna/sequencer/cnd/CndSequencerI18n.properties
===================================================================
--- trunk/extensions/dna-sequencer-cnd/src/main/resources/org/jboss/dna/sequencer/cnd/CndSequencerI18n.properties (rev 0)
+++ trunk/extensions/dna-sequencer-cnd/src/main/resources/org/jboss/dna/sequencer/cnd/CndSequencerI18n.properties 2009-04-20 20:21:21 UTC (rev 841)
@@ -0,0 +1,25 @@
+#
+# JBoss DNA (http://www.jboss.org/dna)
+# See the COPYRIGHT.txt file distributed with this work for information
+# regarding copyright ownership. Some portions may be licensed
+# to Red Hat, Inc. under one or more contributor license agreements.
+# See the AUTHORS.txt file in the distribution for a full listing of
+# individual contributors.
+#
+# JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+# is licensed to you under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# JBoss DNA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+sequencerTaskName = Processing Compact Node Definition (CND) contents
+errorSequencingCndContent = Error while sequencing the CND content: {0}
Deleted: trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndParseFilesTest.java
===================================================================
--- trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndParseFilesTest.java 2009-04-20 19:07:48 UTC (rev 840)
+++ trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndParseFilesTest.java 2009-04-20 20:21:21 UTC (rev 841)
@@ -1,367 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.sequencer.cnd;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.junit.Assert.assertThat;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import org.antlr.runtime.ANTLRInputStream;
-import org.antlr.runtime.CommonTokenStream;
-import org.antlr.runtime.RuleReturnScope;
-import org.antlr.runtime.tree.Tree;
-import org.junit.After;
-import org.junit.Test;
-
-public class CndParseFilesTest {
-
- /*
- * AST looks like this:
- *
- * root (nil)
- * COMMENTS (*)
- * comment-1
- * comment-2
- * ...
- * NAMESPACES (*)
- * namespace_mapping-1
- * namespace_mapping-2
- * ...
- * NODE_TYPE_DEFINITIONS (*)
- * NODE_TYPE_DEFINITION
- * JCR_NAME
- * node_type_definition_name-1
- * SUPERTYPES (*)
- * supertype-1
- * supertype-2
- * ...
- * NODE_TYPE_OPTIONS (*)
- * option-1
- * option-2
- * ...
- * PROPERTIES (*)
- * PROPERTY_DEFINITION
- * JCR_NAME
- * property_name-1
- * PROPERTY_TYPE (*)
- * property type
- * ATTRIBUTES (*)
- * attribute-1
- * attribute-2
- * ...
- * PROPERTY_DEFINITION
- * JCR_NAME
- * property_name-2
- * ...
- * ...
- * CHILD_NODE_DEFINTIONS (*)
- * CHILD_NODE_DEFINTION
- * JCR_NAME
- * child_node_name-1
- * REQUIRED_TYPES (*)
- * required_type-1
- * required_type-2
- * ...
- * DEFAULT_TYPE (*)
- * default_type
- * ATTRIBUTES (*)
- * attribute-1
- * attribute-2
- * ...
- * CHILD_NODE_DEFINTION
- * JCR_NAME
- * child_node_name-2
- * ...
- * ...
- * NODE_TYPE_DEFINITION
- * JCR_NAME
- * node_type_definition_name-2
- * ...
- * ...
- *
- * Note: (*) indicates node only appears if a child node exists
- */
-
- // =============================================================================================================================
- // Constants
- // =============================================================================================================================
- private static final String TEST_DATA_PATH = "./src/test/resources/";
-
- private static final String BUILTIN_NODETYPES_CND = TEST_DATA_PATH + "builtin_nodetypes.cnd";
- private static final String EMPTY_CND = TEST_DATA_PATH + "empty.cnd";
- private static final String IMAGES_CND = TEST_DATA_PATH + "images.cnd";
- private static final String INVALID_CND = TEST_DATA_PATH + "invalid.cnd";
- private static final String MP3_CND = TEST_DATA_PATH + "mp3.cnd";
-
- private static final int COMMENTS_INDEX = 0;
- private static final int NAMESPACES_INDEX = 1;
- private static final int NODE_TYPE_DEFINITIONS_INDEX = 2;
- private static final int PROPERTIES_INDEX = 2;
-
- // =============================================================================================================================
- // Fields
- // =============================================================================================================================
-
- private InputStream stream;
-
- // =============================================================================================================================
- // Methods
- // =============================================================================================================================
-
- @After
- public void afterEach() throws IOException {
- if (this.stream != null) {
- try {
- this.stream.close();
- } finally {
- this.stream = null;
- }
- }
- }
-
- private void assertCommentsCount( Tree root,
- int count ) {
- Tree comments = root.getChild(COMMENTS_INDEX);
- assertThat("Tree type was not CndParser.COMMENTS", comments.getType(), is(CndParser.COMMENTS));
-
- // make sure right number of comments
- assertThat("Incorrect number of comments", comments.getChildCount(), is(count));
- }
-
- private void assertNamespacesCount( Tree root,
- int count ) {
- Tree namespaces = getNamespaces(root);
- assertThat("Incorrect number of namespaces", namespaces.getChildCount(), is(count));
- }
-
- private void assertNodeTypeDefinitionsCount( Tree root,
- int count ) {
- Tree nodeTypeDefinitions = getNodeTypeDefinitions(root);
- assertThat("Incorrect number of node type definitions", nodeTypeDefinitions.getChildCount(), is(count));
- }
-
- private void assertNodeTypeDefinitionsPropertiesCount( Tree root,
- int nodeTypeDefinitionIndex,
- int count ) {
- Tree nodeTypeDefinitions = getNodeTypeDefinitions(root);
-
- Tree nodeType = nodeTypeDefinitions.getChild(nodeTypeDefinitionIndex);
- assertThat("Tree type was not CndParser.NODE_TYPE_DEFINITION", nodeType.getType(), is(CndParser.NODE_TYPE_DEFINITION));
-
- Tree properties = nodeType.getChild(PROPERTIES_INDEX); // properties container node
- assertThat("Tree type was not CndParser.PROPERTIES", properties.getType(), is(CndParser.PROPERTIES));
-
- // make sure right number of properties
- assertThat("Incorrect number of node type properties for first node type", properties.getChildCount(), is(count));
- }
-
- private CndParser createParser( File file ) throws IOException {
- afterEach(); // make sure previous stream is closed
- assertThat('\'' + file.getAbsolutePath() + "' does not exist", file.exists(), is(true));
-
- this.stream = new FileInputStream(file);
- CndLexer lexer = new CndLexer(new ANTLRInputStream(this.stream));
- CommonTokenStream tokens = new CommonTokenStream(lexer);
-
- return new CndParser(tokens);
- }
-
- /**
- * @param root the AST root
- * @return the NAMESPACES tree node
- */
- private Tree getNamespaces( Tree root ) {
- Tree namespaces = root.getChild(NAMESPACES_INDEX);
-
- if (namespaces != null) {
- assertThat("Tree type was not CndParser.NAMESPACES", namespaces.getType(), is(CndParser.NAMESPACES));
- }
-
- return namespaces;
- }
-
- /**
- * @param root the AST root
- * @return the NODE_TYPE_DEFINITIONS tree node
- */
- private Tree getNodeTypeDefinitions( Tree root ) {
- Tree nodeTypeDefinitions = root.getChild(NODE_TYPE_DEFINITIONS_INDEX);
-
- if (nodeTypeDefinitions != null) {
- assertThat("Tree type was not CndParser.NODE_TYPE_DEFINITIONS",
- nodeTypeDefinitions.getType(),
- is(CndParser.NODE_TYPE_DEFINITIONS));
- }
-
- return nodeTypeDefinitions;
- }
-
- /**
- * @param fileName the name of the file to parse
- * @return the root node of the AST
- * @throws Exception if root is null
- */
- private Tree parse( String fileName ) throws Exception {
- return parse(new File(fileName).getCanonicalFile());
- }
-
- /**
- * @param file the file to parse
- * @return the root node of the AST
- * @throws Exception if root is null
- */
- private Tree parse( File file ) throws Exception {
- CndParser parser = createParser(file);
- RuleReturnScope result = parser.cnd();
- Tree root = (Tree)result.getTree();
- assertThat(root, notNullValue());
-
- return root;
- }
-
- // =============================================================================================================================
- // Tests
- // =============================================================================================================================
-
- @Test
- public void shouldParseEmptyCnd() throws Exception {
- Tree root = parse(EMPTY_CND);
-
- // make sure no children
- assertThat(root.getChildCount(), is(0));
-
- // make sure nothing got parsed
- assertThat(root.getTokenStartIndex(), is(-1));
- }
-
- @Test
- public void shouldNotParseInvalidCnd() throws Exception {
- Tree root = parse(INVALID_CND);
-
- // make sure nothing got parsed
- assertThat(root.getTokenStopIndex(), is(0));
- }
-
- // @Test
- public void shouldParseBuiltinNodeTypesCndComments() throws Exception {
- Tree root = parse(BUILTIN_NODETYPES_CND);
- assertCommentsCount(root, 16);
- }
-
- @Test
- public void shouldParseBuiltinNodeTypesCndNamespaces() throws Exception {
- Tree root = parse(BUILTIN_NODETYPES_CND);
- assertNamespacesCount(root, 4);
- }
-
- // @Test
- public void shouldParseBuiltinNodeTypesCndNodeTypeDefinitions() throws Exception {
- Tree root = parse(BUILTIN_NODETYPES_CND);
-
- // make sure correct number of node type definitions
- assertNodeTypeDefinitionsCount(root, 23);
-
- // make sure right number of node type definitions for each node type
- assertNodeTypeDefinitionsPropertiesCount(root, 0, 2); // [nt:base]
- assertNodeTypeDefinitionsPropertiesCount(root, 1, 2); // [nt:unstructured]
- assertNodeTypeDefinitionsPropertiesCount(root, 2, 1); // [mix:referenceable]
- assertNodeTypeDefinitionsPropertiesCount(root, 3, 2); // [mix:lockable]
- assertNodeTypeDefinitionsPropertiesCount(root, 4, 5); // [mix:versionable]
- assertNodeTypeDefinitionsPropertiesCount(root, 5, 1); // [nt:versionHistory]
- assertNodeTypeDefinitionsPropertiesCount(root, 6, 1); // [nt:versionLabels]
- assertNodeTypeDefinitionsPropertiesCount(root, 7, 3); // [nt:version]
- assertNodeTypeDefinitionsPropertiesCount(root, 8, 5); // [nt:frozenNode]
- assertNodeTypeDefinitionsPropertiesCount(root, 9, 1); // [nt:versionedChild]
- assertNodeTypeDefinitionsPropertiesCount(root, 10, 5); // [nt:nodeType]
- assertNodeTypeDefinitionsPropertiesCount(root, 11, 9); // [nt:propertyDefinition]
- assertNodeTypeDefinitionsPropertiesCount(root, 12, 8); // [nt:childNodeDefinition]
- assertNodeTypeDefinitionsPropertiesCount(root, 13, 1); // [nt:hierarchyNode]
- assertNodeTypeDefinitionsPropertiesCount(root, 14, 0); // [nt:folder]
- assertNodeTypeDefinitionsPropertiesCount(root, 15, 0); // [nt:file]
- assertNodeTypeDefinitionsPropertiesCount(root, 16, 1); // [nt:linkedFile]
- assertNodeTypeDefinitionsPropertiesCount(root, 17, 4); // [nt:resource]
- assertNodeTypeDefinitionsPropertiesCount(root, 18, 2); // [nt:query]
- assertNodeTypeDefinitionsPropertiesCount(root, 19, 0); // [rep:nodeTypes]
- assertNodeTypeDefinitionsPropertiesCount(root, 20, 0); // [rep:root]
- assertNodeTypeDefinitionsPropertiesCount(root, 21, 0); // [rep:system]
- assertNodeTypeDefinitionsPropertiesCount(root, 22, 0); // [rep:versionStorage]
- }
-
- @Test
- public void shouldParseImagesCndComments() throws Exception {
- Tree root = parse(IMAGES_CND);
- assertCommentsCount(root, 11);
- }
-
- @Test
- public void shouldParseImagesCndNamespaces() throws Exception {
- Tree root = parse(IMAGES_CND);
- assertNamespacesCount(root, 4);
- }
-
- @Test
- public void shouldParseImagesCndNodeTypeDefinitions() throws Exception {
- Tree root = parse(IMAGES_CND);
-
- // make sure correct number of node type definitions
- assertNodeTypeDefinitionsCount(root, 2);
-
- // make sure right number of node type definitions for each node type
- assertNodeTypeDefinitionsPropertiesCount(root, 0, 2); // [mix:mimeType]
- assertNodeTypeDefinitionsPropertiesCount(root, 1, 10); // [image:metadata]
- }
-
- @Test
- public void shouldParseMp3CndComments() throws Exception {
- Tree root = parse(MP3_CND);
-
- // this will be the COMMENTS imaginary container token
- Tree comments = root.getChild(COMMENTS_INDEX);
- assertThat("Tree type was not CndParser.COMMENTS", comments.getType(), is(CndParser.COMMENTS));
-
- // make sure right number of comments
- assertThat("Incorrect number of comments", comments.getChildCount(), is(10));
- }
-
- @Test
- public void shouldParseMp3CndNamespaces() throws Exception {
- Tree root = parse(MP3_CND);
- assertNamespacesCount(root, 4);
- }
-
- @Test
- public void shouldParseMp3CndNodeTypeDefinitions() throws Exception {
- Tree root = parse(MP3_CND);
-
- // make sure correct number of node type definitions
- assertNodeTypeDefinitionsCount(root, 2);
-
- // make sure right number of node type definitions for each node type
- assertNodeTypeDefinitionsPropertiesCount(root, 0, 2); // [mix:mimeType]
- assertNodeTypeDefinitionsPropertiesCount(root, 1, 5); // [mp3:metadata]
- }
-}
Deleted: trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndParserTest.java
===================================================================
--- trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndParserTest.java 2009-04-20 19:07:48 UTC (rev 840)
+++ trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndParserTest.java 2009-04-20 20:21:21 UTC (rev 841)
@@ -1,768 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.dna.sequencer.cnd;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.junit.Assert.assertThat;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import org.antlr.runtime.ANTLRInputStream;
-import org.antlr.runtime.CommonTokenStream;
-import org.antlr.runtime.RuleReturnScope;
-import org.antlr.runtime.tree.RewriteEmptyStreamException;
-import org.junit.After;
-import org.junit.Test;
-
-public class CndParserTest {
-
- // =============================================================================================================================
- // Fields
- // =============================================================================================================================
-
- private InputStream stream;
-
- // =============================================================================================================================
- // Methods
- // =============================================================================================================================
-
- @After
- public void afterEach() throws IOException {
- if (this.stream != null) {
- try {
- this.stream.close();
- } finally {
- this.stream = null;
- }
- }
- }
-
- private CndParser createParser( String input ) throws IOException {
- afterEach(); // make sure previous stream is closed
- this.stream = new ByteArrayInputStream(input.getBytes("UTF-8"));
- CndLexer lexer = new CndLexer(new ANTLRInputStream(this.stream));
- CommonTokenStream tokens = new CommonTokenStream(lexer);
- return new CndParser(tokens);
- }
-
- // =============================================================================================================================
- // Comment Parsing Tests
- // =============================================================================================================================
-
- private void parseComment( String option,
- boolean success ) throws Exception {
- CndParser parser = createParser(option);
- RuleReturnScope scope = parser.comment();
-
- if (success) {
- assertThat("Value '" + option + "' did not parse and should have", scope.getTree(), notNullValue());
- assertThat(option, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat("Value '" + option + "' should not parse and did", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParseSingleLineComment() throws Exception {
- parseComment("// This is a single line comment", true);
- }
-
- @Test
- public void shouldParseMultiLineComment() throws Exception {
- parseComment("/* This\nis\na\nmulti-line\ncomment */", true);
- }
-
- @Test
- public void shouldNotParseNonComment() throws Exception {
- parseComment("This is not a valid comment", false);
- }
-
- @Test
- public void shouldNotParseMalformedComment() throws Exception {
- parseComment("/* This comment is missing ending delimeters", false);
- }
-
- // =============================================================================================================================
- // Node Type Name Parsing Tests
- // =============================================================================================================================
-
- private void parseNodeTypeName( String name,
- boolean success ) throws Exception {
- CndParser parser = createParser(name);
- RuleReturnScope scope = parser.node_type_name();
-
- if (success) {
- assertThat("Value '" + name + "' did not parse and should have", scope.getTree(), notNullValue());
-
- // strip off brackets
- assertThat(name.substring(1, name.length() - 1), is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat("Value '" + name + "' should not parse", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParseUnquotedNodeTypeName() throws Exception {
- parseNodeTypeName("[typeName]", true);
- }
-
- @Test
- public void shouldParseQuotedNodeTypeName() throws Exception {
- parseNodeTypeName("['quotedName']", true);
- }
-
- @Test
- public void shouldNotParseNodeTypeNameWithSpaces() throws Exception {
- parseNodeTypeName("[no spaces allowed]", false);
- }
-
- @Test
- public void shouldNotParseNodeTypeNameWithMissingEndBracket() throws Exception {
- parseNodeTypeName("[missingClosingBracket", false);
- }
-
- @Test( expected = RewriteEmptyStreamException.class )
- public void shouldNotParseNodeTypeNameWithMissingBracketsButNoName() throws Exception {
- parseNodeTypeName("[]", false);
- }
-
- // =============================================================================================================================
- // Node Type Abstract Option Parsing Tests
- // =============================================================================================================================
-
- private void parseAbstractOption( String option,
- boolean success ) throws Exception {
- CndParser parser = createParser(option);
- RuleReturnScope scope = parser.abs_opt();
-
- if (success) {
- assertThat("Value '" + option + "' did not parse and should have", scope.getTree(), notNullValue());
- assertThat(option, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat("Value '" + option + "' should not parse and did", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParseAbstractOption() throws Exception {
- parseAbstractOption("abstract", true);
- parseAbstractOption("abs", true);
- parseAbstractOption("a", true);
- }
-
- @Test
- public void shouldNotParseInvalidAbstractOption() throws Exception {
- parseAbstractOption("abstractoption", false);
- parseAbstractOption("A", false);
- }
-
- // =============================================================================================================================
- // Node Type Orderable Option Parsing Tests
- // =============================================================================================================================
-
- private void parseOrderableOption( String option,
- boolean success ) throws Exception {
- CndParser parser = createParser(option);
- RuleReturnScope scope = parser.orderable_opt();
-
- if (success) {
- assertThat("Value '" + option + "' did not parse and should have", scope.getTree(), notNullValue());
- assertThat(option, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat("Value '" + option + "' should not parse and did", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParseOrderableOption() throws Exception {
- parseOrderableOption("orderable", true);
- parseOrderableOption("ord", true);
- parseOrderableOption("o", true);
- }
-
- @Test
- public void shouldNotParseInvalidOrderableOption() throws Exception {
- parseOrderableOption("orderableoption", false);
- parseOrderableOption("O", false);
- }
-
- // =============================================================================================================================
- // Node Type Mixin Option Parsing Tests
- // =============================================================================================================================
-
- private void parseMixinOption( String option,
- boolean success ) throws Exception {
- CndParser parser = createParser(option);
- RuleReturnScope scope = parser.mixin_opt();
-
- if (success) {
- assertThat("Value '" + option + "' did not parse and should have", scope.getTree(), notNullValue());
- assertThat(option, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat("Value '" + option + "' should not parse and did", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParseMixinOption() throws Exception {
- parseMixinOption("mixin", true);
- parseMixinOption("mix", true);
- parseMixinOption("m", true);
- }
-
- @Test
- public void shouldNotParseInvalidMixinOption() throws Exception {
- parseMixinOption("mixinoption", false);
- parseMixinOption("M", false);
- }
-
- // =============================================================================================================================
- // Node Type Orderable Mixin Options Parsing Tests
- // =============================================================================================================================
-
- private void parseNodeTypeOrderableMixinOptions( String options,
- boolean success,
- int numChildren ) throws Exception {
- CndParser parser = createParser(options);
- RuleReturnScope scope = parser.ord_mix_opt();
-
- if (success) {
- assertThat("Value '" + options + "' did not parse and should have", scope.getTree(), notNullValue());
-
- if (numChildren == 0) {
- assertThat(options, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat(numChildren, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getChildCount()));
- }
- } else {
- assertThat("Value '" + options + "' should not parse and did", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParseNodeTypeOrderableMixinOptions() throws Exception {
- parseNodeTypeOrderableMixinOptions("orderable", true, 0);
- parseNodeTypeOrderableMixinOptions("orderable mixin", true, 2);
- parseNodeTypeOrderableMixinOptions("orderable mix", true, 2);
- parseNodeTypeOrderableMixinOptions("orderable m", true, 2);
-
- parseNodeTypeOrderableMixinOptions("ord", true, 0);
- parseNodeTypeOrderableMixinOptions("ord mixin", true, 2);
- parseNodeTypeOrderableMixinOptions("ord mix", true, 2);
- parseNodeTypeOrderableMixinOptions("ord m", true, 2);
-
- parseNodeTypeOrderableMixinOptions("o", true, 0);
- parseNodeTypeOrderableMixinOptions("o mixin", true, 2);
- parseNodeTypeOrderableMixinOptions("o mix", true, 2);
- parseNodeTypeOrderableMixinOptions("o m", true, 2);
-
- parseNodeTypeOrderableMixinOptions("mixin", true, 0);
- parseNodeTypeOrderableMixinOptions("mixin orderable", true, 2);
- parseNodeTypeOrderableMixinOptions("mixin ord", true, 2);
- parseNodeTypeOrderableMixinOptions("mixin o", true, 2);
-
- parseNodeTypeOrderableMixinOptions("mix", true, 0);
- parseNodeTypeOrderableMixinOptions("mix orderable", true, 2);
- parseNodeTypeOrderableMixinOptions("mix ord", true, 2);
- parseNodeTypeOrderableMixinOptions("mix o", true, 2);
-
- parseNodeTypeOrderableMixinOptions("m", true, 0);
- parseNodeTypeOrderableMixinOptions("m orderable", true, 2);
- parseNodeTypeOrderableMixinOptions("m ord", true, 2);
- parseNodeTypeOrderableMixinOptions("m o", true, 2);
- }
-
- // =============================================================================================================================
- // Node Type Options Parsing Tests
- // =============================================================================================================================
-
- private void parseNodeTypeOptions( String options,
- boolean success,
- int numChildren ) throws Exception {
- CndParser parser = createParser(options);
- RuleReturnScope scope = parser.node_type_options();
-
- if (success) {
- assertThat("Value '" + options + "' did not parse and should have", scope.getTree(), notNullValue());
-
- if (numChildren == 0) {
- assertThat(options, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat(numChildren, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getChildCount()));
- }
- } else {
- assertThat("Value '" + options + "' should not parse and did", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParseNodeTypeOptions() throws Exception {
- parseNodeTypeOptions("abstract", true, 0);
- parseNodeTypeOptions("abs", true, 0);
- parseNodeTypeOptions("a", true, 0);
-
- parseNodeTypeOptions("abstract orderable", true, 2);
- parseNodeTypeOptions("abstract ord", true, 2);
- parseNodeTypeOptions("abstract o", true, 2);
-
- parseNodeTypeOptions("abs orderable", true, 2);
- parseNodeTypeOptions("abs ord", true, 2);
- parseNodeTypeOptions("abs o", true, 2);
-
- parseNodeTypeOptions("a orderable", true, 2);
- parseNodeTypeOptions("a ord", true, 2);
- parseNodeTypeOptions("a o", true, 2);
-
- parseNodeTypeOptions("abstract mixin", true, 2);
- parseNodeTypeOptions("abstract mix", true, 2);
- parseNodeTypeOptions("abstract m", true, 2);
-
- parseNodeTypeOptions("abs mixin", true, 2);
- parseNodeTypeOptions("abs mix", true, 2);
- parseNodeTypeOptions("abs m", true, 2);
-
- parseNodeTypeOptions("a mixin", true, 2);
- parseNodeTypeOptions("a mix", true, 2);
- parseNodeTypeOptions("a m", true, 2);
-
- parseNodeTypeOptions("abstract orderable mixin", true, 3);
- parseNodeTypeOptions("abstract orderable mix", true, 3);
- parseNodeTypeOptions("abstract orderable m", true, 3);
-
- parseNodeTypeOptions("abstract ord mixin", true, 3);
- parseNodeTypeOptions("abstract ord mix", true, 3);
- parseNodeTypeOptions("abstract ord m", true, 3);
-
- parseNodeTypeOptions("abstract o mixin", true, 3);
- parseNodeTypeOptions("abstract o mix", true, 3);
- parseNodeTypeOptions("abstract o m", true, 3);
-
- parseNodeTypeOptions("abs orderable mixin", true, 3);
- parseNodeTypeOptions("abs orderable mix", true, 3);
- parseNodeTypeOptions("abs orderable m", true, 3);
-
- parseNodeTypeOptions("abs ord mixin", true, 3);
- parseNodeTypeOptions("abs ord mix", true, 3);
- parseNodeTypeOptions("abs ord m", true, 3);
-
- parseNodeTypeOptions("abs o mixin", true, 3);
- parseNodeTypeOptions("abs o mix", true, 3);
- parseNodeTypeOptions("abs o m", true, 3);
-
- parseNodeTypeOptions("a orderable mixin", true, 3);
- parseNodeTypeOptions("a orderable mix", true, 3);
- parseNodeTypeOptions("a orderable m", true, 3);
-
- parseNodeTypeOptions("a ord mixin", true, 3);
- parseNodeTypeOptions("a ord mix", true, 3);
- parseNodeTypeOptions("a ord m", true, 3);
-
- parseNodeTypeOptions("a o mixin", true, 3);
- parseNodeTypeOptions("a o mix", true, 3);
- parseNodeTypeOptions("a o m", true, 3);
-
- parseNodeTypeOptions("abstract mixin orderable", true, 3);
- parseNodeTypeOptions("abstract mixin ord", true, 3);
- parseNodeTypeOptions("abstract mixin o", true, 3);
-
- parseNodeTypeOptions("abstract mix orderable", true, 3);
- parseNodeTypeOptions("abstract mix ord", true, 3);
- parseNodeTypeOptions("abstract mix o", true, 3);
-
- parseNodeTypeOptions("abstract m orderable", true, 3);
- parseNodeTypeOptions("abstract m ord", true, 3);
- parseNodeTypeOptions("abstract m o", true, 3);
-
- parseNodeTypeOptions("abs mixin orderable", true, 3);
- parseNodeTypeOptions("abs mixin ord", true, 3);
- parseNodeTypeOptions("abs mixin o", true, 3);
-
- parseNodeTypeOptions("abs mix orderable", true, 3);
- parseNodeTypeOptions("abs mix ord", true, 3);
- parseNodeTypeOptions("abs mix o", true, 3);
-
- parseNodeTypeOptions("abs m orderable", true, 3);
- parseNodeTypeOptions("abs m ord", true, 3);
- parseNodeTypeOptions("abs m o", true, 3);
-
- parseNodeTypeOptions("a mixin orderable", true, 3);
- parseNodeTypeOptions("a mixin ord", true, 3);
- parseNodeTypeOptions("a mixin o", true, 3);
-
- parseNodeTypeOptions("a mix orderable", true, 3);
- parseNodeTypeOptions("a mix ord", true, 3);
- parseNodeTypeOptions("a mix o", true, 3);
-
- parseNodeTypeOptions("a m orderable", true, 3);
- parseNodeTypeOptions("a m ord", true, 3);
- parseNodeTypeOptions("a m o", true, 3);
-
- parseNodeTypeOptions("orderable abstract", true, 2);
- parseNodeTypeOptions("ord abstract", true, 2);
- parseNodeTypeOptions("o abstract", true, 2);
-
- parseNodeTypeOptions("orderable abs", true, 2);
- parseNodeTypeOptions("ord abs", true, 2);
- parseNodeTypeOptions("o abs", true, 2);
-
- parseNodeTypeOptions("orderable a", true, 2);
- parseNodeTypeOptions("ord a", true, 2);
- parseNodeTypeOptions("o a", true, 2);
-
- parseNodeTypeOptions("mixin abstract", true, 2);
- parseNodeTypeOptions("mix abstract", true, 2);
- parseNodeTypeOptions("m abstract", true, 2);
-
- parseNodeTypeOptions("mixin abs", true, 2);
- parseNodeTypeOptions("mix abs", true, 2);
- parseNodeTypeOptions("m abs", true, 2);
-
- parseNodeTypeOptions("mixin a", true, 2);
- parseNodeTypeOptions("mix a", true, 2);
- parseNodeTypeOptions("m a", true, 2);
-
- parseNodeTypeOptions("orderable mixin abstract", true, 3);
- parseNodeTypeOptions("orderable mix abstract", true, 3);
- parseNodeTypeOptions("orderable m abstract", true, 3);
-
- parseNodeTypeOptions("ord mixin abstract", true, 3);
- parseNodeTypeOptions("ord mix abstract", true, 3);
- parseNodeTypeOptions("ord m abstract", true, 3);
-
- parseNodeTypeOptions("o mixin abstract", true, 3);
- parseNodeTypeOptions("o mix abstract", true, 3);
- parseNodeTypeOptions("o m abstract", true, 3);
-
- parseNodeTypeOptions("orderable mixin abs", true, 3);
- parseNodeTypeOptions("orderable mix abs", true, 3);
- parseNodeTypeOptions("orderable m abs", true, 3);
-
- parseNodeTypeOptions("ord mixin abs", true, 3);
- parseNodeTypeOptions("ord mix abs", true, 3);
- parseNodeTypeOptions("ord m abs", true, 3);
-
- parseNodeTypeOptions("o mixin abs", true, 3);
- parseNodeTypeOptions("o mix abs", true, 3);
- parseNodeTypeOptions("o m abs", true, 3);
-
- parseNodeTypeOptions("orderable mixin a", true, 3);
- parseNodeTypeOptions("orderable mix a", true, 3);
- parseNodeTypeOptions("orderable m a", true, 3);
-
- parseNodeTypeOptions("ord mixin a", true, 3);
- parseNodeTypeOptions("ord mix a", true, 3);
- parseNodeTypeOptions("ord m a", true, 3);
-
- parseNodeTypeOptions("o mixin a", true, 3);
- parseNodeTypeOptions("o mix a", true, 3);
- parseNodeTypeOptions("o m a", true, 3);
-
- parseNodeTypeOptions("mixin orderable abstract", true, 3);
- parseNodeTypeOptions("mixin ord abstract", true, 3);
- parseNodeTypeOptions("mixin o abstract", true, 3);
-
- parseNodeTypeOptions("mix orderable abstract", true, 3);
- parseNodeTypeOptions("mix ord abstract", true, 3);
- parseNodeTypeOptions("mix o abstract", true, 3);
-
- parseNodeTypeOptions("m orderable abstract", true, 3);
- parseNodeTypeOptions("m ord abstract", true, 3);
- parseNodeTypeOptions("m o abstract", true, 3);
-
- parseNodeTypeOptions("mixin orderable abs", true, 3);
- parseNodeTypeOptions("mixin ord abs", true, 3);
- parseNodeTypeOptions("mixin o abs", true, 3);
-
- parseNodeTypeOptions("mix orderable abs", true, 3);
- parseNodeTypeOptions("mix ord abs", true, 3);
- parseNodeTypeOptions("mix o abs", true, 3);
-
- parseNodeTypeOptions("m orderable abs", true, 3);
- parseNodeTypeOptions("m ord abs", true, 3);
- parseNodeTypeOptions("m o abs", true, 3);
-
- parseNodeTypeOptions("mixin orderable a", true, 3);
- parseNodeTypeOptions("mixin ord a", true, 3);
- parseNodeTypeOptions("mixin o a", true, 3);
-
- parseNodeTypeOptions("mix orderable a", true, 3);
- parseNodeTypeOptions("mix ord a", true, 3);
- parseNodeTypeOptions("mix o a", true, 3);
-
- parseNodeTypeOptions("m orderable a", true, 3);
- parseNodeTypeOptions("m ord a", true, 3);
- parseNodeTypeOptions("m o a", true, 3);
-
- parseNodeTypeOptions("orderable", true, 0);
- parseNodeTypeOptions("ord", true, 0);
- parseNodeTypeOptions("o", true, 0);
-
- parseNodeTypeOptions("mixin", true, 0);
- parseNodeTypeOptions("mix", true, 0);
- parseNodeTypeOptions("m", true, 0);
-
- parseNodeTypeOptions("orderable mixin", true, 2);
- parseNodeTypeOptions("orderable mix", true, 2);
- parseNodeTypeOptions("orderable m", true, 2);
-
- parseNodeTypeOptions("ord mixin", true, 2);
- parseNodeTypeOptions("ord mix", true, 2);
- parseNodeTypeOptions("ord m", true, 2);
-
- parseNodeTypeOptions("o mixin", true, 2);
- parseNodeTypeOptions("o mix", true, 2);
- parseNodeTypeOptions("o m", true, 2);
-
- parseNodeTypeOptions("mixin orderable", true, 2);
- parseNodeTypeOptions("mixin ord", true, 2);
- parseNodeTypeOptions("mixin o", true, 2);
-
- parseNodeTypeOptions("mix orderable", true, 2);
- parseNodeTypeOptions("mix ord", true, 2);
- parseNodeTypeOptions("mix o", true, 2);
-
- parseNodeTypeOptions("m orderable", true, 2);
- parseNodeTypeOptions("m ord", true, 2);
- parseNodeTypeOptions("m o", true, 2);
- }
-
- // =============================================================================================================================
- // Property Type Parsing Tests
- // =============================================================================================================================
-
- private void parsePropertyType( String propertyType,
- boolean success ) throws Exception {
- CndParser parser = createParser(propertyType);
- RuleReturnScope scope = parser.property_type();
-
- if (success) {
- assertThat("Value '" + propertyType + "' did not parse and should have", scope.getTree(), notNullValue());
- assertThat(propertyType, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat("Value '" + propertyType + "' should not parse and did", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParseStringPropertyType() throws Exception {
- parsePropertyType("STRING", true);
- parsePropertyType("String", true);
- parsePropertyType("string", true);
- }
-
- @Test
- public void shouldParseBinaryPropertyType() throws Exception {
- parsePropertyType("BINARY", true);
- parsePropertyType("Binary", true);
- parsePropertyType("binary", true);
- }
-
- @Test
- public void shouldParseLongPropertyType() throws Exception {
- parsePropertyType("LONG", true);
- parsePropertyType("Long", true);
- parsePropertyType("long", true);
- }
-
- @Test
- public void shouldParseDoublePropertyType() throws Exception {
- parsePropertyType("DOUBLE", true);
- parsePropertyType("Double", true);
- parsePropertyType("double", true);
- }
-
- @Test
- public void shouldParseDecimalPropertyType() throws Exception {
- parsePropertyType("DECIMAL", true);
- parsePropertyType("Decimal", true);
- parsePropertyType("decimal", true);
- }
-
- @Test
- public void shouldParseBooleanPropertyType() throws Exception {
- parsePropertyType("BOOLEAN", true);
- parsePropertyType("Boolean", true);
- parsePropertyType("boolean", true);
- }
-
- @Test
- public void shouldParseDatePropertyType() throws Exception {
- parsePropertyType("DATE", true);
- parsePropertyType("Date", true);
- parsePropertyType("date", true);
- }
-
- @Test
- public void shouldParseNamePropertyType() throws Exception {
- parsePropertyType("NAME", true);
- parsePropertyType("Name", true);
- parsePropertyType("name", true);
- }
-
- @Test
- public void shouldParsePathPropertyType() throws Exception {
- parsePropertyType("PATH", true);
- parsePropertyType("Path", true);
- parsePropertyType("path", true);
- }
-
- @Test
- public void shouldParseReferencePropertyType() throws Exception {
- parsePropertyType("REFERENCE", true);
- parsePropertyType("Reference", true);
- parsePropertyType("reference", true);
- }
-
- @Test
- public void shouldParseWeakReferencePropertyType() throws Exception {
- parsePropertyType("WEAKREFERENCE", true);
- parsePropertyType("WeakReference", true);
- parsePropertyType("weakreference", true);
- }
-
- @Test
- public void shouldParseUriPropertyType() throws Exception {
- parsePropertyType("URI", true);
- parsePropertyType("Uri", true);
- parsePropertyType("uri", true);
- }
-
- @Test
- public void shouldParseUndefinedPropertyType() throws Exception {
- parsePropertyType("UNDEFINED", true);
- parsePropertyType("Undefined", true);
- parsePropertyType("undefined", true);
- }
-
- @Test
- public void shouldNotParseInvalidPropertyType() throws Exception {
- parsePropertyType("B", false);
- parsePropertyType("b", false);
- parsePropertyType("binarytype", false);
- }
-
- // =============================================================================================================================
- // Attributes Parsing Tests
- // =============================================================================================================================
-
- private void parseAttribute( String attribute,
- boolean success ) throws Exception {
- CndParser parser = createParser(attribute);
- RuleReturnScope scope = parser.attributes();
-
- if (success) {
- assertThat("Value '" + attribute + "' did not parse and should have", scope.getTree(), notNullValue());
- assertThat(attribute, is(((org.antlr.runtime.tree.CommonTree)scope.getTree()).getText()));
- } else {
- assertThat("Value '" + attribute + "' should not parse and did", scope.getTree(), nullValue());
- }
- }
-
- @Test
- public void shouldParsePrimaryAttribute() throws Exception {
- parseAttribute("primary", true);
- parseAttribute("pri", true);
- parseAttribute("!", true);
- }
-
- @Test
- public void shouldParseAutoCreatedAttribute() throws Exception {
- parseAttribute("autocreated", true);
- parseAttribute("aut", true);
- parseAttribute("a", true);
- }
-
- @Test
- public void shouldParseMandatoryAttribute() throws Exception {
- parseAttribute("mandatory", true);
- parseAttribute("man", true);
- parseAttribute("m", true);
- }
-
- @Test
- public void shouldParseProtectedAttribute() throws Exception {
- parseAttribute("protected", true);
- parseAttribute("pro", true);
- parseAttribute("p", true);
- }
-
- @Test
- public void shouldParseMultipleAttribute() throws Exception {
- parseAttribute("multiple", true);
- parseAttribute("mul", true);
- parseAttribute("*", true);
- }
-
- @Test
- public void shouldParseCopyAttribute() throws Exception {
- parseAttribute("COPY", true);
- parseAttribute("Copy", true);
- parseAttribute("copy", true);
- }
-
- @Test
- public void shouldParseVersionAttribute() throws Exception {
- parseAttribute("VERSION", true);
- parseAttribute("Version", true);
- parseAttribute("version", true);
- }
-
- @Test
- public void shouldParseInitializeAttribute() throws Exception {
- parseAttribute("INITIALIZE", true);
- parseAttribute("Initialize", true);
- parseAttribute("initialize", true);
- }
-
- @Test
- public void shouldParseComputeAttribute() throws Exception {
- parseAttribute("COMPUTE", true);
- parseAttribute("Compute", true);
- parseAttribute("compute", true);
- }
-
- @Test
- public void shouldParseIgnoreAttribute() throws Exception {
- parseAttribute("IGNORE", true);
- parseAttribute("Ignore", true);
- parseAttribute("ignore", true);
- }
-
- @Test
- public void shouldParseAbortAttribute() throws Exception {
- parseAttribute("ABORT", true);
- parseAttribute("Abort", true);
- parseAttribute("abort", true);
- }
-
- @Test
- public void shouldNotParseInvalidAttribute() throws Exception {
- parsePropertyType("P", false);
- parsePropertyType("A", false);
- parsePropertyType("PRIMARY", false);
- }
-}
Added: trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndSequencerI18nTest.java
===================================================================
--- trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndSequencerI18nTest.java (rev 0)
+++ trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndSequencerI18nTest.java 2009-04-20 20:21:21 UTC (rev 841)
@@ -0,0 +1,36 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.sequencer.cnd;
+
+import org.jboss.dna.common.AbstractI18nTest;
+
+/**
+ * @author John Verhaeg
+ */
+public class CndSequencerI18nTest extends AbstractI18nTest {
+
+ public CndSequencerI18nTest() {
+ super(CndSequencerI18n.class);
+ }
+}
Added: trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndSequencerTest.java
===================================================================
--- trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndSequencerTest.java (rev 0)
+++ trunk/extensions/dna-sequencer-cnd/src/test/java/org/jboss/dna/sequencer/cnd/CndSequencerTest.java 2009-04-20 20:21:21 UTC (rev 841)
@@ -0,0 +1,127 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.sequencer.cnd;
+
+import static org.hamcrest.core.Is.is;
+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.graph.sequencer.MockSequencerContext;
+import org.jboss.dna.graph.sequencer.MockSequencerOutput;
+import org.jboss.dna.graph.sequencer.SequencerContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class CndSequencerTest {
+ private CndSequencer sequencer;
+ private InputStream content;
+ private MockSequencerOutput output;
+ private URL cndEmpty;
+ private URL cndImages;
+ private URL cndMp3;
+ private URL cndBuiltIns;
+ private SequencerContext context;
+
+ @Before
+ public void beforeEach() {
+ sequencer = new CndSequencer();
+ context = new MockSequencerContext("/a/mySequencer.cnd");
+ context.getNamespaceRegistry().register("jcr", "http://www.jcp.org/jcr/1.0");
+ context.getNamespaceRegistry().register("nt", "http://www.jcp.org/jcr/nt/1.0");
+ context.getNamespaceRegistry().register("mix", "http://www.jcp.org/jcr/mix/1.0");
+ output = new MockSequencerOutput(context);
+ cndEmpty = this.getClass().getClassLoader().getResource("empty.cnd");
+ cndImages = this.getClass().getClassLoader().getResource("images.cnd");
+ cndMp3 = this.getClass().getClassLoader().getResource("mp3.cnd");
+ cndBuiltIns = this.getClass().getClassLoader().getResource("builtin_nodetypes.cnd");
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ if (content != null) {
+ try {
+ content.close();
+ } finally {
+ content = null;
+ }
+ }
+ }
+
+ @Test
+ public void shouldGenerateNodeTypesForCndFileWithJSR170BuiltIns() throws IOException {
+ URL url = this.cndBuiltIns;
+ assertThat(url, is(notNullValue()));
+ content = url.openStream();
+ assertThat(content, is(notNullValue()));
+ sequencer.sequence(content, output, context);
+ // assertThat(output.getPropertyValues("image:metadata", "jcr:primaryType"), is(new Object[] {"image:metadata"}));
+ // assertThat(output.getPropertyValues("image:metadata", "jcr:mimeType"), is(new Object[] {"image/jpeg"}));
+ // assertThat(output.getPropertyValues("image:metadata", "image:formatName"), is(new Object[] {"JPEG"}));
+ // assertThat(output.getPropertyValues("image:metadata", "image:width"), is(new Object[] {48}));
+ // assertThat(output.getPropertyValues("image:metadata", "image:height"), is(new Object[] {48}));
+ // assertThat(output.getPropertyValues("image:metadata", "image:bitsPerPixel"), is(new Object[] {24}));
+ // assertThat(output.getPropertyValues("image:metadata", "image:progressive"), is(new Object[] {false}));
+ // assertThat(output.getPropertyValues("image:metadata", "image:numberOfImages"), is(new Object[] {1}));
+ // assertThat(output.getPropertyValues("image:metadata", "image:physicalWidthDpi"), is(new Object[] {72}));
+ // assertThat(output.getPropertyValues("image:metadata", "image:physicalHeightDpi"), is(new Object[] {72}));
+ // assertThat(((Float)(output.getPropertyValues("image:metadata", "image:physicalWidthInches")[0])).doubleValue(),
+ // is(closeTo(0.666667d, 0.0001d)));
+ // assertThat(((Float)(output.getPropertyValues("image:metadata", "image:physicalHeightInches")[0])).doubleValue(),
+ // is(closeTo(0.666667d, 0.0001d)));
+ }
+
+ @Test
+ public void shouldGenerateNodeTypesForEmptyCndFile() throws IOException {
+ URL url = this.cndEmpty;
+ assertThat(url, is(notNullValue()));
+ content = url.openStream();
+ assertThat(content, is(notNullValue()));
+ sequencer.sequence(content, output, context);
+ }
+
+ @Test
+ public void shouldGenerateNodeTypesForCndFileWithImageNodeTypes() throws IOException {
+ URL url = this.cndImages;
+ assertThat(url, is(notNullValue()));
+ content = url.openStream();
+ assertThat(content, is(notNullValue()));
+ sequencer.sequence(content, output, context);
+ }
+
+ @Test
+ public void shouldGenerateNodeTypesForCndFileWithMp3NodeTypes() throws IOException {
+ URL url = this.cndMp3;
+ assertThat(url, is(notNullValue()));
+ content = url.openStream();
+ assertThat(content, is(notNullValue()));
+ sequencer.sequence(content, output, context);
+ }
+
+}
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-04-20 19:07:48 UTC (rev 840)
+++ trunk/pom.xml 2009-04-20 20:21:21 UTC (rev 841)
@@ -121,7 +121,7 @@
<module>extensions/dna-sequencer-mp3</module>
<module>extensions/dna-sequencer-jbpm-jpdl</module>
<!--module>extensions/dna-sequencer-esbMessage</module-->
- <module>extensions/dna-sequencer-cnd</module>
+ <!--module>extensions/dna-sequencer-cnd</module-->
<module>extensions/dna-sequencer-java</module>
<module>extensions/dna-sequencer-msoffice</module>
<module>extensions/dna-sequencer-xml</module>
@@ -388,6 +388,11 @@
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
+ <artifactId>dna-cnd</artifactId>
+ <version>${pom.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
<artifactId>dna-repository</artifactId>
<version>${pom.version}</version>
</dependency>
17 years
DNA SVN: r840 - in trunk: dna-cnd and 31 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-04-20 15:07:48 -0400 (Mon, 20 Apr 2009)
New Revision: 840
Added:
trunk/dna-cnd/
trunk/dna-cnd/.classpath
trunk/dna-cnd/.project
trunk/dna-cnd/.settings/
trunk/dna-cnd/.settings/org.eclipse.jdt.core.prefs
trunk/dna-cnd/pom.xml
trunk/dna-cnd/src/
trunk/dna-cnd/src/main/
trunk/dna-cnd/src/main/antlr/
trunk/dna-cnd/src/main/antlr/org/
trunk/dna-cnd/src/main/antlr/org/jboss/
trunk/dna-cnd/src/main/antlr/org/jboss/dna/
trunk/dna-cnd/src/main/antlr/org/jboss/dna/cnd/
trunk/dna-cnd/src/main/antlr/org/jboss/dna/cnd/Cnd.g
trunk/dna-cnd/src/main/antlr3/
trunk/dna-cnd/src/main/antlr3/org/
trunk/dna-cnd/src/main/antlr3/org/jboss/
trunk/dna-cnd/src/main/antlr3/org/jboss/dna/
trunk/dna-cnd/src/main/antlr3/org/jboss/dna/cnd/
trunk/dna-cnd/src/main/antlr3/org/jboss/dna/cnd/Cnd.g
trunk/dna-cnd/src/main/java/
trunk/dna-cnd/src/main/java/org/
trunk/dna-cnd/src/main/java/org/jboss/
trunk/dna-cnd/src/main/java/org/jboss/dna/
trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/
trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/CndI18n.java
trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/CndImporter.java
trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/QueryOperator.java
trunk/dna-cnd/src/main/resources/
trunk/dna-cnd/src/main/resources/org/
trunk/dna-cnd/src/main/resources/org/jboss/
trunk/dna-cnd/src/main/resources/org/jboss/dna/
trunk/dna-cnd/src/main/resources/org/jboss/dna/cnd/
trunk/dna-cnd/src/main/resources/org/jboss/dna/cnd/CndI18n.properties
trunk/dna-cnd/src/test/
trunk/dna-cnd/src/test/java/
trunk/dna-cnd/src/test/java/org/
trunk/dna-cnd/src/test/java/org/jboss/
trunk/dna-cnd/src/test/java/org/jboss/dna/
trunk/dna-cnd/src/test/java/org/jboss/dna/cnd/
trunk/dna-cnd/src/test/java/org/jboss/dna/cnd/CndImporterTest.java
trunk/dna-cnd/src/test/resources/
trunk/dna-cnd/src/test/resources/cnd/
trunk/dna-cnd/src/test/resources/cnd/empty.cnd
trunk/dna-cnd/src/test/resources/cnd/images.cnd
trunk/dna-cnd/src/test/resources/cnd/invalid.cnd
trunk/dna-cnd/src/test/resources/cnd/jcr-builtins-170.cnd
trunk/dna-cnd/src/test/resources/cnd/jcr-builtins-283-early-draft.cnd
trunk/dna-cnd/src/test/resources/cnd/mp3.cnd
trunk/dna-cnd/src/test/resources/log4j.properties
Modified:
trunk/pom.xml
Log:
DNA-363 Define node types via CND files
Added a new 'dna-cnd' project containing a graph importer that reads JCR CND files and populates a repository with the content (based upon the JCR 'nt:nodeType', 'nt:propertyDefinition', and 'nt:childNodeDefinition').
Property changes on: trunk/dna-cnd
___________________________________________________________________
Name: svn:ignore
+ target
Added: trunk/dna-cnd/.classpath
===================================================================
--- trunk/dna-cnd/.classpath (rev 0)
+++ trunk/dna-cnd/.classpath 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" path="src/main/antlr3"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
+ <classpathentry kind="src" path="target/generated-sources/antlr3"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
Added: trunk/dna-cnd/.project
===================================================================
--- trunk/dna-cnd/.project (rev 0)
+++ trunk/dna-cnd/.project 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>dna-cnd</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.antlr.eclipse.core.warningcleanerbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.antlr.eclipse.core.smapbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ </natures>
+</projectDescription>
Added: trunk/dna-cnd/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- trunk/dna-cnd/.settings/org.eclipse.jdt.core.prefs (rev 0)
+++ trunk/dna-cnd/.settings/org.eclipse.jdt.core.prefs 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,60 @@
+#Fri Apr 17 14:06:37 CDT 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=error
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=error
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=error
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=error
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=ignore
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
Added: trunk/dna-cnd/pom.xml
===================================================================
--- trunk/dna-cnd/pom.xml (rev 0)
+++ trunk/dna-cnd/pom.xml 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,107 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>dna</artifactId>
+ <groupId>org.jboss.dna</groupId>
+ <version>0.4-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-cnd</artifactId>
+ <name>JBoss DNA CND Utility</name>
+ <description>JBoss DNA utility for processing and working with JCR CND files</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr-runtime</artifactId>
+ <version>3.1.3</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.antlr</groupId>
+ <artifactId>stringtemplate</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <!-- Testing -->
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>${pom.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>3.1.3</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.antlr</groupId>
+ <artifactId>stringtemplate</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ </exclusion>
+ </exclusions>
+ <!-- we try to use scope to hide it from transitivity -->
+ <scope>test</scope> <!-- or perhaps 'provided' (see later discussion) or 'import' (maven >= 2.0.9) -->
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ </dependency>
+ <!--
+ Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for testing)
+ -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ Java Concurrency in Practice annotations
+ -->
+ <dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr3-maven-plugin</artifactId>
+ <version>3.1.3-1</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>antlr</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
Added: trunk/dna-cnd/src/main/antlr/org/jboss/dna/cnd/Cnd.g
===================================================================
--- trunk/dna-cnd/src/main/antlr/org/jboss/dna/cnd/Cnd.g (rev 0)
+++ trunk/dna-cnd/src/main/antlr/org/jboss/dna/cnd/Cnd.g 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,360 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+grammar Cnd;
+
+options {
+ output=AST;
+}
+
+
+tokens {
+ NAMESPACES;
+ PREFIX;
+ URI;
+ NODE;
+ NAME;
+ PRIMARY_TYPE;
+ SUPERTYPES;
+ NODE_TYPES;
+ NODE_TYPE_ATTRIBUTES;
+ HAS_ORDERABLE_CHILD_NODES;
+ IS_MIXIN;
+ IS_ABSTRACT;
+ IS_QUERYABLE;
+ PRIMARY_ITEM_NAME;
+ PROPERTY_DEFINITION;
+ REQUIRED_TYPE;
+ DEFAULT_VALUES;
+ VALUE_CONSTRAINTS;
+ AUTO_CREATED;
+ MANDATORY;
+ PROTECTED;
+ REQUIRED_TYPE;
+ ON_PARENT_VERSION;
+ MULTIPLE;
+ QUERY_OPERATORS;
+ IS_FULL_TEXT_SEARCHABLE;
+ IS_QUERY_ORDERERABLE;
+ CHILD_NODE_DEFINITION;
+ REQUIRED_PRIMARY_TYPES;
+ DEFAULT_PRIMARY_TYPE;
+ SAME_NAME_SIBLINGS;
+}
+
+@header {
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.cnd;
+}
+
+@members {
+@Override
+public void emitErrorMessage( String msg ) {
+ // don't write messages to System.err ...
+ //super.emitErrorMessage(msg);
+}
+}
+
+@lexer::header {
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.cnd;
+}
+
+@rulecatch {
+ catch (RecognitionException re) {
+ reportError(re);
+ }
+}
+
+// ------------
+// Parser rules
+// ------------
+
+// These rules generate an AST that was designed with a structure that may be
+// automatically processed into a graph structure. This structure is:
+//
+// NAMESPACES
+// +- NODE (multiple)
+// +- PREFIX
+// +- string value
+// +- URI
+// +- string value
+// NODE_TYPES
+// +- NODE (multiple)
+// +- NAME [nt:nodeType/@jcr:name]
+// +- string value
+// +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+// +- string with value 'nt:nodeType'
+// +- SUPERTYPES [nt:nodeType/@jcr:supertypes]
+// +- string value(s)
+// +- IS_ABSTRACT [nt:nodeType/@jcr:isAbstract]
+// +- string containing boolean value (or false if not present)
+// +- HAS_ORDERABLE_CHILD_NODES [nt:nodeType/@jcr:hasOrderableChildNodes]
+// +- string containing boolean value (or false if not present)
+// +- IS_MIXIN [nt:nodeType/@jcr:isMixin]
+// +- string containing boolean value (or false if not present)
+// +- IS_QUERYABLE [nt:nodeType/@jcr:isQueryable]
+// +- string containing boolean value (or true if not present)
+// +- PRIMARY_ITEM_NAME [nt:nodeType/@jcr:primaryItemName]
+// +- string containing string value
+// +- PROPERTY_DEFINITION [nt:nodeType/@jcr:propertyDefinition]
+// +- NODE (multiple)
+// +- NAME [nt:propertyDefinition/@jcr:name]
+// +- string value
+// +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+// +- string with value 'nt:propertyDefinition'
+// +- REQUIRED_TYPE [nt:propertyDefinition/@jcr:propertyType]
+// +- string value (limited to one of the predefined types)
+// +- DEFAULT_VALUES [nt:propertyDefinition/@jcr:defaultValues]
+// +- string value(s)
+// +- MULTIPLE [nt:propertyDefinition/@jcr:multiple]
+// +- string containing boolean value (or false if not present)
+// +- MANDATORY [nt:propertyDefinition/@jcr:mandatory]
+// +- string containing boolean value (or false if not present)
+// +- AUTO_CREATED [nt:propertyDefinition/@jcr:autoCreated]
+// +- string containing boolean value (or false if not present)
+// +- PROTECTED [nt:propertyDefinition/@jcr:protected]
+// +- string containing boolean value (or false if not present)
+// +- ON_PARENT_VERSION [nt:propertyDefinition/@jcr:onParentVersion]
+// +- string value (limited to one of the predefined literal values)
+// +- QUERY_OPERATORS
+// +- string value (containing a comma-separated list of operator literals)
+// +- IS_FULL_TEXT_SEARCHABLE [nt:propertyDefinition/@jcr:isFullTextSearchable]
+// +- string containing boolean value (or true if not present)
+// +- IS_QUERY_ORDERABLE [nt:propertyDefinition/@jcr:isQueryOrderable]
+// +- string containing boolean value (or true if not present)
+// +- VALUE_CONSTRAINTS [nt:propertyDefinition/@jcr:valueConstraints]
+// +- string value(s)
+// +- CHILD_NODE_DEFINITION [nt:nodeType/@jcr:childNodeDefinition]
+// +- NODE (multiple)
+// +- NAME [nt:childNodeDefinition/@jcr:name]
+// +- string value
+// +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+// +- string with value 'nt:childNodeDefinition'
+// +- REQUIRED_PRIMARY_TYPES [nt:childNodeDefinition/@jcr:requiredPrimaryTypes]
+// +- string values (limited to names)
+// +- DEFAULT_PRIMARY_TYPE [nt:childNodeDefinition/@jcr:defaultPrimaryType]
+// +- string value (limited to a name)
+// +- MANDATORY [nt:childNodeDefinition/@jcr:mandatory]
+// +- string containing boolean value (or false if not present)
+// +- AUTO_CREATED [nt:childNodeDefinition/@jcr:autoCreated]
+// +- string containing boolean value (or false if not present)
+// +- PROTECTED [nt:childNodeDefinition/@jcr:protected]
+// +- string containing boolean value (or false if not present)
+// +- SAME_NAME_SIBLINGS [nt:childNodeDefinition/@jcr:sameNameSiblings]
+// +- string containing boolean value (or false if not present)
+// +- ON_PARENT_VERSION [nt:childNodeDefinition/@jcr:onParentVersion]
+// +- string value (limited to one of the predefined literal values)
+//
+// Comments
+// --------
+// The JSR-283 specification states that comments are allowed in CND files but are to be removed prior
+// to parsing and processing. This grammar accomplishes this by sending the MULTI_LINE_COMMENT and
+// SINGLE_LINE_COMMENT tokens to the HIDDEN channel (along with all whitespace tokens).
+//
+// Case sensitivity
+// ----------------
+// ANTLR 3 has no way of generating a case-insensitive lexer/parser (since this is dependent upon locale).
+// However, it's possible to do this as outlined at http://www.antlr.org/wiki/pages/viewpage.action?pageId=1782.
+// Note that the approach that overrides the "LT" method does not change the content but merely changes the
+// character returned by the method, which are the characters used to match the rules.
+//
+// And this must be done for this grammar, since the CND tokens are case-insensitive. Note that this
+// grammar defines all tokens as lower-case, so the ANTLRFileStream subclass must perform a 'toLowerCase()'
+// rather than a 'toUpperCase()'.
+//
+// Post Processing
+// ---------------
+// A number of the values in the AST must be post-processed to perform the requisite validation.
+//
+// The string values may or may not be wrapped in quotes (single or double). Any quotes will
+// need to be removed in post-processing.
+//
+// Also, the QUERY_OPERATORS string value should contain a comma-separated list of operators
+// wrapped by single quotes. As noted below, this is a side effect of how this grammar's lexer
+// automatically produces a STRING token whenever single-quoted strings are found, so by the
+// time the parser rules are run, the operators are encapsulated in a STRING token.
+// (It's arguable whether this is a defect in the CND grammar, or a side effect of how this grammar
+// uses ANTLR; other parser and lexer rules were considered, but most caused a massive increase in
+// the size of the generated code and a massive decrease in performance.) In short, these
+// operators must be validated in a post-processing step.
+//
+// Generating JCR content
+// ----------------------
+//
+// The resulting AST's structure was designed such that it directly corresponds to the "nt:nodeType",
+// "nt:propertyDefinition", and "nt:childNodeDefinition" node types that are specified in JSR-283
+// (proposed draft), in the hopes that this approach could be used with a "standard" AST tree walker
+// that could automatically generate the JCR content.
+//
+// First of all, the structure follows a repeating multi-level pattern, where the "NODE" appears
+// in the AST when a new node should be created, with JCR properties
+// identified by AST nodes under "NODE" that have a single child (e.g., the property's value),
+// or with JCR child nodes identified by AST nodes under "NODE" that also contain an AST "NODE"
+// (with properties below it).
+//
+// The AST node names were designed to be easily translated into property names. ANTLR uses
+// all-caps for AST node names and '_' to separate words in those names. To produce the JCR name,
+// simply convert the first word to lowercase, and convert to lowercase all but the first character
+// of each remaining word, and finally remove all '_' characters.
+//
+// This grammar (mostly) uses the "jcr" prefix (the namespaces should probably be "dna").
+// This could be automated by defining a mapping between the AST node names and the property names
+// (as well as defining a default namespace for any AST node name that is to be converted automatically).
+//
+cnd : (namespaceMapping|nodeTypeDefinition)* EOF
+ -> ^(NAMESPACES namespaceMapping*)? ^(NODE_TYPES nodeTypeDefinition*)? ;
+
+// Namespace mappings
+namespaceMapping : '<' prefix '=' uri '>' -> ^(NODE prefix uri);
+prefix : STRING -> ^(PREFIX STRING);
+uri : STRING -> ^(URI STRING);
+
+// Node type definitions
+nodeTypeDefinition : nodeTypeName supertypes? nodeTypeOptions? ( propertyDefinition | childNodeDefinition )*
+ -> ^(NODE nodeTypeName ^(PRIMARY_TYPE STRING["nt:nodeType"]) supertypes? nodeTypeOptions? ^(PROPERTY_DEFINITION propertyDefinition*) ^(CHILD_NODE_DEFINITION childNodeDefinition*)) ;
+nodeTypeName : '[' STRING ']' -> ^(NAME STRING) ;
+supertypes : '>' stringList -> ^(SUPERTYPES stringList);
+nodeTypeOptions : nodeTypeOption+;
+nodeTypeOption : orderable | mixin | isAbstract | noQuery | primaryItem ;
+orderable : ('o'|'ord'|'orderable') -> ^(HAS_ORDERABLE_CHILD_NODES STRING["true"]);
+mixin : ('m' | 'mix' | 'mixin') -> ^(IS_MIXIN STRING["true"]);
+isAbstract : ('a'|'abs'|'abstract') -> ^(IS_ABSTRACT STRING["true"]);
+noQuery : ('nq'|'noquery') -> ^(IS_QUERYABLE STRING["false"]);
+primaryItem : ('primaryitem'|'!') STRING -> ^(PRIMARY_ITEM_NAME STRING);
+
+// Property definitions ...
+propertyDefinition : propertyName propertyType? defaultValues? ( propertyAttributes | valueConstraints )*
+ -> ^(NODE propertyName ^(PRIMARY_TYPE STRING["nt:propertyDefinition"]) propertyType? defaultValues? propertyAttributes* valueConstraints*);
+propertyName : '-' STRING -> ^(NAME STRING);
+propertyType : '(' propertyTypeLiteral ')' -> ^(REQUIRED_TYPE propertyTypeLiteral);
+propertyTypeLiteral : ('string'|'binary'|'long'|'double'|'boolean'|'date'|'name'|'path'|'reference'|'*');
+defaultValues : '=' stringList -> ^(DEFAULT_VALUES stringList);
+propertyAttributes : ( (onParentVersioningLiteral)=>onParentVersioning | (autoCreated)=> autoCreated | (multiple)=>multiple | (mandatory)=>mandatory | (isProtected)=>isProtected | (queryOperators)=>queryOperators | (noFullText)=>noFullText | (noQueryOrder)=>noQueryOrder)+ ;
+//propertyAttributes : ( (onParentVersioning)=> onParentVersioning | ('a')=>autoCreated | ('m')=>mandatory |('p')=>isProtected | ('mul'|'*')=>multiple | ('q')=>queryOperators | ('nof')=>noFullText | ('nqord'|'noq')=>noQueryOrder)+ ;
+valueConstraints : '<' stringList -> ^(VALUE_CONSTRAINTS stringList);
+autoCreated : ('a'|'aut'|'autocreated') -> ^(AUTO_CREATED STRING["true"]);
+mandatory : ('m'|'man'|'mandatory') -> ^(MANDATORY STRING["true"]);
+isProtected : ('p'|'pro'|'protected') -> ^(PROTECTED STRING["true"]);
+onParentVersioning : onParentVersioningLiteral -> ^(ON_PARENT_VERSION onParentVersioningLiteral);
+onParentVersioningLiteral : ('copy'|'version'|'initialize'|'compute'|'ignore'|'abort');
+multiple : ('*'|'mul'|'multiple') -> ^(MULTIPLE STRING["true"]);
+noFullText : ('nof'|'nofulltext') -> ^(IS_FULL_TEXT_SEARCHABLE STRING["false"]);
+noQueryOrder : ('nqord'|'noqueryorder') -> ^(IS_QUERY_ORDERERABLE STRING["false"]);
+queryOperators : ('qop'|'queryops') STRING -> ^(QUERY_OPERATORS STRING);
+// The grammar defines the query operators to be wrapped by single quotes, and therefore the lexer produces a single STRING token.
+// Since we cannot break this token up, we simply store the operators as a STRING literal, and will have to process
+// at a later step.
+
+// Child node definitions ...
+childNodeDefinition : nodeName requiredTypes? defaultType? nodeAttributes?
+ -> ^(NODE nodeName ^(PRIMARY_TYPE STRING["nt:childNodeDefinition"]) requiredTypes? defaultType? nodeAttributes?);
+nodeName : '+' STRING -> ^(NAME STRING);
+requiredTypes :'(' stringList ')' -> ^(REQUIRED_PRIMARY_TYPES stringList);
+defaultType : '=' STRING -> ^(DEFAULT_PRIMARY_TYPE STRING);
+nodeAttributes : nodeAttribute+;
+nodeAttribute : autoCreated | mandatory | isProtected | onParentVersioning | sns ;
+sns : ('sns'|'*') -> ^(SAME_NAME_SIBLINGS STRING["true"]) ;
+
+// General rules
+stringList : STRING (',' STRING )* -> STRING*;
+
+// ------------
+// Lexer rules
+// ------------
+
+// Comments are currently sent to a separate channel
+MULTI_LINE_COMMENT : ('/*' (options {greedy=false;} : . )* '*/') { $channel=HIDDEN;};
+SINGLE_LINE_COMMENT : '//' ~('\n' | '\r')* { $channel=HIDDEN;};
+
+// Quoted strings allow for strings containing characters that otherwise would be CND delimiters.
+// Note that the single- and double-quote characters must be escaped within the string.
+// Also note that escape sequences are allowed as well.
+STRING : QUOTED_STRING | UNQUOTED_STRING;
+
+// Quoted strings may contain escaped characters.
+fragment QUOTED_STRING
+ : '"' ( EscapeSequence | ~('\\'|'"'))* '"'
+ | '\'' ( EscapeSequence | ~('\\'|'\''))* '\''
+ ;
+
+fragment EscapeSequence
+ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\'
+ |('0'..'3') (('0'..'7') ('0'..'7')?)?
+ |'u'(('0'..'9')|('a'..'f')) (('0'..'9')|('a'..'f')) (('0'..'9')|('a'..'f'))
+ )
+;
+
+// An unquoted string is a word delimited by whitespace and CND tokens.
+fragment UNQUOTED_STRING
+: (~(' '|'\r'|'\t'|'\u000C'|'\n' // whitespace
+ |'='|'<'|'>'|'['|']'|','|'-'|'('|')' // tokens
+ ))+;
+
+WS : (' '|'\r'|'\t'|'\u000C'|'\n')+ {$channel=HIDDEN;} ;
+
+
Added: trunk/dna-cnd/src/main/antlr3/org/jboss/dna/cnd/Cnd.g
===================================================================
--- trunk/dna-cnd/src/main/antlr3/org/jboss/dna/cnd/Cnd.g (rev 0)
+++ trunk/dna-cnd/src/main/antlr3/org/jboss/dna/cnd/Cnd.g 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,368 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+grammar Cnd;
+
+options {
+ output=AST;
+}
+
+
+tokens {
+ NAMESPACES;
+ PREFIX;
+ URI;
+ NODE;
+ NAME;
+ PRIMARY_TYPE;
+ SUPERTYPES;
+ NODE_TYPES;
+ NODE_TYPE_ATTRIBUTES;
+ HAS_ORDERABLE_CHILD_NODES;
+ IS_MIXIN;
+ IS_ABSTRACT;
+ IS_QUERYABLE;
+ PRIMARY_ITEM_NAME;
+ PROPERTY_DEFINITION;
+ REQUIRED_TYPE;
+ DEFAULT_VALUES;
+ VALUE_CONSTRAINTS;
+ AUTO_CREATED;
+ MANDATORY;
+ PROTECTED;
+ REQUIRED_TYPE;
+ ON_PARENT_VERSION;
+ MULTIPLE;
+ IS_PRIMARY_PROPERTY;
+ QUERY_OPERATORS;
+ IS_FULL_TEXT_SEARCHABLE;
+ IS_QUERY_ORDERERABLE;
+ CHILD_NODE_DEFINITION;
+ REQUIRED_PRIMARY_TYPES;
+ DEFAULT_PRIMARY_TYPE;
+ SAME_NAME_SIBLINGS;
+}
+
+@header {
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.cnd;
+}
+
+@members {
+@Override
+public void emitErrorMessage( String msg ) {
+ // don't write messages to System.err ...
+ //super.emitErrorMessage(msg);
+}
+}
+
+@lexer::header {
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.cnd;
+}
+
+@rulecatch {
+ catch (RecognitionException re) {
+ reportError(re);
+ }
+}
+
+// ------------
+// Parser rules
+// ------------
+
+// These rules generate an AST that was designed with a structure that may be
+// automatically processed into a graph structure. This structure is:
+//
+// NAMESPACES
+// +- NODE (multiple)
+// +- PREFIX
+// +- string value
+// +- URI
+// +- string value
+// NODE_TYPES
+// +- NODE (multiple)
+// +- NAME [nt:nodeType/@jcr:name]
+// +- string value
+// +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+// +- string with value 'nt:nodeType'
+// +- SUPERTYPES [nt:nodeType/@jcr:supertypes]
+// +- string value(s)
+// +- IS_ABSTRACT [nt:nodeType/@jcr:isAbstract]
+// +- string containing boolean value (or false if not present)
+// +- HAS_ORDERABLE_CHILD_NODES [nt:nodeType/@jcr:hasOrderableChildNodes]
+// +- string containing boolean value (or false if not present)
+// +- IS_MIXIN [nt:nodeType/@jcr:isMixin]
+// +- string containing boolean value (or false if not present)
+// +- IS_QUERYABLE [nt:nodeType/@jcr:isQueryable]
+// +- string containing boolean value (or true if not present)
+// +- PRIMARY_ITEM_NAME [nt:nodeType/@jcr:primaryItemName]
+// +- string containing string value
+// +- PROPERTY_DEFINITION [nt:nodeType/@jcr:propertyDefinition]
+// +- NODE (multiple)
+// +- NAME [nt:propertyDefinition/@jcr:name]
+// +- string value
+// +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+// +- string with value 'nt:propertyDefinition'
+// +- REQUIRED_TYPE [nt:propertyDefinition/@jcr:propertyType]
+// +- string value (limited to one of the predefined types)
+// +- DEFAULT_VALUES [nt:propertyDefinition/@jcr:defaultValues]
+// +- string value(s)
+// +- MULTIPLE [nt:propertyDefinition/@jcr:multiple]
+// +- string containing boolean value (or false if not present)
+// +- MANDATORY [nt:propertyDefinition/@jcr:mandatory]
+// +- string containing boolean value (or false if not present)
+// +- AUTO_CREATED [nt:propertyDefinition/@jcr:autoCreated]
+// +- string containing boolean value (or false if not present)
+// +- PROTECTED [nt:propertyDefinition/@jcr:protected]
+// +- string containing boolean value (or false if not present)
+// +- ON_PARENT_VERSION [nt:propertyDefinition/@jcr:onParentVersion]
+// +- string value (limited to one of the predefined literal values)
+// +- QUERY_OPERATORS
+// +- string value (containing a comma-separated list of operator literals)
+// +- IS_FULL_TEXT_SEARCHABLE [nt:propertyDefinition/@jcr:isFullTextSearchable]
+// +- string containing boolean value (or true if not present)
+// +- IS_QUERY_ORDERABLE [nt:propertyDefinition/@jcr:isQueryOrderable]
+// +- string containing boolean value (or true if not present)
+// +- VALUE_CONSTRAINTS [nt:propertyDefinition/@jcr:valueConstraints]
+// +- string value(s)
+// +- CHILD_NODE_DEFINITION [nt:nodeType/@jcr:childNodeDefinition]
+// +- NODE (multiple)
+// +- NAME [nt:childNodeDefinition/@jcr:name]
+// +- string value
+// +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+// +- string with value 'nt:childNodeDefinition'
+// +- REQUIRED_PRIMARY_TYPES [nt:childNodeDefinition/@jcr:requiredPrimaryTypes]
+// +- string values (limited to names)
+// +- DEFAULT_PRIMARY_TYPE [nt:childNodeDefinition/@jcr:defaultPrimaryType]
+// +- string value (limited to a name)
+// +- MANDATORY [nt:childNodeDefinition/@jcr:mandatory]
+// +- string containing boolean value (or false if not present)
+// +- AUTO_CREATED [nt:childNodeDefinition/@jcr:autoCreated]
+// +- string containing boolean value (or false if not present)
+// +- PROTECTED [nt:childNodeDefinition/@jcr:protected]
+// +- string containing boolean value (or false if not present)
+// +- SAME_NAME_SIBLINGS [nt:childNodeDefinition/@jcr:sameNameSiblings]
+// +- string containing boolean value (or false if not present)
+// +- ON_PARENT_VERSION [nt:childNodeDefinition/@jcr:onParentVersion]
+// +- string value (limited to one of the predefined literal values)
+//
+// JSR-283 node types
+// ------------------
+// This grammar does support reading in the new 'decimal', 'weakreference' and 'uri' property types. Therefore, it
+// is up to the calling component to verify that these types are allowed. Supporting these new types means
+// that this CND grammar can be used for both JSR-170 and JSR-283.
+//
+// Comments
+// --------
+// The JSR-283 specification states that comments are allowed in CND files but are to be removed prior
+// to parsing and processing. This grammar accomplishes this by sending the MULTI_LINE_COMMENT and
+// SINGLE_LINE_COMMENT tokens to the HIDDEN channel (along with all whitespace tokens).
+//
+// Case sensitivity
+// ----------------
+// ANTLR 3 has no way of generating a case-insensitive lexer/parser (since this is dependent upon locale).
+// However, it's possible to do this as outlined at http://www.antlr.org/wiki/pages/viewpage.action?pageId=1782.
+// Note that the approach that overrides the "LT" method does not change the content but merely changes the
+// character returned by the method, which are the characters used to match the rules.
+//
+// And this must be done for this grammar, since the CND tokens are case-insensitive. Note that this
+// grammar defines all tokens as lower-case, so the ANTLRFileStream subclass must perform a 'toLowerCase()'
+// rather than a 'toUpperCase()'.
+//
+// Post Processing
+// ---------------
+// A number of the values in the AST must be post-processed to perform the requisite validation.
+//
+// The string values may or may not be wrapped in quotes (single or double). Any quotes will
+// need to be removed in post-processing.
+//
+// Also, the QUERY_OPERATORS string value should contain a comma-separated list of operators
+// wrapped by single quotes. As noted below, this is a side effect of how this grammar's lexer
+// automatically produces a STRING token whenever single-quoted strings are found, so by the
+// time the parser rules are run, the operators are encapsulated in a STRING token.
+// (It's arguable whether this is a defect in the CND grammar, or a side effect of how this grammar
+// uses ANTLR; other parser and lexer rules were considered, but most caused a massive increase in
+// the size of the generated code and a massive decrease in performance.) In short, these
+// operators must be validated in a post-processing step.
+//
+// Generating JCR content
+// ----------------------
+//
+// The resulting AST's structure was designed such that it directly corresponds to the "nt:nodeType",
+// "nt:propertyDefinition", and "nt:childNodeDefinition" node types that are specified in JSR-283
+// (proposed draft), in the hopes that this approach could be used with a "standard" AST tree walker
+// that could automatically generate the JCR content.
+//
+// First of all, the structure follows a repeating multi-level pattern, where the "NODE" appears
+// in the AST when a new node should be created, with JCR properties
+// identified by AST nodes under "NODE" that have a single child (e.g., the property's value),
+// or with JCR child nodes identified by AST nodes under "NODE" that also contain an AST "NODE"
+// (with properties below it).
+//
+// The AST node names were designed to be easily translated into property names. ANTLR uses
+// all-caps for AST node names and '_' to separate words in those names. To produce the JCR name,
+// simply convert the first word to lowercase, and convert to lowercase all but the first character
+// of each remaining word, and finally remove all '_' characters.
+//
+// This grammar (mostly) uses the "jcr" prefix (the namespaces should probably be "dna").
+// This could be automated by defining a mapping between the AST node names and the property names
+// (as well as defining a default namespace for any AST node name that is to be converted automatically).
+//
+cnd : (namespaceMapping|nodeTypeDefinition)* EOF
+ -> ^(NAMESPACES namespaceMapping*)? ^(NODE_TYPES nodeTypeDefinition*)? ;
+
+// Namespace mappings
+namespaceMapping : '<' prefix '=' uri '>' -> ^(NODE prefix uri);
+prefix :
+ | 'mix' -> ^(PREFIX 'mix') // Must break out this built-in prefix because it happens to be a keyword
+ | STRING -> ^(PREFIX STRING);
+uri : STRING -> ^(URI STRING);
+
+// Node type definitions
+nodeTypeDefinition : nodeTypeName supertypes? nodeTypeOptions? ( propertyDefinition | childNodeDefinition )*
+ -> ^(NODE nodeTypeName ^(PRIMARY_TYPE STRING["nt:nodeType"]) supertypes? nodeTypeOptions? ^(PROPERTY_DEFINITION propertyDefinition*) ^(CHILD_NODE_DEFINITION childNodeDefinition*)) ;
+nodeTypeName : '[' STRING ']' -> ^(NAME STRING) ;
+supertypes : '>' stringList -> ^(SUPERTYPES stringList);
+nodeTypeOptions : nodeTypeOption+;
+nodeTypeOption : orderable | mixin | isAbstract | noQuery | primaryItem ;
+orderable : ('o'|'ord'|'orderable') -> ^(HAS_ORDERABLE_CHILD_NODES STRING["true"]);
+mixin : ('m' | 'mix' | 'mixin') -> ^(IS_MIXIN STRING["true"]);
+isAbstract : ('a'|'abs'|'abstract') -> ^(IS_ABSTRACT STRING["true"]);
+noQuery : ('nq'|'noquery') -> ^(IS_QUERYABLE STRING["false"]);
+primaryItem : ('primaryitem'|'!') STRING -> ^(PRIMARY_ITEM_NAME STRING);
+
+// Property definitions ...
+propertyDefinition : propertyName propertyType? defaultValues? ( propertyAttributes | valueConstraints )*
+ -> ^(NODE propertyName ^(PRIMARY_TYPE STRING["nt:propertyDefinition"]) propertyType? defaultValues? propertyAttributes* valueConstraints*);
+propertyName : '-' ('*' -> ^(NAME '*') | STRING -> ^(NAME STRING));
+propertyType : '(' propertyTypeLiteral ')' -> ^(REQUIRED_TYPE propertyTypeLiteral);
+propertyTypeLiteral : ('string'|'binary'|'long'|'double'|'boolean'|'decimal'|'date'|'name'|'path'|'reference'|'*'|'undefined'|'weakreference'|'uri');
+defaultValues : '=' stringList -> ^(DEFAULT_VALUES stringList);
+propertyAttributes : ( (isPrimary)=>isPrimary | (onParentVersioningLiteral)=>onParentVersioning | (autoCreated)=> autoCreated | (multiple)=>multiple | (mandatory)=>mandatory | (isProtected)=>isProtected | (queryOperators)=>queryOperators | (noFullText)=>noFullText | (noQueryOrder)=>noQueryOrder)+ ;
+//propertyAttributes : ( (onParentVersioning)=> onParentVersioning | ('a')=>autoCreated | ('m')=>mandatory |('p')=>isProtected | ('mul'|'*')=>multiple | ('q')=>queryOperators | ('nof')=>noFullText | ('nqord'|'noq')=>noQueryOrder)+ ;
+valueConstraints : '<' stringList -> ^(VALUE_CONSTRAINTS stringList);
+isPrimary : ('!'|'pri'|'primary') -> ^(IS_PRIMARY_PROPERTY STRING["true"]);
+autoCreated : ('a'|'aut'|'autocreated') -> ^(AUTO_CREATED STRING["true"]);
+mandatory : ('m'|'man'|'mandatory') -> ^(MANDATORY STRING["true"]);
+isProtected : ('p'|'pro'|'protected') -> ^(PROTECTED STRING["true"]);
+onParentVersioning : onParentVersioningLiteral -> ^(ON_PARENT_VERSION onParentVersioningLiteral);
+onParentVersioningLiteral : ('copy'|'version'|'initialize'|'compute'|'ignore'|'abort');
+multiple : ('*'|'mul'|'multiple') -> ^(MULTIPLE STRING["true"]);
+noFullText : ('nof'|'nofulltext') -> ^(IS_FULL_TEXT_SEARCHABLE STRING["false"]);
+noQueryOrder : ('nqord'|'noqueryorder') -> ^(IS_QUERY_ORDERERABLE STRING["false"]);
+queryOperators : ('qop'|'queryops') STRING -> ^(QUERY_OPERATORS STRING);
+// The grammar defines the query operators to be wrapped by single quotes, and therefore the lexer produces a single STRING token.
+// Since we cannot break this token up, we simply store the operators as a STRING literal, and will have to process
+// at a later step.
+
+// Child node definitions ...
+childNodeDefinition : nodeName requiredTypes? defaultType? nodeAttributes?
+ -> ^(NODE nodeName ^(PRIMARY_TYPE STRING["nt:childNodeDefinition"]) requiredTypes? defaultType? nodeAttributes?);
+nodeName : '+' ('*' -> ^(NAME '*') | STRING -> ^(NAME STRING));
+requiredTypes :'(' stringList ')' -> ^(REQUIRED_PRIMARY_TYPES stringList);
+defaultType : '=' STRING -> ^(DEFAULT_PRIMARY_TYPE STRING);
+nodeAttributes : nodeAttribute+;
+nodeAttribute : autoCreated | mandatory | (isPrimary)=>isPrimary| (isProtected)=>isProtected | onParentVersioning | sns ;
+sns : ('sns'|'*'|'multiple') -> ^(SAME_NAME_SIBLINGS STRING["true"]) ;
+
+// General rules
+stringList : STRING (',' STRING )* -> STRING*;
+
+// ------------
+// Lexer rules
+// ------------
+
+// Comments are currently sent to a separate channel
+MULTI_LINE_COMMENT : ('/*' (options {greedy=false;} : . )* '*/') { $channel=HIDDEN;};
+SINGLE_LINE_COMMENT : '//' ~('\n' | '\r')* { $channel=HIDDEN;};
+
+// Quoted strings allow for strings containing characters that otherwise would be CND delimiters.
+// Note that the single- and double-quote characters must be escaped within the string.
+// Also note that escape sequences are allowed as well.
+STRING : QUOTED_STRING | UNQUOTED_STRING;
+
+// Quoted strings may contain escaped characters.
+fragment QUOTED_STRING
+ : '"' ( EscapeSequence | ~('\\'|'"'))* '"'
+ | '\'' ( EscapeSequence | ~('\\'|'\''))* '\''
+ ;
+
+fragment EscapeSequence
+ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\'
+ |('0'..'3') (('0'..'7') ('0'..'7')?)?
+ |'u'(('0'..'9')|('a'..'f')) (('0'..'9')|('a'..'f')) (('0'..'9')|('a'..'f'))
+ )
+;
+
+// An unquoted string is a word delimited by whitespace and CND tokens.
+fragment UNQUOTED_STRING
+: (~(' '|'\r'|'\t'|'\u000C'|'\n' // whitespace
+ |'='|'<'|'>'|'['|']'|','|'-'|'('|')' // tokens
+ ))+;
+
+WS : (' '|'\r'|'\t'|'\u000C'|'\n')+ {$channel=HIDDEN;} ;
\ No newline at end of file
Added: trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/CndI18n.java
===================================================================
--- trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/CndI18n.java (rev 0)
+++ trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/CndI18n.java 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,51 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+* See the AUTHORS.txt file in the distribution for a full listing of
+* individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.cnd;
+
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author John Verhaeg
+ * @author Randall Hauch
+ */
+public final class CndI18n {
+
+ public static I18n passthrough;
+ public static I18n errorImportingCndContent;
+ public static I18n expectedBooleanLiteral;
+ public static I18n expectedStringLiteral;
+ public static I18n expectedValidNameLiteral;
+ public static I18n expectedValidQueryOperator;
+ public static I18n expectedValidPropertyTypeName;
+ public static I18n expectedValidOnParentVersion;
+ public static I18n locationFromLineNumberAndCharacter;
+
+ static {
+ try {
+ I18n.initialize(CndI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+}
Added: trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/CndImporter.java
===================================================================
--- trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/CndImporter.java (rev 0)
+++ trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/CndImporter.java 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,743 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.cnd;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import net.jcip.annotations.NotThreadSafe;
+import org.antlr.runtime.ANTLRFileStream;
+import org.antlr.runtime.ANTLRInputStream;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.RewriteCardinalityException;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.JcrNtLexicon;
+import org.jboss.dna.graph.io.Destination;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.graph.property.ValueFactory;
+import org.jboss.dna.graph.property.ValueFormatException;
+import org.jboss.dna.graph.property.basic.LocalNamespaceRegistry;
+
+/**
+ * A class that imports the node types contained in a JCR Compact Node Definition (CND) file into graph content. The content is
+ * written using the graph structured defined by JCR and the "{@code nt:nodeType}", "{@code nt:propertyDefinition}", and "{@code
+ * nt:childNodeDefinition}" node types.
+ * <p>
+ * Although instances of this class never change their behavior and all processing is done in local contexts, {@link Destination}
+ * is not thread-safe and therefore this component may not be considered thread-safe.
+ * </p>
+ */
+@NotThreadSafe
+public class CndImporter {
+
+ private static final Set<String> VALID_PROPERTY_TYPES = Collections.unmodifiableSet(new HashSet<String>(
+ Arrays.asList(new String[] {
+ "STRING",
+ "BINARY", "LONG",
+ "DOUBLE",
+ "BOOLEAN",
+ "DECIMAL",
+ "DATE", "NAME",
+ "PATH",
+ "REFERENCE",
+ "WEAKREFERENCE",
+ "URI",
+ "UNDEFINED"})));
+ private static final Set<String> VALID_ON_PARENT_VERSION = Collections.unmodifiableSet(new HashSet<String>(
+ Arrays.asList(new String[] {
+ "COPY",
+ "VERSION",
+ "INITIALIZE",
+ "COMPUTE",
+ "IGNORE",
+ "ABORT"})));
+ protected final Destination destination;
+ protected final Path parentPath;
+ private boolean debug = false;
+
+ /**
+ * Create a new importer that will place the content in the supplied destination under the supplied path.
+ *
+ * @param destination the destination where content is to be written
+ * @param parentPath the path in the destination below which the generated content is to appear
+ * @throws IllegalArgumentException if either parameter is null
+ */
+ public CndImporter( Destination destination,
+ Path parentPath ) {
+ CheckArg.isNotNull(destination, "destination");
+ CheckArg.isNotNull(parentPath, "parentPath");
+ this.destination = destination;
+ this.parentPath = parentPath;
+ }
+
+ void setDebug( boolean value ) {
+ this.debug = value;
+ }
+
+ protected ExecutionContext context() {
+ return this.destination.getExecutionContext();
+ }
+
+ protected NamespaceRegistry namespaces() {
+ return context().getNamespaceRegistry();
+ }
+
+ protected NameFactory nameFactory() {
+ return context().getValueFactories().getNameFactory();
+ }
+
+ protected ValueFactory<String> stringFactory() {
+ return context().getValueFactories().getStringFactory();
+ }
+
+ protected ValueFactory<Boolean> booleanFactory() {
+ return context().getValueFactories().getBooleanFactory();
+ }
+
+ /**
+ * Import the CND content from the supplied stream, placing the content into the importer's destination.
+ *
+ * @param stream the stream containing the CND content
+ * @param problems where any problems encountered during import should be reported
+ * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no
+ * useful name
+ * @throws IOException if there is a problem reading from the supplied stream
+ */
+ public void importFrom( InputStream stream,
+ Problems problems,
+ String resourceName ) throws IOException {
+ CndLexer lex = new CndLexer(new CaseInsensitiveInputStream(stream));
+ importFrom(lex, resourceName, problems);
+ }
+
+ /**
+ * Import the CND content from the supplied stream, placing the content into the importer's destination.
+ *
+ * @param content the string containing the CND content
+ * @param problems where any problems encountered during import should be reported
+ * @param resourceName a logical name for the resource name to be used when reporting problems; may be null if there is no
+ * useful name
+ * @throws IOException if there is a problem reading from the supplied stream
+ */
+ public void importFrom( String content,
+ Problems problems,
+ String resourceName ) throws IOException {
+ ByteArrayInputStream stream = new ByteArrayInputStream(content.getBytes());
+ importFrom(stream, problems, resourceName);
+ }
+
+ /**
+ * Import the CND content from the supplied stream, placing the content into the importer's destination.
+ *
+ * @param file the file containing the CND content
+ * @param problems where any problems encountered during import should be reported
+ * @throws IOException if there is a problem reading from the supplied stream
+ */
+ public void importFrom( File file,
+ Problems problems ) throws IOException {
+ CndLexer lex = new CndLexer(new CaseInsensitiveFileStream(file.getAbsolutePath()));
+ importFrom(lex, file.getCanonicalPath(), problems);
+ }
+
+ protected void importFrom( CndLexer lexer,
+ String resourceName,
+ Problems problems ) {
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ CndParser parser = new Parser(tokens, problems, resourceName);
+
+ // Create a new context with our own namespace registry ...
+ ImportContext context = new ImportContext(context(), problems, resourceName);
+ CommonTree ast = null;
+ try {
+ ast = (CommonTree)parser.cnd().getTree();
+ } catch (RecognitionException e) {
+ // already handled by Parser, so we should not handle twice
+ } catch (RewriteCardinalityException e) {
+ // already handled by Parser, so we should not handle twice
+ } catch (RuntimeException e) {
+ problems.addError(e, CndI18n.errorImportingCndContent, (Object)resourceName, e.getMessage());
+ }
+
+ if (ast != null && problems.isEmpty()) {
+
+ // --------------
+ // Namespaces ...
+ // --------------
+
+ /*
+ NAMESPACES
+ +- NODE (multiple)
+ +- PREFIX
+ +- string value
+ +- URI
+ +- string value
+ */
+
+ // Get the namespaces before we do anything else ...
+ CommonTree namespaces = (CommonTree)ast.getFirstChildWithType(CndLexer.NAMESPACES);
+ if (namespaces != null) {
+ for (int i = 0; i != namespaces.getChildCount(); ++i) {
+ CommonTree namespace = (CommonTree)namespaces.getChild(i);
+ String prefix = namespace.getFirstChildWithType(CndLexer.PREFIX).getChild(0).getText();
+ String uri = namespace.getFirstChildWithType(CndLexer.URI).getChild(0).getText();
+ // Register the namespace ...
+ context.namespaces().register(removeQuotes(prefix), removeQuotes(uri));
+ }
+ }
+
+ // --------------
+ // Node Types ...
+ // --------------
+
+ /*
+ NODE_TYPES
+ +- NODE (multiple)
+ +- NAME [nt:nodeType/@jcr:name]
+ +- string value
+ +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+ +- string with value 'nt:nodeType'
+ +- SUPERTYPES [nt:nodeType/@jcr:supertypes]
+ +- string value(s)
+ +- IS_ABSTRACT [nt:nodeType/@jcr:isAbstract]
+ +- string containing boolean value (or false if not present)
+ +- HAS_ORDERABLE_CHILD_NODES [nt:nodeType/@jcr:hasOrderableChildNodes]
+ +- string containing boolean value (or false if not present)
+ +- IS_MIXIN [nt:nodeType/@jcr:isMixin]
+ +- string containing boolean value (or false if not present)
+ +- IS_QUERYABLE [nt:nodeType/@jcr:isQueryable]
+ +- string containing boolean value (or true if not present)
+ +- PRIMARY_ITEM_NAME [nt:nodeType/@jcr:primaryItemName]
+ +- string containing string value
+ +- PROPERTY_DEFINITION [nt:nodeType/@jcr:propertyDefinition]
+ +- NODE (multiple)
+ +- NAME [nt:propertyDefinition/@jcr:name]
+ +- string value
+ +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+ +- string with value 'nt:propertyDefinition'
+ +- REQUIRED_TYPE [nt:propertyDefinition/@jcr:propertyType]
+ +- string value (limited to one of the predefined types)
+ +- DEFAULT_VALUES [nt:propertyDefinition/@jcr:defaultValues]
+ +- string value(s)
+ +- MULTIPLE [nt:propertyDefinition/@jcr:multiple]
+ +- string containing boolean value (or false if not present)
+ +- MANDATORY [nt:propertyDefinition/@jcr:mandatory]
+ +- string containing boolean value (or false if not present)
+ +- AUTO_CREATED [nt:propertyDefinition/@jcr:autoCreated]
+ +- string containing boolean value (or false if not present)
+ +- PROTECTED [nt:propertyDefinition/@jcr:protected]
+ +- string containing boolean value (or false if not present)
+ +- ON_PARENT_VERSION [nt:propertyDefinition/@jcr:onParentVersion]
+ +- string value (limited to one of the predefined literal values)
+ +- QUERY_OPERATORS
+ +- string value (containing a comma-separated list of operator literals)
+ +- IS_FULL_TEXT_SEARCHABLE [nt:propertyDefinition/@jcr:isFullTextSearchable]
+ +- string containing boolean value (or true if not present)
+ +- IS_QUERY_ORDERABLE [nt:propertyDefinition/@jcr:isQueryOrderable]
+ +- string containing boolean value (or true if not present)
+ +- VALUE_CONSTRAINTS [nt:propertyDefinition/@jcr:valueConstraints]
+ +- string value(s)
+ +- CHILD_NODE_DEFINITION [nt:nodeType/@jcr:childNodeDefinition]
+ +- NODE (multiple)
+ +- NAME [nt:childNodeDefinition/@jcr:name]
+ +- string value
+ +- PRIMARY_TYPE [nt:base/@jcr:primaryType]
+ +- string with value 'nt:childNodeDefinition'
+ +- REQUIRED_PRIMARY_TYPES [nt:childNodeDefinition/@jcr:requiredPrimaryTypes]
+ +- string values (limited to names)
+ +- DEFAULT_PRIMARY_TYPE [nt:childNodeDefinition/@jcr:defaultPrimaryType]
+ +- string value (limited to a name)
+ +- MANDATORY [nt:childNodeDefinition/@jcr:mandatory]
+ +- string containing boolean value (or false if not present)
+ +- AUTO_CREATED [nt:childNodeDefinition/@jcr:autoCreated]
+ +- string containing boolean value (or false if not present)
+ +- PROTECTED [nt:childNodeDefinition/@jcr:protected]
+ +- string containing boolean value (or false if not present)
+ +- SAME_NAME_SIBLINGS [nt:childNodeDefinition/@jcr:sameNameSiblings]
+ +- string containing boolean value (or false if not present)
+ +- ON_PARENT_VERSION [nt:childNodeDefinition/@jcr:onParentVersion]
+ +- string value (limited to one of the predefined literal values)
+ */
+
+ // Get the node types ...
+ CommonTree nodeTypes = (CommonTree)ast.getFirstChildWithType(CndLexer.NODE_TYPES);
+ if (nodeTypes != null) {
+ int numNodeTypes = 0;
+ // Walk each of the nodes underneath the NODE_TYPES parent node ...
+ for (int i = 0; i != nodeTypes.getChildCount(); ++i) {
+ CommonTree nodeType = (CommonTree)nodeTypes.getChild(i);
+ if (this.debug) System.out.println(nodeType.toStringTree());
+ Path nodeTypePath = context.createNodeType(nodeType, parentPath);
+ if (nodeTypePath == null) continue;
+ ++numNodeTypes;
+
+ CommonTree propertyDefinitions = (CommonTree)nodeType.getFirstChildWithType(CndLexer.PROPERTY_DEFINITION);
+ if (propertyDefinitions != null) {
+ // Walk each of the nodes under PROPERTY_DEFINITION ...
+ for (int j = 0; j != propertyDefinitions.getChildCount(); ++j) {
+ CommonTree propDefn = (CommonTree)propertyDefinitions.getChild(j);
+ context.createPropertyDefinition(propDefn, nodeTypePath);
+ }
+ }
+
+ CommonTree childNodeDefinitions = (CommonTree)nodeType.getFirstChildWithType(CndLexer.CHILD_NODE_DEFINITION);
+ if (childNodeDefinitions != null) {
+ // Walk each of the nodes under CHILD_NODE_DEFINITION ...
+ for (int j = 0; j != childNodeDefinitions.getChildCount(); ++j) {
+ CommonTree childDefn = (CommonTree)childNodeDefinitions.getChild(j);
+ context.createChildDefinition(childDefn, nodeTypePath);
+ }
+ }
+ }
+
+ // Submit the destination
+ destination.submit();
+ }
+ }
+ }
+
+ protected final String removeQuotes( String text ) {
+ // Remove leading and trailing quotes, if there are any ...
+ return text.replaceFirst("^['\"]+", "").replaceAll("['\"]+$", "");
+ }
+
+ /**
+ * Utility class that uses a context with a local namespace registry, along with the problems and resource name.
+ */
+ protected final class ImportContext {
+ private final ExecutionContext context;
+ private final Problems problems;
+ private final String resourceName;
+
+ protected ImportContext( ExecutionContext context,
+ Problems problems,
+ String resourceName ) {
+ // Create a context that has a local namespace registry
+ NamespaceRegistry localNamespaces = new LocalNamespaceRegistry(context.getNamespaceRegistry());
+ this.context = context.with(localNamespaces);
+ this.problems = problems;
+ this.resourceName = resourceName;
+ }
+
+ protected ExecutionContext context() {
+ return this.context;
+ }
+
+ protected NamespaceRegistry namespaces() {
+ return this.context.getNamespaceRegistry();
+ }
+
+ protected NameFactory nameFactory() {
+ return this.context.getValueFactories().getNameFactory();
+ }
+
+ protected PathFactory pathFactory() {
+ return this.context.getValueFactories().getPathFactory();
+ }
+
+ protected ValueFactory<String> stringFactory() {
+ return this.context.getValueFactories().getStringFactory();
+ }
+
+ protected ValueFactory<Boolean> booleanFactory() {
+ return this.context.getValueFactories().getBooleanFactory();
+ }
+
+ protected void recordError( CommonTree node,
+ I18n msg,
+ Object... params ) {
+ String location = CndI18n.locationFromLineNumberAndCharacter.text(node.getLine(), node.getCharPositionInLine());
+ problems.addError(msg, resourceName, location, params);
+ }
+
+ protected void recordError( Throwable throwable,
+ CommonTree node,
+ I18n msg,
+ Object... params ) {
+ String location = CndI18n.locationFromLineNumberAndCharacter.text(node.getLine(), node.getCharPositionInLine());
+ problems.addError(throwable, msg, resourceName, location, params);
+ }
+
+ protected Name nameFrom( CommonTree node,
+ int childType ) {
+ CommonTree childNode = (CommonTree)node.getFirstChildWithType(childType);
+ if (childNode != null && childNode.getChildCount() > 0) {
+ CommonTree textNode = (CommonTree)childNode.getChild(0);
+ if (textNode.getToken().getTokenIndex() < 0) return null;
+ String text = removeQuotes(childNode.getChild(0).getText());
+ try {
+ return nameFactory().create(text);
+ } catch (ValueFormatException e) {
+ recordError(e, node, CndI18n.expectedValidNameLiteral, text);
+ }
+ }
+ return null;
+ }
+
+ protected Name[] namesFrom( CommonTree node,
+ int childType ) {
+ CommonTree childNode = (CommonTree)node.getFirstChildWithType(childType);
+ if (childNode != null && childNode.getChildCount() > 0) {
+ List<Name> names = new ArrayList<Name>();
+ for (int i = 0; i != childNode.getChildCount(); ++i) {
+ String text = removeQuotes(childNode.getChild(i).getText());
+ try {
+ names.add(nameFactory().create(text));
+ } catch (ValueFormatException e) {
+ recordError(e, node, CndI18n.expectedValidNameLiteral, text);
+ }
+ }
+ return names.toArray(new Name[names.size()]);
+ }
+ return new Name[] {};
+ }
+
+ protected String stringFrom( CommonTree node,
+ int childType ) {
+ CommonTree childNode = (CommonTree)node.getFirstChildWithType(childType);
+ if (childNode != null && childNode.getChildCount() > 0) {
+ String text = removeQuotes(childNode.getChild(0).getText().trim());
+ try {
+ return stringFactory().create(text);
+ } catch (ValueFormatException e) {
+ recordError(e, node, CndI18n.expectedStringLiteral, text);
+ }
+ }
+ return null;
+ }
+
+ protected String[] stringsFrom( CommonTree node,
+ int childType ) {
+ CommonTree childNode = (CommonTree)node.getFirstChildWithType(childType);
+ if (childNode != null && childNode.getChildCount() > 0) {
+ List<String> names = new ArrayList<String>();
+ for (int i = 0; i != childNode.getChildCount(); ++i) {
+ String text = removeQuotes(childNode.getChild(i).getText().trim());
+ try {
+ names.add(stringFactory().create(text));
+ } catch (ValueFormatException e) {
+ recordError(e, node, CndI18n.expectedStringLiteral, text);
+ }
+ }
+ return names.toArray(new String[names.size()]);
+ }
+ return new String[] {};
+ }
+
+ protected boolean booleanFrom( CommonTree node,
+ int childType,
+ boolean defaultValue ) {
+ CommonTree childNode = (CommonTree)node.getFirstChildWithType(childType);
+ if (childNode != null && childNode.getChildCount() > 0) {
+ String text = removeQuotes(childNode.getChild(0).getText());
+ try {
+ return booleanFactory().create(text);
+ } catch (ValueFormatException e) {
+ recordError(e, node, CndI18n.expectedBooleanLiteral, text);
+ }
+ }
+ return defaultValue;
+ }
+
+ protected QueryOperator[] queryOperatorsFrom( CommonTree node,
+ int childType ) {
+ String text = stringFrom(node, childType);
+ if (text != null) {
+ String[] literals = text.split(",");
+ if (literals.length != 0) {
+ Set<QueryOperator> operators = new HashSet<QueryOperator>();
+ for (String literal : literals) {
+ literal = literal.trim();
+ if (literal.length() == 0) continue;
+ QueryOperator operator = QueryOperator.forText(literal);
+ if (operator != null) {
+ operators.add(operator);
+ } else {
+ recordError(node, CndI18n.expectedValidQueryOperator, literal);
+ }
+ }
+ return operators.toArray(new QueryOperator[operators.size()]);
+ }
+ }
+ return new QueryOperator[] {};
+ }
+
+ protected String propertyTypeNameFrom( CommonTree node,
+ int childType ) {
+ String text = stringFrom(node, childType);
+ if (text.equals("*")) text = "undefined";
+ String upperText = text.toUpperCase();
+ if (!VALID_PROPERTY_TYPES.contains(upperText)) {
+ recordError(node, CndI18n.expectedValidPropertyTypeName, text, VALID_PROPERTY_TYPES);
+ return null;
+ }
+ return upperText;
+ }
+
+ protected String onParentVersionFrom( CommonTree node,
+ int childType ) {
+ String text = stringFrom(node, childType);
+ if (text == null) return "COPY";
+ String upperText = text.toUpperCase();
+ if (!VALID_ON_PARENT_VERSION.contains(upperText)) {
+ recordError(node, CndI18n.expectedValidOnParentVersion, text, VALID_ON_PARENT_VERSION);
+ return null;
+ }
+ return upperText;
+ }
+
+ protected Path createNodeType( CommonTree nodeType,
+ Path parentPath ) {
+ Name name = nameFrom(nodeType, CndLexer.NAME);
+ Name[] supertypes = namesFrom(nodeType, CndLexer.SUPERTYPES);
+ boolean isAbstract = booleanFrom(nodeType, CndLexer.IS_ABSTRACT, false);
+ boolean hasOrderableChildNodes = booleanFrom(nodeType, CndLexer.HAS_ORDERABLE_CHILD_NODES, false);
+ boolean isMixin = booleanFrom(nodeType, CndLexer.IS_MIXIN, false);
+ boolean isQueryable = booleanFrom(nodeType, CndLexer.IS_QUERYABLE, true);
+ Name primaryItemName = nameFrom(nodeType, CndLexer.PRIMARY_ITEM_NAME);
+
+ if (primaryItemName == null) {
+ // See if one of the property definitions is marked as the primary ...
+ CommonTree propertyDefinitions = (CommonTree)nodeType.getFirstChildWithType(CndLexer.PROPERTY_DEFINITION);
+ if (propertyDefinitions != null) {
+ // Walk each of the nodes under PROPERTY_DEFINITION ...
+ for (int j = 0; j != propertyDefinitions.getChildCount(); ++j) {
+ CommonTree propDefn = (CommonTree)propertyDefinitions.getChild(j);
+ if (booleanFrom(propDefn, CndLexer.IS_PRIMARY_PROPERTY, false)) {
+ primaryItemName = nameFrom(propDefn, CndLexer.NAME);
+ break;
+ }
+ }
+ }
+ }
+ if (primaryItemName == null) {
+ // See if one of the child definitions is marked as the primary ...
+ CommonTree childNodeDefinitions = (CommonTree)nodeType.getFirstChildWithType(CndLexer.CHILD_NODE_DEFINITION);
+ if (childNodeDefinitions != null) {
+ // Walk each of the nodes under CHILD_NODE_DEFINITION ...
+ for (int j = 0; j != childNodeDefinitions.getChildCount(); ++j) {
+ CommonTree childDefn = (CommonTree)childNodeDefinitions.getChild(j);
+ if (booleanFrom(childDefn, CndLexer.IS_PRIMARY_PROPERTY, false)) {
+ primaryItemName = nameFrom(childDefn, CndLexer.NAME);
+ break;
+ }
+ }
+ }
+ }
+
+ // Create the node for the node type ...
+ if (name == null) return null;
+ Path path = pathFactory().create(parentPath, name);
+
+ PropertyFactory factory = context.getPropertyFactory();
+ destination.create(path,
+ factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.NODE_TYPE),
+ factory.create(JcrLexicon.SUPERTYPES, (Object[])supertypes),
+ factory.create(JcrLexicon.IS_ABSTRACT, isAbstract),
+ factory.create(JcrLexicon.HAS_ORDERABLE_CHILD_NODES, hasOrderableChildNodes),
+ factory.create(JcrLexicon.IS_MIXIN, isMixin),
+ factory.create(JcrLexicon.IS_QUERYABLE, isQueryable),
+ factory.create(JcrLexicon.PRIMARY_ITEM_NAME, primaryItemName));
+
+ return path;
+ }
+
+ protected Path createPropertyDefinition( CommonTree propDefn,
+ Path parentPath ) {
+ Name name = nameFrom(propDefn, CndLexer.NAME);
+ String requiredType = propertyTypeNameFrom(propDefn, CndLexer.REQUIRED_TYPE);
+ String[] defaultValues = stringsFrom(propDefn, CndLexer.DEFAULT_VALUES);
+ boolean multiple = booleanFrom(propDefn, CndLexer.MULTIPLE, false);
+ boolean mandatory = booleanFrom(propDefn, CndLexer.MANDATORY, false);
+ boolean autoCreated = booleanFrom(propDefn, CndLexer.AUTO_CREATED, false);
+ boolean isProtected = booleanFrom(propDefn, CndLexer.PROTECTED, false);
+ String onParentVersion = onParentVersionFrom(propDefn, CndLexer.ON_PARENT_VERSION);
+ /*QueryOperator[] queryOperators =*/queryOperatorsFrom(propDefn, CndLexer.QUERY_OPERATORS);
+ boolean isFullTextSearchable = booleanFrom(propDefn, CndLexer.IS_FULL_TEXT_SEARCHABLE, true);
+ boolean isQueryOrderable = booleanFrom(propDefn, CndLexer.IS_QUERY_ORDERERABLE, true);
+ String[] valueConstraints = stringsFrom(propDefn, CndLexer.VALUE_CONSTRAINTS);
+
+ // Create the node for the node type ...
+ if (name == null) return null;
+ Path path = pathFactory().create(parentPath, name);
+
+ PropertyFactory factory = context.getPropertyFactory();
+ destination.create(path,
+ factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.PROPERTY_DEFINITION),
+ factory.create(JcrLexicon.REQUIRED_TYPE, requiredType),
+ factory.create(JcrLexicon.DEFAULT_VALUES, (Object[])defaultValues),
+ factory.create(JcrLexicon.MULTIPLE, multiple),
+ factory.create(JcrLexicon.MANDATORY, mandatory),
+ factory.create(JcrLexicon.AUTO_CREATED, autoCreated),
+ factory.create(JcrLexicon.PROTECTED, isProtected),
+ factory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion),
+ // factory.create(DnaLexicon.QUERY_OPERATORS, queryOperators),
+ factory.create(JcrLexicon.IS_FULL_TEXT_SEARCHABLE, isFullTextSearchable),
+ factory.create(JcrLexicon.IS_QUERY_ORDERABLE, isQueryOrderable),
+ factory.create(JcrLexicon.VALUE_CONSTRAINTS, (Object[])valueConstraints));
+
+ return path;
+ }
+
+ protected Path createChildDefinition( CommonTree childDefn,
+ Path parentPath ) {
+ Name name = nameFrom(childDefn, CndLexer.NAME);
+ Name[] requiredPrimaryTypes = namesFrom(childDefn, CndLexer.REQUIRED_PRIMARY_TYPES);
+ Name defaultPrimaryType = nameFrom(childDefn, CndLexer.DEFAULT_PRIMARY_TYPE);
+ boolean mandatory = booleanFrom(childDefn, CndLexer.MANDATORY, false);
+ boolean autoCreated = booleanFrom(childDefn, CndLexer.AUTO_CREATED, false);
+ boolean isProtected = booleanFrom(childDefn, CndLexer.PROTECTED, false);
+ String onParentVersion = onParentVersionFrom(childDefn, CndLexer.ON_PARENT_VERSION);
+ boolean sameNameSiblings = booleanFrom(childDefn, CndLexer.SAME_NAME_SIBLINGS, false);
+
+ // Create the node for the node type ...
+ if (name == null) return null;
+ Path path = pathFactory().create(parentPath, name);
+
+ PropertyFactory factory = context.getPropertyFactory();
+ destination.create(path,
+ factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.CHILD_NODE_DEFINITION),
+ factory.create(JcrLexicon.REQUIRED_PRIMARY_TYPES, (Object[])requiredPrimaryTypes),
+ factory.create(JcrLexicon.DEFAULT_PRIMARY_TYPE, defaultPrimaryType),
+ factory.create(JcrLexicon.MANDATORY, mandatory),
+ factory.create(JcrLexicon.AUTO_CREATED, autoCreated),
+ factory.create(JcrLexicon.PROTECTED, isProtected),
+ factory.create(JcrLexicon.ON_PARENT_VERSION, onParentVersion),
+ factory.create(JcrLexicon.SAME_NAME_SIBLINGS, sameNameSiblings));
+
+ return path;
+ }
+ }
+
+ protected class Parser extends CndParser {
+ private final Problems problems;
+ private final String nameOfResource;
+
+ public Parser( TokenStream input,
+ Problems problems,
+ String nameOfResource ) {
+ super(input);
+ this.problems = problems;
+ this.nameOfResource = nameOfResource;
+ }
+
+ @Override
+ public void displayRecognitionError( String[] tokenNames,
+ RecognitionException e ) {
+ if (problems != null) {
+ String hdr = getErrorHeader(e);
+ String msg = getErrorMessage(e, tokenNames);
+ problems.addError(CndI18n.passthrough, nameOfResource, hdr, msg);
+ } else {
+ super.displayRecognitionError(tokenNames, e);
+ }
+ }
+ }
+
+ /**
+ * Specialization of an {@link ANTLRInputStream} that converts all tokens to lowercase, allowing the grammar to be
+ * case-insensitive. See the <a href="http://www.antlr.org/wiki/pages/viewpage.action?pageId=1782">ANTLR documentation</a>.
+ */
+ protected class CaseInsensitiveInputStream extends ANTLRInputStream {
+ protected CaseInsensitiveInputStream( InputStream stream ) throws IOException {
+ super(stream);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.antlr.runtime.ANTLRStringStream#LA(int)
+ */
+ @Override
+ public int LA( int i ) {
+ if (i == 0) {
+ return 0; // undefined
+ }
+ if (i < 0) {
+ i++; // e.g., translate LA(-1) to use offset 0
+ }
+
+ if ((p + i - 1) >= n) {
+ return CharStream.EOF;
+ }
+ return Character.toLowerCase(data[p + i - 1]);
+ }
+ }
+
+ /**
+ * Specialization of an {@link ANTLRInputStream} that converts all tokens to lowercase, allowing the grammar to be
+ * case-insensitive. See the <a href="http://www.antlr.org/wiki/pages/viewpage.action?pageId=1782">ANTLR documentation</a>.
+ */
+ protected class CaseInsensitiveFileStream extends ANTLRFileStream {
+ protected CaseInsensitiveFileStream( String fileName ) throws IOException {
+ super(fileName, null);
+ }
+
+ protected CaseInsensitiveFileStream( String fileName,
+ String encoding ) throws IOException {
+ super(fileName, encoding);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.antlr.runtime.ANTLRStringStream#LA(int)
+ */
+ @Override
+ public int LA( int i ) {
+ if (i == 0) {
+ return 0; // undefined
+ }
+ if (i < 0) {
+ i++; // e.g., translate LA(-1) to use offset 0
+ }
+
+ if ((p + i - 1) >= n) {
+
+ return CharStream.EOF;
+ }
+ return Character.toLowerCase(data[p + i - 1]);
+ }
+ }
+
+}
Added: trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/QueryOperator.java
===================================================================
--- trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/QueryOperator.java (rev 0)
+++ trunk/dna-cnd/src/main/java/org/jboss/dna/cnd/QueryOperator.java 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,80 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.cnd;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.jboss.dna.common.util.CheckArg;
+
+/**
+ * Enumeration of the query operators allowed in a CND file.
+ */
+public enum QueryOperator {
+
+ EQUAL("="),
+ NOT_EQUAL("<>"),
+ LESS_THAN("<"),
+ LESS_THAN_OR_EQUALS("<="),
+ GREATER_THAN("<"),
+ GREATER_THAN_OR_EQUALS("<="),
+ LIKE("LIKE");
+
+ private static final Map<String, QueryOperator> ALL_OPERATORS;
+ static {
+ Map<String, QueryOperator> operators = new HashMap<String, QueryOperator>();
+ for (QueryOperator operator : QueryOperator.values()) {
+ operators.put(operator.getText(), operator);
+ }
+ ALL_OPERATORS = Collections.unmodifiableMap(operators);
+ }
+
+ private final String text;
+
+ private QueryOperator( String text ) {
+ this.text = text;
+ }
+
+ /**
+ * @return text
+ */
+ public String getText() {
+ return text;
+ }
+
+ public static QueryOperator forText( String text ) {
+ CheckArg.isNotNull(text, "text");
+ return ALL_OPERATORS.get(text.trim().toUpperCase());
+ }
+
+ /**
+ * Return an iterator over all the operator enumeration literals.
+ *
+ * @return an immutable iterator
+ */
+ public static Iterator<QueryOperator> iterator() {
+ return ALL_OPERATORS.values().iterator();
+ }
+}
Added: trunk/dna-cnd/src/main/resources/org/jboss/dna/cnd/CndI18n.properties
===================================================================
--- trunk/dna-cnd/src/main/resources/org/jboss/dna/cnd/CndI18n.properties (rev 0)
+++ trunk/dna-cnd/src/main/resources/org/jboss/dna/cnd/CndI18n.properties 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,33 @@
+#
+# JBoss DNA (http://www.jboss.org/dna)
+# See the COPYRIGHT.txt file distributed with this work for information
+# regarding copyright ownership. Some portions may be licensed
+# to Red Hat, Inc. under one or more contributor license agreements.
+# See the AUTHORS.txt file in the distribution for a full listing of
+# individual contributors.
+#
+# JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+# is licensed to you under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# JBoss DNA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+
+passthrough = {0}
+errorImportingCndContent = Error importing {0}: {1}
+expectedBooleanLiteral = Expected 'true' or 'false', but was "{0}"
+expectedStringLiteral = Expected a valid string, but was "{0}"
+expectedValidNameLiteral = Expected a valid name, but was "{0}"
+expectedValidPropertyTypeName = Property type name was "{0}" but should be one of "{1}"
+expectedValidOnParentVersion = On parent version value was "{0}" but should be one of "{1}"
+expectedValidQueryOperator = Expected a valid query operator ('=', '<>', '<', '<=', '>', '>=', or 'LIKE'), but was {0}
+locationFromLineNumberAndCharacter = Line {0} column {1}
\ No newline at end of file
Added: trunk/dna-cnd/src/test/java/org/jboss/dna/cnd/CndImporterTest.java
===================================================================
--- trunk/dna-cnd/src/test/java/org/jboss/dna/cnd/CndImporterTest.java (rev 0)
+++ trunk/dna-cnd/src/test/java/org/jboss/dna/cnd/CndImporterTest.java 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,611 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.cnd;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.jboss.dna.graph.IsNodeWithProperty.hasProperty;
+import static org.junit.Assert.assertThat;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
+import org.jboss.dna.common.collection.Problem;
+import org.jboss.dna.common.collection.SimpleProblems;
+import org.jboss.dna.graph.DnaLexicon;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.JcrNtLexicon;
+import org.jboss.dna.graph.Node;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.io.Destination;
+import org.jboss.dna.graph.io.GraphBatchDestination;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class CndImporterTest {
+
+ public static final String CND_FILE_PATH = "src/test/resources/cnd/";
+
+ private ExecutionContext context;
+ private InMemoryRepositorySource repository;
+ private Graph graph;
+ private Destination destination;
+ private Path rootPath;
+ private CndImporter importer;
+ private SimpleProblems problems;
+
+ @Before
+ public void beforeEach() {
+ problems = new SimpleProblems();
+ context = new ExecutionContext();
+ context.getNamespaceRegistry().register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
+ context.getNamespaceRegistry().register(JcrLexicon.Namespace.PREFIX, JcrLexicon.Namespace.URI);
+ context.getNamespaceRegistry().register(JcrNtLexicon.Namespace.PREFIX, JcrNtLexicon.Namespace.URI);
+
+ // Set up the repository and graph ...
+ repository = new InMemoryRepositorySource();
+ repository.setName("NodeTypes");
+ graph = Graph.create(repository, context);
+
+ // Set up the path where the content will go, and make sure that path exists in the repository ...
+ rootPath = context.getValueFactories().getPathFactory().create("/a");
+ graph.create(rootPath);
+
+ // Now set up the destination ...
+ destination = new GraphBatchDestination(graph.batch());
+
+ // Set up the importer ...
+ importer = new CndImporter(destination, rootPath);
+ }
+
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected void printProblems() {
+ for (Problem problem : problems) {
+ System.out.println(problem);
+ }
+ }
+
+ protected Node node( String pathToNode ) {
+ return graph.getNodeAt("/a/" + pathToNode);
+ }
+
+ protected InputStream openCndStream( String cndFileName ) throws IOException {
+ return this.getClass().getClassLoader().getResourceAsStream("cnd/" + cndFileName);
+ }
+
+ protected File openCndFile( String cndFileName ) throws IOException, URISyntaxException {
+ File result = new File(CND_FILE_PATH + cndFileName);
+ assertThat(result.exists(), is(true));
+ return result;
+ }
+
+ @Test
+ public void shouldReportErrorIfTheNodeTypeNameIsEmpty() throws IOException {
+ String cnd = "<ns = 'http://namespace.com/ns'> [] abstract";
+ importer.importFrom(cnd, problems, "string");
+ // printProblems();
+ assertThat(problems.size(), is(1));
+ assertThat(problems.iterator().next().getMessageString(), is("missing STRING at ']'"));
+ }
+
+ @Test
+ public void shouldReportErrorIfTheNodeTypeNameIsBlank() throws IOException {
+ String cnd = "<ns = 'http://namespace.com/ns'> [ ] abstract";
+ importer.importFrom(cnd, problems, "string");
+ // printProblems();
+ assertThat(problems.size(), is(1));
+ assertThat(problems.iterator().next().getMessageString(), is("missing STRING at ']'"));
+ }
+
+ @Test
+ public void shouldReportErrorIfTheNodeTypeNameIsNotFollowedByClosingBracket() throws IOException {
+ String cnd = "<ns = 'http://namespace.com/ns'> [ abstract";
+ importer.importFrom(cnd, problems, "string");
+ // printProblems();
+ assertThat(problems.size(), is(1));
+ assertThat(problems.iterator().next().getMessageString(), is("mismatched input 'abstract' expecting STRING"));
+ }
+
+ @Test
+ public void shouldReportErrorIfTheNodeTypeNameUsesInvalidNamespace() throws IOException {
+ String cnd = "<ns = 'http://namespace.com/ns'> [xyz:acme] abstract";
+ importer.importFrom(cnd, problems, "string");
+ // printProblems();
+ assertThat(problems.size(), is(1));
+ assertThat(problems.iterator().next().getMessage(), is(CndI18n.expectedValidNameLiteral));
+ }
+
+ @Test
+ public void shouldImportCndThatUsesAllFeatures() throws IOException {
+ // importer.setDebug(true);
+ String cnd = "<ex = 'http://namespace.com/ns'>\n"
+ + "[ex:NodeType] > ex:ParentType1, ex:ParentType2 abstract orderable mixin noquery primaryitem ex:property\n"
+ + "- ex:property (STRING) = 'default1', 'default2' mandatory autocreated protected multiple VERSION < 'constraint1', 'constraint2'\n"
+ + " queryops '=, <>, <, <=, >, >=, LIKE' nofulltext noqueryorder\n"
+ + "+ ex:node (ex:reqType1, ex:reqType2) = ex:defaultType mandatory autocreated protected sns version";
+ importer.importFrom(cnd, problems, "string");
+ // assertThat(problems.size(), is(1));
+ // printProblems();
+ context.getNamespaceRegistry().register("ex", "http://namespace.com/ns");
+ Node nodeType = node("ex:NodeType");
+ assertThat(nodeType, hasProperty(JcrLexicon.IS_ABSTRACT, true));
+ Node prop = node("ex:NodeType/ex:property");
+ assertThat(prop, hasProperty(JcrLexicon.REQUIRED_TYPE, "STRING"));
+ assertThat(prop, hasProperty(JcrLexicon.DEFAULT_VALUES, new Object[] {"default1", "default2"}));
+ assertThat(prop, hasProperty(JcrLexicon.AUTO_CREATED, true));
+ assertThat(prop, hasProperty(JcrLexicon.MANDATORY, true));
+ assertThat(prop, hasProperty(JcrLexicon.PROTECTED, true));
+ assertThat(prop, hasProperty(JcrLexicon.MULTIPLE, true));
+ assertThat(prop, hasProperty(JcrLexicon.ON_PARENT_VERSION, "VERSION"));
+ assertThat(prop, hasProperty(JcrLexicon.VALUE_CONSTRAINTS, new Object[] {"constraint1", "constraint2"}));
+ assertThat(prop, hasProperty(JcrLexicon.IS_FULL_TEXT_SEARCHABLE, false));
+ assertThat(prop, hasProperty(JcrLexicon.IS_QUERY_ORDERABLE, false));
+ Node node = node("ex:NodeType/ex:node");
+ assertThat(node, hasProperty(JcrLexicon.REQUIRED_PRIMARY_TYPES, new Object[] {name("ex:reqType1"), name("ex:reqType2")}));
+ assertThat(node, hasProperty(JcrLexicon.DEFAULT_PRIMARY_TYPE, name("ex:defaultType")));
+ assertThat(node, hasProperty(JcrLexicon.AUTO_CREATED, true));
+ assertThat(node, hasProperty(JcrLexicon.MANDATORY, true));
+ assertThat(node, hasProperty(JcrLexicon.PROTECTED, true));
+ assertThat(node, hasProperty(JcrLexicon.SAME_NAME_SIBLINGS, true));
+ assertThat(node, hasProperty(JcrLexicon.ON_PARENT_VERSION, "VERSION"));
+ }
+
+ @Test
+ public void shouldImportCndThatIsOnOneLine() throws IOException {
+ String cnd = "<ns = 'http://namespace.com/ns'> "
+ + "[ns:NodeType] > ns:ParentType1, ns:ParentType2 abstract orderable mixin noquery primaryitem ex:property "
+ + "- ex:property (STRING) = 'default1', 'default2' mandatory autocreated protected multiple VERSION < 'constraint1', 'constraint2' "
+ + " queryops '=, <>, <, <=, >, >=, LIKE' nofulltext noqueryorder "
+ + "+ ns:node (ns:reqType1, ns:reqType2) = ns:defaultType mandatory autocreated protected sns version";
+ // importer.importFrom(cnd, problems, "string");
+ }
+
+ @Test
+ public void shouldImportCndThatHasNoChildren() throws IOException {
+ String cnd = "<ns = 'http://namespace.com/ns'>\n"
+ + "[ns:NodeType] > ns:ParentType1, ns:ParentType2 abstract orderable mixin noquery primaryitem ex:property\n"
+ + "- ex:property (STRING) = 'default1', 'default2' mandatory autocreated protected multiple VERSION < 'constraint1', 'constraint2'\n"
+ + " queryops '=, <>, <, <=, >, >=, LIKE' nofulltext noqueryorder";
+ // importer.importFrom(cnd, problems, "string");
+ }
+
+ @Test
+ public void shouldImportJcrBuiltinNodeTypesForJSR170() throws Exception {
+ importer.importFrom(openCndFile("jcr-builtins-170.cnd"), problems);
+ if (problems.size() != 0) printProblems();
+ assertThat(problems.size(), is(0));
+
+ // [nt:base]
+ // - jcr:primaryType (name) mandatory autocreated protected compute
+ // - jcr:mixinTypes (name) protected multiple compute
+ assertNodeType("nt:base", NO_SUPERTYPES, NO_PRIMARY_NAME);
+ assertProperty("nt:base", "jcr:primaryType", "Name", NO_DEFAULTS, new PropertyOptions[] {PropertyOptions.Mandatory,
+ PropertyOptions.Autocreated, PropertyOptions.Protected}, OnParentVersion.Compute);
+ assertProperty("nt:base", "jcr:mixinTypes", "Name", NO_DEFAULTS, new PropertyOptions[] {PropertyOptions.Multiple,
+ PropertyOptions.Protected}, OnParentVersion.Compute);
+
+ // [nt:unstructured]
+ // orderable
+ // - * (undefined) multiple
+ // - * (undefined)
+ // + * (nt:base) = nt:unstructured multiple version
+ assertNodeType("nt:unstructured", NO_SUPERTYPES, NO_PRIMARY_NAME, NodeOptions.Ordered);
+ assertProperty("nt:unstructured", "*[1]", "Undefined", NO_DEFAULTS, PropertyOptions.Multiple);
+ assertProperty("nt:unstructured", "*[2]", "Undefined", NO_DEFAULTS);
+ assertChild("nt:unstructured", "*[3]", "nt:base", "nt:unstructured", OnParentVersion.Version, ChildOptions.Multiple);
+
+ // [mix:referenceable]
+ // mixin
+ // - jcr:uuid (string) mandatory autocreated protected initialize
+ assertNodeType("mix:referenceable", NO_SUPERTYPES, NO_PRIMARY_NAME, NodeOptions.Mixin);
+ assertProperty("mix:referenceable",
+ "jcr:uuid",
+ "String",
+ NO_DEFAULTS,
+ OnParentVersion.Initialize,
+ PropertyOptions.Mandatory,
+ PropertyOptions.Autocreated,
+ PropertyOptions.Protected);
+
+ // [mix:lockable]
+ // mixin
+ // - jcr:lockOwner (string) protected ignore
+ // - jcr:lockIsDeep (boolean) protected ignore
+ assertNodeType("mix:lockable", NO_SUPERTYPES, NO_PRIMARY_NAME, NodeOptions.Mixin);
+ assertProperty("mix:lockable", "jcr:lockOwner", "String", NO_DEFAULTS, OnParentVersion.Ignore, PropertyOptions.Protected);
+ assertProperty("mix:lockable",
+ "jcr:lockIsDeep",
+ "Boolean",
+ NO_DEFAULTS,
+ OnParentVersion.Ignore,
+ PropertyOptions.Protected);
+
+ // [nt:propertyDefinition]
+ // - jcr:name (name)
+ // - jcr:autoCreated (boolean) mandatory
+ // - jcr:mandatory (boolean) mandatory
+ // - jcr:onParentVersion (string) mandatory
+ // < 'COPY', 'VERSION', 'INITIALIZE', 'COMPUTE', 'IGNORE', 'ABORT'
+ // - jcr:protected (boolean) mandatory
+ // - jcr:requiredType (string) mandatory
+ // < 'STRING', 'BINARY', 'LONG', 'DOUBLE', 'BOOLEAN', 'DATE', 'NAME', 'PATH', 'REFERENCE', 'UNDEFINED'
+ // - jcr:valueConstraints (string) multiple
+ // - jcr:defaultValues (undefined) multiple
+ // - jcr:multiple (boolean) mandatory
+ assertNodeType("nt:propertyDefinition", NO_SUPERTYPES, NO_PRIMARY_NAME);
+ assertProperty("nt:propertyDefinition", "jcr:name", "Name", NO_DEFAULTS);
+ assertProperty("nt:propertyDefinition", "jcr:autoCreated", "Boolean", NO_DEFAULTS, PropertyOptions.Mandatory);
+ assertProperty("nt:propertyDefinition", "jcr:mandatory", "Boolean", NO_DEFAULTS, PropertyOptions.Mandatory);
+ assertProperty("nt:propertyDefinition",
+ "jcr:onParentVersion",
+ "String",
+ NO_DEFAULTS,
+ new PropertyOptions[] {PropertyOptions.Mandatory},
+ null,
+ new String[] {"COPY", "VERSION", "INITIALIZE", "COMPUTE", "IGNORE", "ABORT"});
+ assertProperty("nt:propertyDefinition", "jcr:protected", "Boolean", NO_DEFAULTS, PropertyOptions.Mandatory);
+ assertProperty("nt:propertyDefinition",
+ "jcr:requiredType",
+ "String",
+ NO_DEFAULTS,
+ new PropertyOptions[] {PropertyOptions.Mandatory},
+ null,
+ new String[] {"STRING", "BINARY", "LONG", "DOUBLE", "BOOLEAN", "DATE", "NAME", "PATH", "REFERENCE",
+ "UNDEFINED"});
+ assertProperty("nt:propertyDefinition", "jcr:valueConstraints", "String", NO_DEFAULTS, PropertyOptions.Multiple);
+ assertProperty("nt:propertyDefinition", "jcr:defaultValues", "Undefined", NO_DEFAULTS, PropertyOptions.Multiple);
+ assertProperty("nt:propertyDefinition", "jcr:multiple", "Boolean", NO_DEFAULTS, PropertyOptions.Mandatory);
+ }
+
+ @Test
+ public void shouldImportJcrBuiltinNodeTypesForJSR283() throws Exception {
+ importer.importFrom(openCndFile("jcr-builtins-283-early-draft.cnd"), problems);
+ if (problems.size() != 0) printProblems();
+ assertThat(problems.size(), is(0));
+
+ // [nt:base]
+ // - jcr:primaryType (name) mandatory autocreated protected compute
+ // - jcr:mixinTypes (name) protected multiple compute
+ assertNodeType("nt:base", NO_SUPERTYPES, NO_PRIMARY_NAME, NodeOptions.Abstract);
+ assertProperty("nt:base", "jcr:primaryType", "Name", NO_DEFAULTS, new PropertyOptions[] {PropertyOptions.Mandatory,
+ PropertyOptions.Autocreated, PropertyOptions.Protected}, OnParentVersion.Compute);
+ assertProperty("nt:base", "jcr:mixinTypes", "Name", NO_DEFAULTS, new PropertyOptions[] {PropertyOptions.Multiple,
+ PropertyOptions.Protected}, OnParentVersion.Compute);
+
+ // [nt:unstructured]
+ // orderable
+ // - * (undefined) multiple
+ // - * (undefined)
+ // + * (nt:base) = nt:unstructured multiple version
+ assertNodeType("nt:unstructured", NO_SUPERTYPES, NO_PRIMARY_NAME, NodeOptions.Ordered);
+ assertProperty("nt:unstructured", "*[1]", "Undefined", NO_DEFAULTS, PropertyOptions.Multiple);
+ assertProperty("nt:unstructured", "*[2]", "Undefined", NO_DEFAULTS);
+ assertChild("nt:unstructured", "*[3]", "nt:base", "nt:unstructured", OnParentVersion.Version, ChildOptions.Multiple);
+
+ // [mix:referenceable]
+ // mixin
+ // - jcr:uuid (string) mandatory autocreated protected initialize
+ assertNodeType("mix:referenceable", NO_SUPERTYPES, NO_PRIMARY_NAME, NodeOptions.Mixin);
+ assertProperty("mix:referenceable",
+ "jcr:uuid",
+ "String",
+ NO_DEFAULTS,
+ OnParentVersion.Initialize,
+ PropertyOptions.Mandatory,
+ PropertyOptions.Autocreated,
+ PropertyOptions.Protected);
+
+ // [mix:lockable]
+ // mixin
+ // - jcr:lockOwner (string) protected ignore
+ // - jcr:lockIsDeep (boolean) protected ignore
+ assertNodeType("mix:lockable", NO_SUPERTYPES, NO_PRIMARY_NAME, NodeOptions.Mixin);
+ assertProperty("mix:lockable", "jcr:lockOwner", "String", NO_DEFAULTS, OnParentVersion.Ignore, PropertyOptions.Protected);
+ assertProperty("mix:lockable",
+ "jcr:lockIsDeep",
+ "Boolean",
+ NO_DEFAULTS,
+ OnParentVersion.Ignore,
+ PropertyOptions.Protected);
+
+ // [nt:propertyDefinition]
+ // - jcr:name (name)
+ // - jcr:autoCreated (boolean) mandatory
+ // - jcr:mandatory (boolean) mandatory
+ // - jcr:onParentVersion (string) mandatory
+ // < 'COPY', 'VERSION', 'INITIALIZE', 'COMPUTE', 'IGNORE', 'ABORT'
+ // - jcr:protected (boolean) mandatory
+ // - jcr:requiredType (string) mandatory
+ // < 'STRING', 'BINARY', 'LONG', 'DOUBLE', 'BOOLEAN', 'DATE', 'NAME', 'PATH', 'REFERENCE', 'UNDEFINED'
+ // - jcr:valueConstraints (string) multiple
+ // - jcr:defaultValues (undefined) multiple
+ // - jcr:multiple (boolean) mandatory
+ assertNodeType("nt:propertyDefinition", NO_SUPERTYPES, NO_PRIMARY_NAME);
+ assertProperty("nt:propertyDefinition", "jcr:name", "Name", NO_DEFAULTS);
+ assertProperty("nt:propertyDefinition", "jcr:autoCreated", "Boolean", NO_DEFAULTS, PropertyOptions.Mandatory);
+ assertProperty("nt:propertyDefinition", "jcr:mandatory", "Boolean", NO_DEFAULTS, PropertyOptions.Mandatory);
+ assertProperty("nt:propertyDefinition",
+ "jcr:onParentVersion",
+ "String",
+ NO_DEFAULTS,
+ new PropertyOptions[] {PropertyOptions.Mandatory},
+ null,
+ new String[] {"COPY", "VERSION", "INITIALIZE", "COMPUTE", "IGNORE", "ABORT"});
+ assertProperty("nt:propertyDefinition", "jcr:protected", "Boolean", NO_DEFAULTS, PropertyOptions.Mandatory);
+ assertProperty("nt:propertyDefinition",
+ "jcr:requiredType",
+ "String",
+ NO_DEFAULTS,
+ new PropertyOptions[] {PropertyOptions.Mandatory},
+ null,
+ new String[] {"STRING", "BINARY", "LONG", "DOUBLE", "BOOLEAN", "DATE", "NAME", "PATH", "REFERENCE",
+ "UNDEFINED"});
+ assertProperty("nt:propertyDefinition", "jcr:valueConstraints", "String", NO_DEFAULTS, PropertyOptions.Multiple);
+ assertProperty("nt:propertyDefinition", "jcr:defaultValues", "Undefined", NO_DEFAULTS, PropertyOptions.Multiple);
+ assertProperty("nt:propertyDefinition", "jcr:multiple", "Boolean", NO_DEFAULTS, PropertyOptions.Mandatory);
+ }
+
+ @Test
+ public void shouldImportCndThatIsEmpty() throws Exception {
+ importer.importFrom(openCndFile("empty.cnd"), problems);
+ if (problems.size() != 0) printProblems();
+ assertThat(problems.size(), is(0));
+ }
+
+ @Test
+ public void shouldImportCndForImageSequencer() throws Exception {
+ importer.importFrom(openCndFile("images.cnd"), problems);
+ if (problems.size() != 0) printProblems();
+ assertThat(problems.size(), is(0));
+ }
+
+ @Test
+ public void shouldImportCndForMp3Sequencer() throws Exception {
+ importer.importFrom(openCndFile("mp3.cnd"), problems);
+ if (problems.size() != 0) printProblems();
+ assertThat(problems.size(), is(0));
+ }
+
+ @Test
+ public void shouldNotImportFileThatIsNotAValidCnd() throws Exception {
+ importer.importFrom(openCndFile("invalid.cnd"), problems);
+ assertThat(problems.size(), is(1));
+ }
+
+ public static final String[] NO_DEFAULTS = {};
+ public static final String[] NO_SUPERTYPES = {};
+ public static final String[] NO_VALUE_CONSTRAINTS = {};
+ public static final String NO_PRIMARY_NAME = null;
+
+ public static enum PropertyOptions {
+ Mandatory,
+ Autocreated,
+ Protected,
+ Multiple,
+ FullTextSearchable,
+ QueryOrderable
+ }
+
+ public static enum ChildOptions {
+ Mandatory,
+ Autocreated,
+ Protected,
+ Multiple
+ }
+
+ public static enum NodeOptions {
+ Abstract,
+ Mixin,
+ Ordered,
+ Queryable
+ }
+
+ public static enum OnParentVersion {
+ Copy,
+ Version,
+ Initialize,
+ Compute,
+ Ignore,
+ Abort
+ }
+
+ protected void assertNodeType( String name,
+ String[] superTypes,
+ String primaryItemName,
+ NodeOptions... nodeOptions ) {
+ Set<NodeOptions> options = new HashSet<NodeOptions>();
+ for (NodeOptions option : nodeOptions)
+ options.add(option);
+
+ Node nodeType = node(name);
+ assertThat(nodeType, hasProperty(JcrLexicon.IS_MIXIN, options.contains(NodeOptions.Mixin)));
+ assertThat(nodeType, hasProperty(JcrLexicon.IS_ABSTRACT, options.contains(NodeOptions.Abstract)));
+ assertThat(nodeType, hasProperty(JcrLexicon.HAS_ORDERABLE_CHILD_NODES, options.contains(NodeOptions.Ordered)));
+ assertThat(nodeType, hasProperty(JcrLexicon.IS_QUERYABLE, !options.contains(NodeOptions.Queryable)));
+ assertThat(nodeType, hasProperty(JcrLexicon.PRIMARY_ITEM_NAME, name(primaryItemName)));
+ if (superTypes.length != 0) {
+ Name[] superTypeNames = new Name[superTypes.length];
+ for (int i = 0; i != superTypes.length; ++i) {
+ String requiredType = superTypes[i];
+ superTypeNames[i] = name(requiredType);
+ }
+ assertThat(nodeType, hasProperty(JcrLexicon.SUPERTYPES, (Object[])superTypeNames));
+ } else {
+ assertThat(nodeType.getProperty(JcrLexicon.SUPERTYPES), is(nullValue()));
+ }
+ }
+
+ protected void assertProperty( String nodeTypeName,
+ String propertyName,
+ String requiredType,
+ String[] defaultValues,
+ PropertyOptions... propertyOptions ) {
+ assertProperty(nodeTypeName, propertyName, requiredType, defaultValues, propertyOptions, null);
+ }
+
+ protected void assertProperty( String nodeTypeName,
+ String propertyName,
+ String requiredType,
+ String[] defaultValues,
+ OnParentVersion onParentVersion,
+ PropertyOptions... propertyOptions ) {
+ assertProperty(nodeTypeName, propertyName, requiredType, defaultValues, propertyOptions, onParentVersion);
+ }
+
+ protected void assertProperty( String nodeTypeName,
+ String propertyName,
+ String requiredType,
+ String[] defaultValues,
+ PropertyOptions[] propertyOptions,
+ OnParentVersion onParentVersioning,
+ String... valueConstraints ) {
+ Set<PropertyOptions> options = new HashSet<PropertyOptions>();
+ for (PropertyOptions option : propertyOptions)
+ options.add(option);
+
+ Node nodeType = node(nodeTypeName + "/" + propertyName);
+ assertThat(nodeType, hasProperty(JcrLexicon.REQUIRED_TYPE, requiredType.toUpperCase()));
+ assertThat(nodeType, hasProperty(JcrLexicon.MULTIPLE, options.contains(PropertyOptions.Multiple)));
+ assertThat(nodeType, hasProperty(JcrLexicon.MANDATORY, options.contains(PropertyOptions.Mandatory)));
+ assertThat(nodeType, hasProperty(JcrLexicon.AUTO_CREATED, options.contains(PropertyOptions.Autocreated)));
+ assertThat(nodeType, hasProperty(JcrLexicon.PROTECTED, options.contains(PropertyOptions.Protected)));
+ if (onParentVersioning != null) {
+ switch (onParentVersioning) {
+ case Abort:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "ABORT"));
+ break;
+ case Compute:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "COMPUTE"));
+ break;
+ case Copy:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "COPY"));
+ break;
+ case Ignore:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "IGNORE"));
+ break;
+ case Initialize:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "INITIALIZE"));
+ break;
+ case Version:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "VERSION"));
+ break;
+ }
+ } else {
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "COPY")); // it's copy by default
+ }
+ assertThat(nodeType, hasProperty(JcrLexicon.IS_FULL_TEXT_SEARCHABLE,
+ !options.contains(PropertyOptions.FullTextSearchable)));
+ assertThat(nodeType, hasProperty(JcrLexicon.IS_QUERY_ORDERABLE, !options.contains(PropertyOptions.QueryOrderable)));
+ if (valueConstraints.length != 0) {
+ assertThat(nodeType, hasProperty(JcrLexicon.VALUE_CONSTRAINTS, (Object[])valueConstraints));
+ } else {
+ assertThat(nodeType.getProperty(JcrLexicon.VALUE_CONSTRAINTS), is(nullValue()));
+ }
+ if (defaultValues.length != 0) {
+ assertThat(nodeType, hasProperty(JcrLexicon.DEFAULT_VALUES, (Object[])defaultValues));
+ } else {
+ assertThat(nodeType.getProperty(JcrLexicon.DEFAULT_VALUES), is(nullValue()));
+ }
+ }
+
+ protected void assertChild( String nodeTypeName,
+ String childName,
+ String requiredType,
+ String defaultPrimaryType,
+ ChildOptions[] childOptions,
+ OnParentVersion onParentVersioning ) {
+ assertChild(nodeTypeName, childName, new String[] {requiredType}, defaultPrimaryType, childOptions, onParentVersioning);
+ }
+
+ protected void assertChild( String nodeTypeName,
+ String childName,
+ String requiredType,
+ String defaultPrimaryType,
+ OnParentVersion onParentVersioning,
+ ChildOptions... childOptions ) {
+ assertChild(nodeTypeName, childName, new String[] {requiredType}, defaultPrimaryType, childOptions, onParentVersioning);
+ }
+
+ protected void assertChild( String nodeTypeName,
+ String childName,
+ String[] requiredTypes,
+ String defaultPrimaryType,
+ ChildOptions[] childOptions,
+ OnParentVersion onParentVersioning ) {
+ Set<ChildOptions> options = new HashSet<ChildOptions>();
+ for (ChildOptions option : childOptions)
+ options.add(option);
+
+ Node nodeType = node(nodeTypeName + "/" + childName);
+ assertThat(nodeType, hasProperty(JcrLexicon.DEFAULT_PRIMARY_TYPE, name(defaultPrimaryType)));
+ assertThat(nodeType, hasProperty(JcrLexicon.SAME_NAME_SIBLINGS, options.contains(ChildOptions.Multiple)));
+ assertThat(nodeType, hasProperty(JcrLexicon.MANDATORY, options.contains(ChildOptions.Mandatory)));
+ assertThat(nodeType, hasProperty(JcrLexicon.AUTO_CREATED, options.contains(ChildOptions.Autocreated)));
+ assertThat(nodeType, hasProperty(JcrLexicon.PROTECTED, options.contains(ChildOptions.Protected)));
+ switch (onParentVersioning) {
+ case Abort:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "ABORT"));
+ break;
+ case Compute:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "COMPUTE"));
+ break;
+ case Copy:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "COPY"));
+ break;
+ case Ignore:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "IGNORE"));
+ break;
+ case Initialize:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "INITIALIZE"));
+ break;
+ case Version:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, "VERSION"));
+ break;
+ default:
+ assertThat(nodeType, hasProperty(JcrLexicon.ON_PARENT_VERSION, is(nullValue())));
+ }
+ if (requiredTypes.length != 0) {
+ Name[] requiredTypeNames = new Name[requiredTypes.length];
+ for (int i = 0; i != requiredTypes.length; ++i) {
+ String requiredType = requiredTypes[i];
+ requiredTypeNames[i] = name(requiredType);
+ }
+ assertThat(nodeType, hasProperty(JcrLexicon.REQUIRED_PRIMARY_TYPES, (Object[])requiredTypeNames));
+ } else {
+ assertThat(nodeType.getProperty(JcrLexicon.REQUIRED_PRIMARY_TYPES), is(nullValue()));
+ }
+ }
+}
Added: trunk/dna-cnd/src/test/resources/cnd/empty.cnd
===================================================================
Added: trunk/dna-cnd/src/test/resources/cnd/images.cnd
===================================================================
--- trunk/dna-cnd/src/test/resources/cnd/images.cnd (rev 0)
+++ trunk/dna-cnd/src/test/resources/cnd/images.cnd 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,63 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+//------------------------------------------------------------------------------
+// N A M E S P A C E S
+//------------------------------------------------------------------------------
+<jcr='http://www.jcp.org/jcr/1.0'>
+<nt='http://www.jcp.org/jcr/nt/1.0'>
+<mix='http://www.jcp.org/jcr/mix/1.0'>
+<image='http://jboss.org/dna/images/1.0'>
+
+// ----------------------------------------------------------
+// JCR Pre-defined Mixin Types that are not loaded by default
+// ----------------------------------------------------------
+
+[mix:mimeType] mixin
+ - jcr:mimeType (string)
+ - jcr:encoding (string)
+
+
+//------------------------------------------------------------------------------
+// N O D E T Y P E S
+//------------------------------------------------------------------------------
+
+/**
+ * Mixin that defines the metadata for an image
+ */
+[image:metadata] > nt:unstructured, mix:mimeType
+ - image:formatName (string) mandatory
+ < 'JPEG', 'GIF', 'PNG', 'BMP', 'PCX', 'IFF', 'RAS', 'PBM', 'PGM', 'PPM', 'PSD'
+ - image:width (long)
+ - image:height (long)
+ - image:bitsPerPixel (long)
+ - image:progressive (boolean)
+ - image:numberOfImages (long)
+ - image:physicalWidthDpi (long)
+ - image:physicalHeightDpi (long)
+ - image:physicalWidthInches (long)
+ - image:physicalHeightInches (long)
+
+
+
\ No newline at end of file
Added: trunk/dna-cnd/src/test/resources/cnd/invalid.cnd
===================================================================
--- trunk/dna-cnd/src/test/resources/cnd/invalid.cnd (rev 0)
+++ trunk/dna-cnd/src/test/resources/cnd/invalid.cnd 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1 @@
+This is not a valid cnd file.
\ No newline at end of file
Added: trunk/dna-cnd/src/test/resources/cnd/jcr-builtins-170.cnd
===================================================================
--- trunk/dna-cnd/src/test/resources/cnd/jcr-builtins-170.cnd (rev 0)
+++ trunk/dna-cnd/src/test/resources/cnd/jcr-builtins-170.cnd 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+<rep='internal'>
+<jcr='http://www.jcp.org/jcr/1.0'>
+<nt='http://www.jcp.org/jcr/nt/1.0'>
+
+//------------------------------------------------------------------------------
+// B A S E T Y P E S
+//------------------------------------------------------------------------------
+
+[nt:base]
+ - jcr:primaryType (name) mandatory autocreated protected compute
+ - jcr:mixinTypes (name) protected multiple compute
+
+[nt:unstructured]
+ orderable
+ - * (undefined) multiple
+ - * (undefined)
+ + * (nt:base) = nt:unstructured multiple version
+
+[mix:referenceable]
+ mixin
+ - jcr:uuid (string) mandatory autocreated protected initialize
+
+[mix:lockable]
+ mixin
+ - jcr:lockOwner (string) protected ignore
+ - jcr:lockIsDeep (boolean) protected ignore
+
+//------------------------------------------------------------------------------
+// V E R S I O N I N G
+//------------------------------------------------------------------------------
+
+[mix:versionable] > mix:referenceable
+ mixin
+ - jcr:versionHistory (reference) mandatory protected
+ < 'nt:versionHistory'
+ - jcr:baseVersion (reference) mandatory protected ignore
+ < 'nt:version'
+ - jcr:isCheckedOut (boolean) = 'true' mandatory autocreated protected ignore
+ - jcr:predecessors (reference) mandatory protected multiple
+ < 'nt:version'
+ - jcr:mergeFailed (reference) protected multiple abort
+
+[nt:versionHistory] > mix:referenceable
+ - jcr:versionableUuid (string) mandatory autocreated protected abort
+ + jcr:rootVersion (nt:version) = nt:version mandatory autocreated protected abort
+ + jcr:versionLabels (nt:versionLabels) = nt:versionLabels mandatory autocreated protected abort
+ + * (nt:version) = nt:version protected abort
+
+[nt:versionLabels]
+ - * (reference) protected abort
+ < 'nt:version'
+
+[nt:version] > mix:referenceable
+ - jcr:created (date) mandatory autocreated protected abort
+ - jcr:predecessors (reference) protected multiple abort
+ < 'nt:version'
+ - jcr:successors (reference) protected multiple abort
+ < 'nt:version'
+ + jcr:frozenNode (nt:frozenNode) protected abort
+
+[nt:frozenNode] > mix:referenceable
+ orderable
+ - jcr:frozenPrimaryType (name) mandatory autocreated protected abort
+ - jcr:frozenMixinTypes (name) protected multiple abort
+ - jcr:frozenUuid (string) mandatory autocreated protected abort
+ - * (undefined) protected abort
+ - * (undefined) protected multiple abort
+ + * (nt:base) protected multiple abort
+
+[nt:versionedChild]
+ - jcr:childVersionHistory (reference) mandatory autocreated protected abort
+ < 'nt:versionHistory'
+
+//------------------------------------------------------------------------------
+// N O D E T Y P E S
+//------------------------------------------------------------------------------
+
+[nt:nodeType]
+ - jcr:nodeTypeName (name) mandatory
+ - jcr:supertypes (name) multiple
+ - jcr:isMixin (boolean) mandatory
+ - jcr:hasOrderableChildNodes (boolean) mandatory
+ - jcr:primaryItemName (name)
+ + jcr:propertyDefinition (nt:propertyDefinition) = nt:propertyDefinition multiple version
+ + jcr:childNodeDefinition (nt:childNodeDefinition) = nt:childNodeDefinition multiple version
+
+[nt:propertyDefinition]
+ - jcr:name (name)
+ - jcr:autoCreated (boolean) mandatory
+ - jcr:mandatory (boolean) mandatory
+ - jcr:onParentVersion (string) mandatory
+ < 'COPY', 'VERSION', 'INITIALIZE', 'COMPUTE', 'IGNORE', 'ABORT'
+ - jcr:protected (boolean) mandatory
+ - jcr:requiredType (string) mandatory
+ < 'STRING', 'BINARY', 'LONG', 'DOUBLE', 'BOOLEAN', 'DATE', 'NAME', 'PATH', 'REFERENCE', 'UNDEFINED'
+ - jcr:valueConstraints (string) multiple
+ - jcr:defaultValues (undefined) multiple
+ - jcr:multiple (boolean) mandatory
+
+[nt:childNodeDefinition]
+ - jcr:name (name)
+ - jcr:autoCreated (boolean) mandatory
+ - jcr:mandatory (boolean) mandatory
+ - jcr:onParentVersion (string) mandatory
+ < 'COPY', 'VERSION', 'INITIALIZE', 'COMPUTE', 'IGNORE', 'ABORT'
+ - jcr:protected (boolean) mandatory
+ - jcr:requiredPrimaryTypes (name) = 'nt:base' mandatory multiple
+ - jcr:defaultPrimaryType (name)
+ - jcr:sameNameSiblings (boolean) mandatory
+
+//------------------------------------------------------------------------------
+// M I S C
+//------------------------------------------------------------------------------
+
+[nt:hierarchyNode]
+ - jcr:created (date) autocreated protected initialize
+
+[nt:folder] > nt:hierarchyNode
+ + * (nt:hierarchyNode) version
+
+[nt:file] > nt:hierarchyNode
+ + jcr:content (nt:base) primary mandatory
+
+[nt:linkedFile] > nt:hierarchyNode
+ - jcr:content (reference) primary mandatory
+
+[nt:resource] > mix:referenceable
+ - jcr:encoding (string)
+ - jcr:mimeType (string) mandatory
+ - jcr:data (binary) primary mandatory
+ - jcr:lastModified (date) mandatory ignore
+
+[nt:query]
+ - jcr:statement (string)
+ - jcr:language (string)
+
+//------------------------------------------------------------------------------
+// J A C K R A B B I T I N T E R N A L S
+//------------------------------------------------------------------------------
+
+[rep:nodeTypes]
+ + * (nt:nodeType) = nt:nodeType protected abort
+
+[rep:root] > nt:unstructured
+ orderable
+ + jcr:system (rep:system) = rep:system mandatory ignore
+
+[rep:system]
+ orderable
+ + jcr:versionStorage (rep:versionStorage) = rep:versionStorage mandatory protected abort
+ + jcr:nodeTypes (rep:nodeTypes) = rep:nodeTypes mandatory protected abort
+ + * (nt:base) = nt:unstructured multiple ignore
+
+[rep:versionStorage]
+ + * (nt:versionHistory) = nt:versionHistory protected multiple abort
+ + * (rep:versionStorage) = rep:versionStorage protected multiple abort
Added: trunk/dna-cnd/src/test/resources/cnd/jcr-builtins-283-early-draft.cnd
===================================================================
--- trunk/dna-cnd/src/test/resources/cnd/jcr-builtins-283-early-draft.cnd (rev 0)
+++ trunk/dna-cnd/src/test/resources/cnd/jcr-builtins-283-early-draft.cnd 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,218 @@
+<jcr=http://www.jcp.org/jcr/1.0>
+<nt=http://www.jcp.org/jcr/nt/1.0>
+<mix=http://www.jcp.org/jcr/mix/1.0>
+<sv=http://www.jcp.org/jcr/sv/1.0>
+
+// ------------------------------------------------------------------------
+// Pre-defined Node Types
+// ------------------------------------------------------------------------
+
+[nt:base] abstract
+ - jcr:primaryType (name) mandatory autocreated
+ protected compute
+ - jcr:mixinTypes (name) protected multiple compute
+
+[nt:unstructured]
+ orderable
+ - * (undefined) multiple
+ - * (undefined)
+ + * (nt:base) = nt:unstructured multiple version
+
+[nt:hierarchyNode] > mix:created abstract
+
+[nt:file] > nt:hierarchyNode
+ + jcr:content (nt:base) primary mandatory
+
+[nt:linkedFile] > nt:hierarchyNode
+ - jcr:content (reference) primary mandatory
+
+[nt:folder] > nt:hierarchyNode
+ + * (nt:hierarchyNode) version
+
+[nt:resource] > mix:referenceable,
+ mix:mimeTyped,
+ mix:lastModified
+ - jcr:data (binary) primary mandatory
+
+[nt:nodeType]
+ - jcr:nodeTypeName (name) mandatory
+ - jcr:supertypes (name) multiple
+ - jcr:isAbstract (boolean) mandatory
+ - jcr:isMixin (boolean) mandatory
+ - jcr:hasOrderableChildNodes (boolean) mandatory
+ - jcr:primaryItemName (name)
+ + jcr:propertyDefinition (nt:propertyDefinition)
+ = nt:propertyDefinition multiple version
+ + jcr:childNodeDefinition (nt:childNodeDefinition)
+ = nt:childNodeDefinition multiple version
+
+[nt:propertyDefinition]
+ - jcr:name (name)
+ - jcr:autoCreated (boolean) mandatory
+ - jcr:mandatory (boolean) mandatory
+ - jcr:onParentVersion (string) mandatory
+ < 'COPY', 'VERSION', 'INITIALIZE', 'COMPUTE',
+ 'IGNORE', 'ABORT'
+ - jcr:protected (boolean) mandatory
+ - jcr:requiredType (string) mandatory
+ < 'STRING', 'BINARY', 'LONG', 'DOUBLE', 'BOOLEAN',
+ 'DATE', 'NAME', 'PATH', 'REFERENCE', 'UNDEFINED'
+ - jcr:valueConstraints (string) multiple
+ - jcr:defaultValues (undefined) multiple
+ - jcr:multiple (boolean) mandatory
+
+[nt:childNodeDefinition]
+ - jcr:name (name)
+ - jcr:autoCreated (boolean) mandatory
+ - jcr:mandatory (boolean) mandatory
+ - jcr:onParentVersion (string) mandatory
+ < 'COPY', 'VERSION', 'INITIALIZE', 'COMPUTE',
+ 'IGNORE', 'ABORT'
+ - jcr:protected (boolean) mandatory
+ - jcr:requiredPrimaryTypes (name) = 'nt:base' mandatory
+ multiple
+ - jcr:defaultPrimaryType (name)
+ - jcr:sameNameSiblings (boolean) mandatory
+
+[nt:versionHistory] > mix:referenceable
+ - jcr:versionableUuid (string) mandatory autocreated
+ protected abort
+ - jcr:copiedFrom (reference) protected abort
+ < 'nt:version'
+ + jcr:rootVersion (nt:version) = nt:version mandatory
+ autocreated protected abort
+ + jcr:versionLabels (nt:versionLabels)
+ = nt:versionLabels mandatory autocreated protected
+ abort
+ + * (nt:version) = nt:version protected abort
+
+[nt:versionLabels]
+ - * (reference) protected abort
+ < 'nt:version'
+
+[nt:version] > mix:referenceable
+ - jcr:created (date) mandatory autocreated protected
+ abort
+ - jcr:predecessors (reference) protected multiple abort
+ < 'nt:version'
+ - jcr:successors (reference) protected multiple abort
+ < 'nt:version'
+ - jcr:activity (reference) protected abort
+ < 'nt:activity'
+ + jcr:frozenNode (nt:frozenNode) protected abort
+
+[nt:frozenNode] > mix:referenceable
+ orderable
+ - jcr:frozenPrimaryType (name) mandatory autocreated
+ protected abort
+ - jcr:frozenMixinTypes (name) protected multiple abort
+ - jcr:frozenUuid (string) mandatory autocreated
+ protected abort
+ - * (undefined) protected abort
+ - * (undefined) protected multiple abort
+ + * (nt:base) protected multiple abort
+
+[nt:versionedChild]
+ - jcr:childVersionHistory (reference) mandatory
+ autocreated protected abort
+ < 'nt:versionHistory'
+
+[nt:query]
+ - jcr:statement (string)
+ - jcr:language (string)
+
+[nt:activity] > mix:referenceable
+ - jcr:title (string)
+ mandatory autocreated protected
+
+[nt:configuration] > mix:versionable
+ - jcr:root (reference)
+ mandatory autocreated protected
+
+[nt:address]
+ - jcr:protocol (string)
+ - jcr:host (string)
+ - jcr:port (string)
+ - jcr:repository (string)
+ - jcr:workspace (string)
+ - jcr:path (path)
+ - jcr:id (weakreference)
+
+[nt:naturalText]
+ - jcr:text (string)
+ - jcr:messageId (string)
+
+
+// ------------------------------------------------------------------------
+// Pre-defined Mixins
+// ------------------------------------------------------------------------
+
+[mix:lockable]
+ mixin
+ - jcr:lockOwner (string) protected ignore
+ - jcr:lockIsDeep (boolean) protected ignore
+
+[mix:referenceable]
+ mixin
+ - jcr:uuid (string) mandatory autocreated protected
+ initialize
+
+[mix:simpleVersionable] > mix:referenceable
+ mixin
+ - jcr:isCheckedOut (boolean) = 'true' mandatory
+ autocreated protected ignore
+ - jcr:versionLabels (name) mandatory protected multiple
+
+[mix:versionable] > mix:simpleVersionable
+ mixin
+ - jcr:versionHistory (reference) mandatory protected
+ < 'nt:versionHistory'
+ - jcr:baseVersion (reference) mandatory protected
+ ignore
+ < 'nt:version'
+ - jcr:predecessors (reference) mandatory protected
+ multiple
+ < 'nt:version'
+ - jcr:mergeFailed (reference) protected multiple abort
+ - jcr:activity (reference)
+ < 'nt:version'
+ - jcr:configuration (reference)
+ < 'nt:configuration'
+
+[mix:lifecycle]
+ mixin
+ - jcr:lifecyclePolicy (reference) protected initialize
+ - jcr:currentLifecycleState (string) protected
+initialize
+
+[mix:managedRetention] > mix:referenceable
+ mixin
+ - jcr:hold (string) protected multiple
+ - jcr:isDeep (boolean) protected multiple
+ - jcr:retentionPolicy (reference) protected
+
+[mix:shareable] > mix:referenceable mixin
+
+[mix:title] mixin
+ - jcr:title (string)
+ - jcr:description (string)
+
+[mix:created] mixin
+ - jcr:created (date)
+ - jcr:createdBy (string)
+
+[mix:lastModified] mixin
+ - jcr:lastModified (date)
+ - jcr:lastModifiedBy (string)
+
+[mix:language] mixin
+ - jcr:language (string)
+
+[mix:mimeType] mixin
+ - jcr:mimeType (string)
+ - jcr:encoding (string)
+
+
+
+
+
\ No newline at end of file
Added: trunk/dna-cnd/src/test/resources/cnd/mp3.cnd
===================================================================
--- trunk/dna-cnd/src/test/resources/cnd/mp3.cnd (rev 0)
+++ trunk/dna-cnd/src/test/resources/cnd/mp3.cnd 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,53 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+//------------------------------------------------------------------------------
+// N A M E S P A C E S
+//------------------------------------------------------------------------------
+<jcr='http://www.jcp.org/jcr/1.0'>
+<nt='http://www.jcp.org/jcr/nt/1.0'>
+<mix='http://www.jcp.org/jcr/mix/1.0'>
+<mp3='http://jboss.org/dna/mp3/1.0'>
+
+// ----------------------------------------------------------
+// JCR Pre-defined Mixin Types that are not loaded by default
+// ----------------------------------------------------------
+
+[mix:mimeType] mixin
+ - jcr:mimeType (string)
+ - jcr:encoding (string)
+
+
+//------------------------------------------------------------------------------
+// N O D E T Y P E S
+//------------------------------------------------------------------------------
+
+[mp3:metadata] > nt:unstructured, mix:mimeTyped
+ - mp3:title (string)
+ - mp3:author (string)
+ - mp3:album (string)
+ - mp3:year (long)
+ - mp3:comment (string)
+
+
\ No newline at end of file
Added: trunk/dna-cnd/src/test/resources/log4j.properties
===================================================================
--- trunk/dna-cnd/src/test/resources/log4j.properties (rev 0)
+++ trunk/dna-cnd/src/test/resources/log4j.properties 2009-04-20 19:07:48 UTC (rev 840)
@@ -0,0 +1,13 @@
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %m%n
+
+# Root logger option
+log4j.rootLogger=INFO, stdout
+
+# Set up the default logging to be INFO level, then override specific units
+log4j.logger.org.jboss.dna=INFO
+log4j.logger.org.jboss.dna.cnd=INFO
+
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-04-17 14:23:57 UTC (rev 839)
+++ trunk/pom.xml 2009-04-20 19:07:48 UTC (rev 840)
@@ -114,7 +114,8 @@
<module>dna-common</module>
<module>dna-graph</module>
<module>dna-repository</module>
- <module>dna-jcr</module>
+ <module>dna-cnd</module>
+ <!--module>dna-jcr</module-->
<module>extensions/dna-classloader-maven</module>
<module>extensions/dna-sequencer-images</module>
<module>extensions/dna-sequencer-mp3</module>
17 years