Author: rhauch
Date: 2008-07-24 15:52:13 -0400 (Thu, 24 Jul 2008)
New Revision: 369
Added:
trunk/connectors/dna-connector-federation/
trunk/connectors/dna-connector-federation/.classpath
trunk/connectors/dna-connector-federation/.project
trunk/connectors/dna-connector-federation/pom.xml
trunk/connectors/dna-connector-federation/src/
trunk/connectors/dna-connector-federation/src/main/
trunk/connectors/dna-connector-federation/src/main/java/
trunk/connectors/dna-connector-federation/src/main/java/org/
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConfig.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConnection.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationException.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/Projection.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/ProjectionParser.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/AbstractContribution.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PropertyContribution.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCreateNodeCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommand.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/BasicFederatedNode.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/BasicMergePlan.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/DoubleContributionMergePlan.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FederatedNode.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlan.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SingleContributionMergePlan.java
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/TripleContributionMergePlan.java
trunk/connectors/dna-connector-federation/src/main/resources/
trunk/connectors/dna-connector-federation/src/main/resources/org/
trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/
trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/
trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/connector/
trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/
trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
trunk/connectors/dna-connector-federation/src/test/
trunk/connectors/dna-connector-federation/src/test/java/
trunk/connectors/dna-connector-federation/src/test/java/org/
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryConnectionTest.java
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryTest.java
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederationI18nTest.java
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionParserTest.java
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionPathRuleTest.java
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionTest.java
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java
trunk/connectors/dna-connector-federation/src/test/resources/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositorySourceManager.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/ExecutionContextFactory.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/DelegatingCommandExecutor.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/LoggingCommandExecutor.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/NoOpCommandExecutor.java
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepository.java
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepositorySource.java
Removed:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/
Modified:
trunk/dna-repository/pom.xml
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
trunk/dna-spi/src/main/java/org/jboss/dna/spi/SpiI18n.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/Path.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathFactory.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/AbstractCommandExecutor.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/CommandExecutor.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCompositeCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCopyNodeCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCreateNodeCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicDeleteBranchCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetChildrenCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetNodeCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetPropertiesCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicMoveBranchCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicRecordBranchCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicSetPropertiesCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/BasicPath.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/PathValueFactory.java
trunk/dna-spi/src/main/resources/org/jboss/dna/spi/SpiI18n.properties
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/commands/executor/AbstractCommandExecutorTest.java
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/BasicPathTest.java
trunk/pom.xml
Log:
DNA-115 - Moved the federating functionality into a separate connector and out of
'dna-repository'. This cleans up the 'dna-repository' project and also
makes it easier to assemble and (re)use the federation capability in different parts of
the system.
Property changes on: trunk/connectors/dna-connector-federation
___________________________________________________________________
Name: svn:ignore
+ target
Added: trunk/connectors/dna-connector-federation/.classpath
===================================================================
--- trunk/connectors/dna-connector-federation/.classpath (rev 0)
+++ trunk/connectors/dna-connector-federation/.classpath 2008-07-24 19:52:13 UTC (rev
369)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/resources"/>
+ <classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
Added: trunk/connectors/dna-connector-federation/.project
===================================================================
--- trunk/connectors/dna-connector-federation/.project (rev 0)
+++ trunk/connectors/dna-connector-federation/.project 2008-07-24 19:52:13 UTC (rev 369)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>dna-connector-federation</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>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ </natures>
+</projectDescription>
Added: trunk/connectors/dna-connector-federation/pom.xml
===================================================================
--- trunk/connectors/dna-connector-federation/pom.xml (rev 0)
+++ trunk/connectors/dna-connector-federation/pom.xml 2008-07-24 19:52:13 UTC (rev 369)
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna</artifactId>
+ <version>0.2-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+ <!-- The groupId and version values are inherited from parent -->
+ <artifactId>dna-connector-federation</artifactId>
+ <packaging>jar</packaging>
+ <name>JBoss DNA Federation Connector</name>
+ <description>JBoss DNA Connector that federates content from multiple
connectors.</description>
+ <
url>http://labs.jboss.org/dna</url>
+
+ <properties>
+ <dna-version>0.2-SNAPSHOT</dna-version>
+ </properties>
+ <!--
+ Define the dependencies. Note that all version and scopes default to those
+ defined in the dependencyManagement section of the parent pom.
+ -->
+ <dependencies>
+ <!--
+ Common
+ -->
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ Testing (note the scope)
+ -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ </dependency>
+ <!--
+ Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for
testing)
+ -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <!--
+ Java Concurrency in Practice annotations
+ -->
+ <dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ </dependency>
+ </dependencies>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
\ No newline at end of file
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,259 @@
+/*
+ * 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.connector.federation;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.connector.federation.executor.FederatingCommandExecutor;
+import org.jboss.dna.spi.graph.commands.executor.CommandExecutor;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactories;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * The component that represents a single federated repository. The federated repository
uses a set of {@link RepositorySource
+ * federated sources} as designated by name through the {@link #getConfiguration()
configuration}, and provides the logic of
+ * interacting with those sources and presenting a single unified graph.
+ *
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class FederatedRepository {
+
+ private final ExecutionEnvironment env;
+ private final RepositoryConnectionFactories connectionFactories;
+ private FederatedRepositoryConfig config;
+ private final AtomicInteger openExecutors = new AtomicInteger(0);
+ private final CountDownLatch shutdownLatch = new CountDownLatch(1);
+ private final AtomicBoolean shutdownRequested = new AtomicBoolean(false);
+ private final CopyOnWriteArrayList<RepositorySourceListener> listeners = new
CopyOnWriteArrayList<RepositorySourceListener>();
+
+ /**
+ * Create a federated repository instance.
+ *
+ * @param env the execution environment
+ * @param connectionFactories the set of connection factories that should be used
+ * @param config the configuration for this repository
+ * @throws IllegalArgumentException if any of the parameters are null, or if the name
is blank
+ */
+ public FederatedRepository( ExecutionEnvironment env,
+ RepositoryConnectionFactories connectionFactories,
+ FederatedRepositoryConfig config ) {
+ ArgCheck.isNotNull(connectionFactories, "connectionFactories");
+ ArgCheck.isNotNull(env, "env");
+ ArgCheck.isNotNull(config, "config");
+ this.env = env;
+ this.connectionFactories = connectionFactories;
+ this.config = config;
+ }
+
+ /**
+ * Get the name of this repository
+ *
+ * @return name
+ */
+ public String getName() {
+ return this.config.getName();
+ }
+
+ /**
+ * @return the execution environment
+ */
+ public ExecutionEnvironment getExecutionEnvironment() {
+ return env;
+ }
+
+ /**
+ * @return connectionFactories
+ */
+ protected RepositoryConnectionFactories getConnectionFactories() {
+ return connectionFactories;
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ public synchronized void start() {
+ // Do not establish connections to the sources; these will be established as
needed
+ }
+
+ /**
+ * Return true if this federated repository is running and ready for connections.
+ *
+ * @return true if running, or false otherwise
+ */
+ public boolean isRunning() {
+ return this.shutdownRequested.get() != true;
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ public synchronized void shutdown() {
+ this.shutdownRequested.set(true);
+ if (this.openExecutors.get() <= 0) shutdownLatch.countDown();
+ }
+
+ /**
+ * Utility method called by the administrator.
+ *
+ * @param timeout
+ * @param unit
+ * @return true if all connections open at the time this method is called were {@link
RepositoryConnection#close() closed} in
+ * the supplied time, or false if the timeout occurred before all the
connections were closed
+ * @throws InterruptedException
+ */
+ public boolean awaitTermination( long timeout,
+ TimeUnit unit ) throws InterruptedException {
+ // Await until all connections have been closed, or until the timeout occurs
+ return shutdownLatch.await(timeout, unit);
+ }
+
+ /**
+ * Return true if this federated repository has completed its termination and no
longer has any open connections.
+ *
+ * @return true if terminated, or false otherwise
+ */
+ public boolean isTerminated() {
+ return this.openExecutors.get() != 0;
+ }
+
+ /**
+ * Add a listener that is to receive notifications to changes to content within this
repository. This method does nothing if
+ * the supplied listener is null.
+ *
+ * @param listener the new listener
+ * @return true if the listener was added, or false if the listener was not added (if
reference is null, or if non-null
+ * listener is already an existing listener)
+ */
+ public boolean addListener( RepositorySourceListener listener ) {
+ if (listener == null) return false;
+ return this.listeners.addIfAbsent(listener);
+ }
+
+ /**
+ * Remove the supplied listener. This method does nothing if the supplied listener is
null.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param listener the listener to remove
+ * @return true if the listener was removed, or false if the listener was not
registered
+ */
+ public boolean removeListener( RepositorySourceListener listener ) {
+ if (listener == null) return false;
+ return this.listeners.remove(listener);
+ }
+
+ /**
+ * Get the list of listeners, which is the actual list used by the repository.
+ *
+ * @return the listeners
+ */
+ public List<RepositorySourceListener> getListeners() {
+ return this.listeners;
+ }
+
+ /**
+ * Authenticate the supplied username with the supplied credentials, and return
whether authentication was successful.
+ *
+ * @param source the {@link RepositorySource} that should be affiliated with the
resulting connection
+ * @param username the username
+ * @param credentials the credentials
+ * @return the repository connection if authentication succeeded, or null otherwise
+ */
+ public RepositoryConnection createConnection( RepositorySource source,
+ String username,
+ Object credentials ) {
+ return new FederatedRepositoryConnection(this, source.getName());
+ }
+
+ /**
+ * Get the configuration of this repository. This configuration is immutable and may
be
+ * {@link #setConfiguration(FederatedRepositoryConfig) changed} as needed. Therefore,
when using a configuration and needing a
+ * consistent configuration, maintain a reference to the configuration during that
time (as the actual configuration may be
+ * replaced at any time).
+ *
+ * @return the repository's configuration at the time this method is called.
+ */
+ public FederatedRepositoryConfig getConfiguration() {
+ return config;
+ }
+
+ /**
+ * Set the configuration for this repository. The configuration is immutable and
therefore may be replaced using this method.
+ * All interaction with the configuration is done in a thread-safe and concurrent
manner, and as such only valid
+ * configurations should be used.
+ *
+ * @param config the new configuration
+ * @throws IllegalArgumentException if the configuration is null
+ */
+ public void setConfiguration( FederatedRepositoryConfig config ) {
+ ArgCheck.isNotNull(config, "config");
+ this.config = config;
+ }
+
+ /**
+ * Called by
+ * {@link FederatedRepositoryConnection#execute(ExecutionEnvironment,
org.jboss.dna.spi.graph.commands.GraphCommand...)}.
+ *
+ * @param env the execution environment in which the executor will be run; may not be
null
+ * @param sourceName the name of the {@link RepositorySource} that is making use of
this executor; may not be null or empty
+ * @return the executor
+ */
+ protected CommandExecutor getExecutor( ExecutionEnvironment env,
+ String sourceName ) {
+ FederatedRepositoryConfig config = this.getConfiguration();
+ return new FederatingCommandExecutor(env, sourceName,
config.getCacheProjection(), config.getSourceProjections(),
+ getConnectionFactories());
+ }
+
+ /**
+ * Called by {@link
FederatedRepositoryConnection#FederatedRepositoryConnection(FederatedRepository,
String)}.
+ *
+ * @param connection the connection being opened
+ */
+ /*package*/void register( FederatedRepositoryConnection connection ) {
+ openExecutors.incrementAndGet();
+ }
+
+ /**
+ * Called by {@link FederatedRepositoryConnection#close()}.
+ *
+ * @param connection the connection being closed
+ */
+ /*package*/void unregister( FederatedRepositoryConnection connection ) {
+ if (openExecutors.decrementAndGet() <= 0 && shutdownRequested.get())
{
+ // Last connection, so turn out the lights ...
+ shutdownLatch.countDown();
+ }
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConfig.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConfig.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConfig.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,177 @@
+/*
+ * 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.connector.federation;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.collection.ThreadSafeProblems;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * The configuration of a federated repository. The configuration defines, among other
things, the set of
+ * {@link #getSourceProjections() source projections} in the federated repository that
each specify how and where content from a
+ * {@link RepositorySource source} is federated into the unified repository.
+ *
+ * @author Randall Hauch
+ */
+@Immutable
+public class FederatedRepositoryConfig implements
Comparable<FederatedRepositoryConfig> {
+
+ private final Projection cacheProjection;
+ private final List<Projection> sourceProjections;
+ private final Problems problems;
+ private final String name;
+ private final CachePolicy defaultCachePolicy;
+
+ /**
+ * Create a federated repository instance.
+ *
+ * @param repositoryName the name of the repository
+ * @param cacheProjection the projection used for the cache; may not be null
+ * @param sourceProjections the source projections; may not be null
+ * @param defaultCachePolicy the default cache policy for this repository; may be
null
+ * @throws IllegalArgumentException if the name is null or is blank
+ */
+ public FederatedRepositoryConfig( String repositoryName,
+ Projection cacheProjection,
+ Iterable<Projection> sourceProjections,
+ CachePolicy defaultCachePolicy ) {
+ ArgCheck.isNotEmpty(repositoryName, "repositoryName");
+ ArgCheck.isNotNull(cacheProjection, "cacheProjection");
+ this.name = repositoryName;
+ this.problems = new ThreadSafeProblems();
+ this.defaultCachePolicy = defaultCachePolicy;
+ this.cacheProjection = cacheProjection;
+ List<Projection> projectionList = new ArrayList<Projection>();
+ for (Projection projection : sourceProjections) {
+ if (projection == null) continue;
+ if (!projectionList.contains(projection)) {
+ projectionList.add(projection);
+ }
+ }
+ this.sourceProjections = Collections.unmodifiableList(projectionList);
+ ArgCheck.isNotEmpty(this.sourceProjections, "sourceProjections");
+ }
+
+ /**
+ * Get the name of this repository
+ *
+ * @return name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Return the problem associated with this configuration. These problems may change
at any time, although the returned
+ * {@link Problems} object is thread-safe.
+ *
+ * @return the thread-safe problems for this configuration
+ */
+ public Problems getProblems() {
+ return problems;
+ }
+
+ /**
+ * Get the projection that defines the cache for this repository. This projection
does not exist in the
+ * {@link #getSourceProjections() list of source projections}.
+ *
+ * @return the region used for caching; never null
+ */
+ public Projection getCacheProjection() {
+ return cacheProjection;
+ }
+
+ /**
+ * Return the unmodifiable list of source projections.
+ *
+ * @return the source projections; never null and never empty
+ */
+ public List<Projection> getSourceProjections() {
+ return sourceProjections;
+ }
+
+ /**
+ * Get the default cache policy for the repository with the supplied name
+ *
+ * @return the default cache policy
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return defaultCachePolicy;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return this.name.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof FederatedRepositoryConfig) {
+ FederatedRepositoryConfig that = (FederatedRepositoryConfig)obj;
+ if (!this.getName().equals(that.getName())) return false;
+ if (!this.getCacheProjection().equals(that.getCacheProjection())) return
false;
+ if (!this.getSourceProjections().equals(that.getSourceProjections())) return
false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo( FederatedRepositoryConfig that ) {
+ if (that == this) return 0;
+ int diff = this.getName().compareTo(that.getName());
+ if (diff != 0) return diff;
+ diff = this.getCacheProjection().compareTo(that.getCacheProjection());
+ if (diff != 0) return diff;
+ Iterator<Projection> thisIter = this.getSourceProjections().iterator();
+ Iterator<Projection> thatIter = that.getSourceProjections().iterator();
+ while (thisIter.hasNext() && thatIter.hasNext()) {
+ diff = thisIter.next().compareTo(thatIter.next());
+ if (diff != 0) return diff;
+ }
+ if (thisIter.hasNext()) return 1;
+ if (thatIter.hasNext()) return -1;
+ return 0;
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConnection.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConnection.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConnection.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,139 @@
+/*
+ * 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.connector.federation;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.transaction.xa.XAResource;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.executor.CommandExecutor;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class FederatedRepositoryConnection implements RepositoryConnection {
+
+ protected static final RepositorySourceListener NO_OP_LISTENER = new
RepositorySourceListener() {
+ public void notify( String sourceName,
+ Object... events ) {
+ // do nothing
+ }
+ };
+
+ private final FederatedRepository repository;
+ private final String sourceName;
+ private final AtomicReference<RepositorySourceListener> listener;
+
+ protected FederatedRepositoryConnection( FederatedRepository repository,
+ String sourceName ) {
+ assert sourceName != null;
+ assert repository != null;
+ this.sourceName = sourceName;
+ this.repository = repository;
+ this.listener = new
AtomicReference<RepositorySourceListener>(NO_OP_LISTENER);
+ this.repository.register(this);
+ }
+
+ /**
+ * @return repository
+ */
+ protected FederatedRepository getRepository() {
+ return this.repository;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSourceName() {
+ return this.sourceName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return this.repository.getConfiguration().getDefaultCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public XAResource getXAResource() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setListener( RepositorySourceListener listener ) {
+ if (listener == null) listener = NO_OP_LISTENER;
+ RepositorySourceListener oldListener = this.listener.getAndSet(listener);
+ this.repository.addListener(listener);
+ if (oldListener != NO_OP_LISTENER) {
+ this.repository.removeListener(oldListener);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean ping( long time,
+ TimeUnit unit ) {
+ return this.repository.isRunning();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void execute( ExecutionEnvironment env,
+ GraphCommand... commands ) throws RepositorySourceException,
InterruptedException {
+ if (!this.repository.isRunning()) {
+ throw new
RepositorySourceException(FederationI18n.repositoryHasBeenShutDown.text(this.repository.getName()));
+ }
+ if (commands == null || commands.length == 0) return;
+
+ CommandExecutor executor = this.repository.getExecutor(env, sourceName);
+ assert executor != null;
+ for (GraphCommand command : commands) {
+ executor.execute(command);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() {
+ try {
+ this.repository.removeListener(this.listener.get());
+ } finally {
+ this.repository.unregister(this);
+ }
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,961 @@
+/*
+ * 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.connector.federation;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.LoginException;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.collection.SimpleProblems;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.connector.federation.executor.FederatingCommandExecutor;
+import org.jboss.dna.connector.federation.executor.SingleProjectionCommandExecutor;
+import org.jboss.dna.spi.ExecutionContextFactory;
+import org.jboss.dna.spi.cache.BasicCachePolicy;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.InvalidPathException;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.ValueFactory;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.executor.CommandExecutor;
+import org.jboss.dna.spi.graph.commands.executor.LoggingCommandExecutor;
+import org.jboss.dna.spi.graph.commands.executor.NoOpCommandExecutor;
+import org.jboss.dna.spi.graph.commands.impl.BasicCompositeCommand;
+import org.jboss.dna.spi.graph.commands.impl.BasicGetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.impl.BasicGetNodeCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactories;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class FederatedRepositorySource implements RepositorySource {
+
+ /**
+ */
+ private static final long serialVersionUID = 7587346948013486977L;
+
+ public static final int DEFAULT_RETRY_LIMIT = 0;
+ public static final String[] DEFAULT_CONFIGURATION_SOURCE_PROJECTION_RULES =
{"/dna:system => /"};
+
+ protected static final String REPOSITORY_NAME = "repositoryName";
+ protected static final String SOURCE_NAME = "sourceName";
+ protected static final String USERNAME = "username";
+ protected static final String PASSWORD = "password";
+ protected static final String CONFIGURATION_SOURCE_NAME =
"configurationSourceName";
+ protected static final String CONFIGURATION_SOURCE_PROJECTION_RULES =
"configurationSourceProjectionRules";
+ protected static final String CONNECTION_FACTORIES_JNDI_NAME =
"connectionFactoriesJndiName";
+ protected static final String EXECUTION_CONTEXT_FACTORY_JNDI_NAME =
"executionContextFacotryJndiName";
+ protected static final String REPOSITORY_JNDI_NAME = "repositoryJndiName";
+ protected static final String SECURITY_DOMAIN = "securityDomain";
+ protected static final String RETRY_LIMIT = "retryLimit";
+
+ protected static final String PROJECTION_RULES_CONFIG_PROPERTY_NAME =
"dna:projectionRules";
+ protected static final String CACHE_POLICY_TIME_TO_EXPIRE_CONFIG_PROPERTY_NAME =
"dna:timeToExpire";
+ protected static final String CACHE_POLICY_TIME_TO_CACHE_CONFIG_PROPERTY_NAME =
"dna:timeToCache";
+
+ private String repositoryName;
+ private String sourceName;
+ private String username;
+ private String password;
+ private String configurationSourceName;
+ private String[] configurationSourceProjectionRules =
DEFAULT_CONFIGURATION_SOURCE_PROJECTION_RULES;
+ private String connectionFactoriesJndiName;
+ private String executionContextFactoryJndiName;
+ private String securityDomain;
+ private String repositoryJndiName;
+ private int retryLimit = DEFAULT_RETRY_LIMIT;
+ private transient FederatedRepository repository;
+ private transient Context jndiContext;
+
+ /**
+ * Create a new instance of the source, which must still be properly initialized with
a {@link #setRepositoryName(String)
+ * repository name}.
+ */
+ public FederatedRepositorySource() {
+ }
+
+ /**
+ * Create a new instance of the source with the required repository name and
federation service.
+ *
+ * @param repositoryName the repository name
+ * @throws IllegalArgumentException if the federation service is null or the
repository name is null or blank
+ */
+ public FederatedRepositorySource( String repositoryName ) {
+ ArgCheck.isNotNull(repositoryName, "repositoryName");
+ this.repositoryName = repositoryName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getRetryLimit() {
+ return this.retryLimit;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setRetryLimit( int limit ) {
+ this.retryLimit = limit > 0 ? limit : 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized RepositoryConnection getConnection() throws
RepositorySourceException {
+ if (getName() == null) {
+ throw new
RepositorySourceException(FederationI18n.propertyIsRequired.text("name"));
+ }
+ if (getExecutionContextFactoryJndiName() == null) {
+ throw new
RepositorySourceException(FederationI18n.propertyIsRequired.text("execution context
factory JNDI name"));
+ }
+ if (getSecurityDomain() == null) {
+ throw new
RepositorySourceException(FederationI18n.propertyIsRequired.text("security
domain"));
+ }
+ if (getConnectionFactoriesJndiName() == null) {
+ throw new
RepositorySourceException(FederationI18n.propertyIsRequired.text("connection
factories JNDI name"));
+ }
+ // Find the repository ...
+ FederatedRepository repository = getRepository();
+ // Authenticate the user ...
+ String username = this.username;
+ Object credentials = this.password;
+ RepositoryConnection connection = repository.createConnection(this, username,
credentials);
+ if (connection == null) {
+ I18n msg =
FederationI18n.unableToAuthenticateConnectionToFederatedRepository;
+ throw new RepositorySourceException(msg.text(this.repositoryName,
username));
+ }
+ // Return the new connection ...
+ return connection;
+ }
+
+ /**
+ * Get the {@link FederatedRepository} instance that this source is using. This
method uses the following logic:
+ * <ol>
+ * <li>If a {@link FederatedRepository} already was obtained from a prior call,
the same instance is returned.</li>
+ * <li>A {@link FederatedRepository} is created using a {@link
FederatedRepositoryConfig} is created from this instance's
+ * properties and {@link ExecutionEnvironment} and {@link
RepositoryConnectionFactories} instances obtained from JNDI.</li>
+ * <li></li>
+ * <li></li>
+ * </ol>
+ *
+ * @return the federated repository instance
+ * @throws RepositorySourceException
+ */
+ protected synchronized FederatedRepository getRepository() throws
RepositorySourceException {
+ if (repository == null) {
+ String jndiName = this.getRepositoryJndiName();
+ Context context = getContext();
+ if (jndiName != null && jndiName.trim().length() != 0) {
+ // Look for an existing repository in JNDI ...
+ try {
+ if (context == null) context = new InitialContext();
+ repository = (FederatedRepository)context.lookup(jndiName);
+ } catch (Throwable err) {
+ I18n msg = FederationI18n.unableToFindFederatedRepositoryInJndi;
+ throw new RepositorySourceException(msg.text(this.sourceName,
jndiName), err);
+ }
+ }
+
+ if (repository == null) {
+ // Find in JNDI the repository connection factories and the environment
...
+ ExecutionEnvironment env = getExecutionEnvironment();
+ RepositoryConnectionFactories factories =
getRepositoryConnectionFactories();
+ // And create the configuration and the repository ...
+ FederatedRepositoryConfig config = getRepositoryConfiguration(env,
factories);
+ repository = new FederatedRepository(env, factories, config);
+ }
+ }
+ return repository;
+ }
+
+ protected ExecutionEnvironment getExecutionEnvironment() {
+ ExecutionContextFactory factory = null;
+ Context context = getContext();
+ String jndiName = getExecutionContextFactoryJndiName();
+ if (jndiName != null && jndiName.trim().length() != 0) {
+ try {
+ if (context == null) context = new InitialContext();
+ factory = (ExecutionContextFactory)context.lookup(jndiName);
+ } catch (Throwable err) {
+ I18n msg = FederationI18n.unableToFindExecutionContextFactoryInJndi;
+ throw new RepositorySourceException(msg.text(this.sourceName, jndiName),
err);
+ }
+ }
+ if (factory == null) {
+ I18n msg = FederationI18n.unableToFindExecutionContextFactoryInJndi;
+ throw new RepositorySourceException(msg.text(this.sourceName, jndiName));
+ }
+ String securityDomain = getSecurityDomain();
+ CallbackHandler handler = createCallbackHandler();
+ try {
+ return factory.create(securityDomain, handler);
+ } catch (LoginException e) {
+ I18n msg = FederationI18n.unableToCreateExecutionContext;
+ throw new RepositorySourceException(msg.text(this.sourceName, jndiName,
securityDomain), e);
+ }
+ }
+
+ protected RepositoryConnectionFactories getRepositoryConnectionFactories() {
+ RepositoryConnectionFactories factories = null;
+ Context context = getContext();
+ String jndiName = getConnectionFactoriesJndiName();
+ if (jndiName != null && jndiName.trim().length() != 0) {
+ try {
+ if (context == null) context = new InitialContext();
+ factories = (RepositoryConnectionFactories)context.lookup(jndiName);
+ } catch (Throwable err) {
+ I18n msg =
FederationI18n.unableToFindRepositoryConnectionFactoriesInJndi;
+ throw new RepositorySourceException(msg.text(this.sourceName, jndiName),
err);
+ }
+ }
+ if (factories == null) {
+ I18n msg = FederationI18n.noRepositoryConnectionFactories;
+ throw new RepositorySourceException(msg.text(this.repositoryName));
+ }
+ return factories;
+ }
+
+ protected CallbackHandler createCallbackHandler() {
+ return new CallbackHandler() {
+ public void handle( Callback[] callbacks ) {
+ for (Callback callback : callbacks) {
+ if (callback instanceof NameCallback) {
+ NameCallback nameCallback = (NameCallback)callback;
+
nameCallback.setName(FederatedRepositorySource.this.getUsername());
+ }
+ if (callback instanceof PasswordCallback) {
+ PasswordCallback passwordCallback = (PasswordCallback)callback;
+
passwordCallback.setPassword(FederatedRepositorySource.this.getPassword().toCharArray());
+ }
+ }
+ }
+ };
+ }
+
+ protected Context getContext() {
+ return this.jndiContext;
+ }
+
+ protected synchronized void setContext( Context context ) {
+ this.jndiContext = context;
+ }
+
+ /**
+ * Create a {@link FederatedRepositoryConfig} instance from the current properties of
this instance. This method does
+ * <i>not</i> modify the state of this instance.
+ *
+ * @param env the execution environment that should be used to read the
configuration; may not be null
+ * @param factories the factories from which can be obtained the
RepositoryConnectionFactory instances for each name source;
+ * may not be null
+ * @return a configuration reflecting the current state of this instance
+ */
+ protected synchronized FederatedRepositoryConfig getRepositoryConfiguration(
ExecutionEnvironment env,
+
RepositoryConnectionFactories factories ) {
+ Problems problems = new SimpleProblems();
+ ValueFactories valueFactories = env.getValueFactories();
+ PathFactory pathFactory = valueFactories.getPathFactory();
+ NameFactory nameFactory = valueFactories.getNameFactory();
+ ValueFactory<Long> longFactory = valueFactories.getLongFactory();
+
+ // Create the configuration projection ...
+ ProjectionParser projectionParser = ProjectionParser.getInstance();
+ Projection.Rule[] rules = projectionParser.rulesFromStrings(env,
this.getConfigurationSourceProjectionRules());
+ Projection configurationProjection = new
Projection(this.getConfigurationSourceName(), rules);
+
+ // Create a federating command executor to execute the commands and merge the
results into a single set of
+ // commands.
+ final String configurationSourceName = configurationProjection.getSourceName();
+ List<Projection> projections =
Collections.singletonList(configurationProjection);
+ CommandExecutor executor = null;
+ if (configurationProjection.getRules().size() == 1) {
+ // There is just a single projection for the configuration repository, so
just use an executor that
+ // translates the paths using the projection
+ executor = new SingleProjectionCommandExecutor(env, configurationSourceName,
configurationProjection, factories);
+ } else if (configurationProjection.getRules().size() == 0) {
+ // There is no projection for the configuration repository, so just use a
no-op executor
+ executor = new NoOpCommandExecutor(env, configurationSourceName);
+ } else {
+ // The configuration repository has more than one projection, so we need to
merge the results
+ executor = new FederatingCommandExecutor(env, configurationSourceName, null,
projections, factories);
+ }
+ // Wrap the executor with a logging executor ...
+ executor = new LoggingCommandExecutor(executor, Logger.getLogger(getClass()),
Logger.Level.INFO);
+
+ // The configuration projection (via "executor") will convert this path
into a path that exists in the configuration
+ // repository
+ Path configNode = pathFactory.create("/dna:system/dna:federation");
+
+ try {
+ // Get the repository node ...
+ BasicGetNodeCommand getRepository = new BasicGetNodeCommand(configNode);
+ executor.execute(getRepository);
+ if (getRepository.hasError()) {
+ throw new
FederationException(FederationI18n.federatedRepositoryCannotBeFound.text(repositoryName));
+ }
+
+ // Add a command to get the projection defining the cache ...
+ Path pathToCacheRegion = pathFactory.create(configNode,
nameFactory.create("dna:cache"));
+ BasicGetNodeCommand getCacheRegion = new
BasicGetNodeCommand(pathToCacheRegion);
+ executor.execute(getCacheRegion);
+ Projection cacheProjection = createProjection(env,
+ projectionParser,
+ getCacheRegion.getPath(),
+
getCacheRegion.getProperties(),
+ problems);
+
+ if (getCacheRegion.hasError()) {
+ I18n msg = FederationI18n.requiredNodeDoesNotExistRelativeToNode;
+ throw new FederationException(msg.text("dna:cache",
configNode));
+ }
+
+ // Get the source projections for the repository ...
+ Path projectionsNode = pathFactory.create(configNode,
nameFactory.create("dna:projections"));
+ BasicGetChildrenCommand getProjections = new
BasicGetChildrenCommand(projectionsNode);
+
+ executor.execute(getProjections);
+ if (getProjections.hasError()) {
+ I18n msg = FederationI18n.requiredNodeDoesNotExistRelativeToNode;
+ throw new FederationException(msg.text("dna:projections",
configNode));
+ }
+
+ // Build the commands to get each of the projections (children of the
"dna:projections" node) ...
+ List<Projection> sourceProjections = new
LinkedList<Projection>();
+ if (getProjections.hasNoError() &&
!getProjections.getChildren().isEmpty()) {
+ BasicCompositeCommand commands = new BasicCompositeCommand();
+ for (Path.Segment child : getProjections.getChildren()) {
+ final Path pathToSource = pathFactory.create(projectionsNode,
child);
+ commands.add(new BasicGetNodeCommand(pathToSource));
+ }
+ // Now execute these commands ...
+ executor.execute(commands);
+
+ // Iterate over each region node obtained ...
+ for (GraphCommand command : commands) {
+ BasicGetNodeCommand getProjectionCommand =
(BasicGetNodeCommand)command;
+ if (getProjectionCommand.hasNoError()) {
+ Projection projection = createProjection(env,
+ projectionParser,
+
getProjectionCommand.getPath(),
+
getProjectionCommand.getProperties(),
+ problems);
+ if (projection != null) sourceProjections.add(projection);
+ }
+ }
+ }
+
+ // Look for the default cache policy ...
+ BasicCachePolicy cachePolicy = new BasicCachePolicy();
+ Property timeToExpireProperty =
getRepository.getProperties().get(nameFactory.create(CACHE_POLICY_TIME_TO_EXPIRE_CONFIG_PROPERTY_NAME));
+ Property timeToCacheProperty =
getRepository.getProperties().get(nameFactory.create(CACHE_POLICY_TIME_TO_CACHE_CONFIG_PROPERTY_NAME));
+ if (timeToCacheProperty != null && !timeToCacheProperty.isEmpty()) {
+
cachePolicy.setTimeToCache(longFactory.create(timeToCacheProperty.getValues().next()));
+ }
+ if (timeToExpireProperty != null && !timeToExpireProperty.isEmpty())
{
+
cachePolicy.setTimeToExpire(longFactory.create(timeToExpireProperty.getValues().next()));
+ }
+ CachePolicy defaultCachePolicy = cachePolicy.isEmpty() ? null :
cachePolicy.getUnmodifiable();
+ return new FederatedRepositoryConfig(repositoryName, cacheProjection,
sourceProjections, defaultCachePolicy);
+ } catch (InvalidPathException err) {
+ I18n msg = FederationI18n.federatedRepositoryCannotBeFound;
+ throw new FederationException(msg.text(repositoryName));
+ } catch (InterruptedException err) {
+ I18n msg =
FederationI18n.interruptedWhileUsingFederationConfigurationRepository;
+ throw new FederationException(msg.text(repositoryName));
+ }
+
+ }
+
+ /**
+ * Instantiate the {@link Projection} described by the supplied properties.
+ *
+ * @param env the execution environment that should be used to read the
configuration; may not be null
+ * @param projectionParser the projection rule parser that should be used; may not be
null
+ * @param path the path to the node where these properties were found; never null
+ * @param properties the properties; never null
+ * @param problems the problems container in which any problems should be reported;
never null
+ * @return the region instance, or null if it could not be created
+ */
+ protected Projection createProjection( ExecutionEnvironment env,
+ ProjectionParser projectionParser,
+ Path path,
+ Map<Name, Property> properties,
+ Problems problems ) {
+ ValueFactories valueFactories = env.getValueFactories();
+ NameFactory nameFactory = valueFactories.getNameFactory();
+ ValueFactory<String> stringFactory = valueFactories.getStringFactory();
+
+ String sourceName = path.getLastSegment().getName().getLocalName();
+
+ // Get the rules ...
+ Projection.Rule[] projectionRules = null;
+ Property projectionRulesProperty =
properties.get(nameFactory.create(PROJECTION_RULES_CONFIG_PROPERTY_NAME));
+ if (projectionRulesProperty != null &&
!projectionRulesProperty.isEmpty()) {
+ String[] projectionRuleStrs =
stringFactory.create(projectionRulesProperty.getValuesAsArray());
+ if (projectionRuleStrs != null && projectionRuleStrs.length != 0) {
+ projectionRules = projectionParser.rulesFromStrings(env,
projectionRuleStrs);
+ }
+ }
+ if (problems.hasErrors()) return null;
+
+ Projection region = new Projection(sourceName, projectionRules);
+ return region;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized String getName() {
+ return sourceName;
+ }
+
+ /**
+ * Set the name of this source.
+ * <p>
+ * This is a required property.
+ * </p>
+ *
+ * @param sourceName the name of this repository source
+ * @see #setConfigurationSourceName(String)
+ * @see #setConnectionFactoriesJndiName(String)
+ * @see #setConfigurationSourceProjectionRules(String[])
+ * @see #setPassword(String)
+ * @see #setUsername(String)
+ * @see #setRepositoryName(String)
+ * @see #setExecutionContextFactoryJndiName(String)
+ * @see #setPassword(String)
+ * @see #setUsername(String)
+ * @see #setName(String)
+ */
+ public synchronized void setName( String sourceName ) {
+ if (this.sourceName == sourceName || this.sourceName != null &&
this.sourceName.equals(sourceName)) return;
+ this.sourceName = sourceName;
+ changeRepositoryConfig();
+ }
+
+ /**
+ * Get the name in JNDI of a {@link FederatedRepository} instance that should be
used. If this is set (and an instance can be
+ * found at that location), few of the remaining properties on this instance may not
be used (basically just
+ * {@link #getUsername() username}, {@link #getPassword() password}, and {@link
#getName() source name}).
+ * <p>
+ * This is an optional property.
+ * </p>
+ *
+ * @return the location in JNDI of the {@link FederatedRepository} that should be
used by this source, or null if the
+ * {@link FederatedRepository} instance will be created from the properties
of this instance
+ * @see #setRepositoryJndiName(String)
+ */
+ public String getRepositoryJndiName() {
+ return repositoryJndiName;
+ }
+
+ /**
+ * Set the name in JNDI of a {@link FederatedRepository} instance that should be
used. If this is set (and an instance can be
+ * found at that location), few of the remaining properties on this instance may not
be used (basically just
+ * {@link #getUsername() username}, {@link #getPassword() password}, and {@link
#getName() source name}).
+ * <p>
+ * This is an optional property.
+ * </p>
+ *
+ * @param jndiName the JNDI name where the {@link FederatedRepository} instance can
be found, or null if the instance is not
+ * to be found in JNDI but one should be instantiated from this instance's
properties
+ * @see #getRepositoryJndiName()
+ * @see #setPassword(String)
+ * @see #setUsername(String)
+ * @see #setName(String)
+ */
+ public void setRepositoryJndiName( String jndiName ) {
+ if (this.repositoryJndiName == jndiName || this.repositoryJndiName != null
&& this.repositoryJndiName.equals(jndiName)) return;
+ this.repositoryJndiName = jndiName;
+ changeRepositoryConfig();
+ }
+
+ /**
+ * Get the name in JNDI of a {@link RepositorySource} instance that should be used by
the {@link FederatedRepository federated
+ * repository} as the configuration repository.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @return the JNDI name of the {@link RepositorySource} instance that should be used
for the configuration, or null if the
+ * federated repository instance is to be found in JNDI
+ * @see #setConfigurationSourceName(String)
+ */
+ public String getConfigurationSourceName() {
+ return configurationSourceName;
+ }
+
+ /**
+ * Get the name of a {@link RepositorySource} instance that should be used by the
{@link FederatedRepository federated
+ * repository} as the configuration repository. The instance will be retrieved from
the {@link RepositoryConnectionFactories}
+ * instance {@link #getConnectionFactoriesJndiName() found in JDNI}.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @param sourceName the name of the {@link RepositorySource} instance that should be
used for the configuration, or null if
+ * the federated repository instance is to be found in JNDI
+ * @see #getConfigurationSourceName()
+ * @see #setConnectionFactoriesJndiName(String)
+ * @see #setConfigurationSourceProjectionRules(String[])
+ * @see #setPassword(String)
+ * @see #setUsername(String)
+ * @see #setRepositoryName(String)
+ * @see #setExecutionContextFactoryJndiName(String)
+ * @see #setName(String)
+ */
+ public void setConfigurationSourceName( String sourceName ) {
+ if (this.configurationSourceName == sourceName || this.configurationSourceName !=
null
+ && this.configurationSourceName.equals(sourceName)) return;
+ this.configurationSourceName = sourceName;
+ changeRepositoryConfig();
+ }
+
+ /**
+ * Get the projection rule definitions used for the {@link
#getConfigurationSourceName() configuration source}. The
+ * {@link #DEFAULT_CONFIGURATION_SOURCE_PROJECTION_RULES default projection rules}
map the root of the configuration source
+ * into the <code>/dna:system</code> branch of the repository.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @return the string array of projection rules, or null if the projection rules
haven't yet been set or if the federated
+ * repository instance is to be found in JNDI
+ * @see #setConfigurationSourceProjectionRules(String[])
+ */
+ public String[] getConfigurationSourceProjectionRules() {
+ return configurationSourceProjectionRules;
+ }
+
+ /**
+ * Get the projection rule definitions used for the {@link
#getConfigurationSourceName() configuration source}. The
+ * {@link #DEFAULT_CONFIGURATION_SOURCE_PROJECTION_RULES default projection rules}
map the root of the configuration source
+ * into the <code>/dna:system</code> branch of the repository.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @param projectionRules the string array of projection rules, or null if the
projection rules haven't yet been set or if the
+ * federated repository instance is to be found in JNDI
+ * @see #setConfigurationSourceProjectionRules(String[])
+ * @see #setConnectionFactoriesJndiName(String)
+ * @see #setConfigurationSourceName(String)
+ * @see #setPassword(String)
+ * @see #setUsername(String)
+ * @see #setRepositoryName(String)
+ * @see #setExecutionContextFactoryJndiName(String)
+ * @see #setName(String)
+ */
+ public void setConfigurationSourceProjectionRules( String[] projectionRules ) {
+ if (projectionRules != null) {
+ List<String> rules = new LinkedList<String>();
+ for (String rule : projectionRules) {
+ if (rule != null && rule.trim().length() != 0) rules.add(rule);
+ }
+ projectionRules = rules.toArray(new String[rules.size()]);
+ }
+ this.configurationSourceProjectionRules = projectionRules != null ?
projectionRules : DEFAULT_CONFIGURATION_SOURCE_PROJECTION_RULES;
+ }
+
+ /**
+ * Get the name in JNDI of a {@link ExecutionContextFactory} instance that should be
used to obtain the
+ * {@link ExecutionEnvironment execution context} used by the {@link
FederatedRepository federated repository}.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @return the JNDI name of the {@link ExecutionContextFactory} instance that should
be used, or null if the federated
+ * repository instance is to be found in JNDI
+ * @see #setExecutionContextFactoryJndiName(String)
+ */
+ public String getExecutionContextFactoryJndiName() {
+ return executionContextFactoryJndiName;
+ }
+
+ /**
+ * Set the name in JNDI of a {@link ExecutionContextFactory} instance that should be
used to obtain the
+ * {@link ExecutionEnvironment execution context} used by the {@link
FederatedRepository federated repository}.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @param jndiName the JNDI name where the {@link ExecutionContextFactory} instance
can be found, or null if the federated
+ * repository instance is to be found in JNDI
+ * @see #getExecutionContextFactoryJndiName()
+ * @see #setConfigurationSourceName(String)
+ * @see #setConfigurationSourceProjectionRules(String[])
+ * @see #setConnectionFactoriesJndiName(String)
+ * @see #setPassword(String)
+ * @see #setUsername(String)
+ * @see #setRepositoryName(String)
+ * @see #setName(String)
+ */
+ public synchronized void setExecutionContextFactoryJndiName( String jndiName ) {
+ if (this.repositoryJndiName == jndiName || this.repositoryJndiName != null
&& this.repositoryJndiName.equals(jndiName)) return;
+ this.executionContextFactoryJndiName = jndiName;
+ changeRepositoryConfig();
+ }
+
+ /**
+ * Get the name in JNDI where the {@link RepositoryConnectionFactories} instance that
can be used by the
+ * {@link FederatedRepository federated repository} can find any {@link
RepositorySource} sources it needs, including those
+ * used for {@link Projection sources} and that used for it's {@link
#getConfigurationSourceName() configuration}.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @return the JNDI name where the {@link RepositoryConnectionFactories} instance can
be found, or null if the federated
+ * repository instance is to be found in JNDI
+ * @see #setConnectionFactoriesJndiName(String)
+ */
+ public String getConnectionFactoriesJndiName() {
+ return connectionFactoriesJndiName;
+ }
+
+ /**
+ * Set the name in JNDI where the {@link RepositoryConnectionFactories} instance that
can be used by the
+ * {@link FederatedRepository federated repository} can find any {@link
RepositorySource} sources it needs, including those
+ * used for {@link Projection sources} and that used for it's {@link
#getConfigurationSourceName() configuration}.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @param jndiName the JNDI name where the {@link RepositoryConnectionFactories}
instance can be found, or null if the
+ * federated repository instance is to be found in JNDI
+ * @see #getConnectionFactoriesJndiName()
+ * @see #setConfigurationSourceName(String)
+ * @see #setConfigurationSourceProjectionRules(String[])
+ * @see #setPassword(String)
+ * @see #setUsername(String)
+ * @see #setRepositoryName(String)
+ * @see #setExecutionContextFactoryJndiName(String)
+ * @see #setName(String)
+ */
+ public synchronized void setConnectionFactoriesJndiName( String jndiName ) {
+ if (this.connectionFactoriesJndiName == jndiName ||
this.connectionFactoriesJndiName != null
+ && this.connectionFactoriesJndiName.equals(jndiName)) return;
+ this.connectionFactoriesJndiName = jndiName;
+ changeRepositoryConfig();
+ }
+
+ /**
+ * @return securityDomain
+ */
+ public String getSecurityDomain() {
+ return securityDomain;
+ }
+
+ /**
+ * @param securityDomain Sets securityDomain to the specified value.
+ */
+ public void setSecurityDomain( String securityDomain ) {
+ this.securityDomain = securityDomain;
+ }
+
+ /**
+ * Get the name of the federated repository.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @return the name of the repository
+ * @see #setRepositoryName(String)
+ */
+ public synchronized String getRepositoryName() {
+ return this.repositoryName;
+ }
+
+ /**
+ * Get the name of the federated repository.
+ * <p>
+ * This is a required property (unless the {@link #getRepositoryJndiName() federated
repository is to be found in JDNI}).
+ * </p>
+ *
+ * @param repositoryName the new name of the repository
+ * @throws IllegalArgumentException if the repository name is null, empty or blank
+ * @see #getRepositoryName()
+ * @see #setConfigurationSourceName(String)
+ * @see #setConfigurationSourceProjectionRules(String[])
+ * @see #setPassword(String)
+ * @see #setUsername(String)
+ * @see #setConnectionFactoriesJndiName(String)
+ * @see #setExecutionContextFactoryJndiName(String)
+ * @see #setName(String)
+ */
+ public synchronized void setRepositoryName( String repositoryName ) {
+ ArgCheck.isNotEmpty(repositoryName, "repositoryName");
+ if (this.repositoryName != null &&
this.repositoryName.equals(repositoryName)) return;
+ this.repositoryName = repositoryName;
+ changeRepositoryConfig();
+ }
+
+ /**
+ * This method is called to signal that some aspect of the configuration has changed.
If a {@link #getRepository() repository}
+ * instance has been created, it's configuration is
+ * {@link #getRepositoryConfiguration(ExecutionEnvironment,
RepositoryConnectionFactories) rebuilt} and updated. Nothing is
+ * done, however, if there is currently no {@link #getRepository() repository}.
+ */
+ protected synchronized void changeRepositoryConfig() {
+ if (this.repository != null) {
+ // Find in JNDI the repository connection factories and the environment ...
+ ExecutionEnvironment env = getExecutionEnvironment();
+ RepositoryConnectionFactories factories =
getRepositoryConnectionFactories();
+ // Compute a new repository config and set it on the repository ...
+ FederatedRepositoryConfig newConfig = getRepositoryConfiguration(env,
factories);
+ this.repository.setConfiguration(newConfig);
+ }
+ }
+
+ /**
+ * Get the username that should be used when authenticating and {@link
#getConnection() creating connections}.
+ * <p>
+ * This is an optional property, required only when authentication is to be used.
+ * </p>
+ *
+ * @return the username, or null if no username has been set or are not to be used
+ * @see #setUsername(String)
+ */
+ public String getUsername() {
+ return this.username;
+ }
+
+ /**
+ * Set the username that should be used when authenticating and {@link
#getConnection() creating connections}.
+ * <p>
+ * This is an optional property, required only when authentication is to be used.
+ * </p>
+ *
+ * @param username the username, or null if no username has been set or are not to be
used
+ * @see #getUsername()
+ * @see #setPassword(String)
+ * @see #setConfigurationSourceName(String)
+ * @see #setConfigurationSourceProjectionRules(String[])
+ * @see #setPassword(String)
+ * @see #setRepositoryName(String)
+ * @see #setConnectionFactoriesJndiName(String)
+ * @see #setExecutionContextFactoryJndiName(String)
+ * @see #setName(String)
+ */
+ public void setUsername( String username ) {
+ this.username = username;
+ }
+
+ /**
+ * Get the password that should be used when authenticating and {@link
#getConnection() creating connections}.
+ * <p>
+ * This is an optional property, required only when authentication is to be used.
+ * </p>
+ *
+ * @return the password, or null if no password have been set or are not to be used
+ * @see #setPassword(String)
+ */
+ public String getPassword() {
+ return this.password;
+ }
+
+ /**
+ * Get the password that should be used when authenticating and {@link
#getConnection() creating connections}.
+ * <p>
+ * This is an optional property, required only when authentication is to be used.
+ * </p>
+ *
+ * @param password the password, or null if no password have been set or are not to
be used
+ * @see #getPassword()
+ * @see #setConfigurationSourceName(String)
+ * @see #setConfigurationSourceProjectionRules(String[])
+ * @see #setUsername(String)
+ * @see #setRepositoryName(String)
+ * @see #setConnectionFactoriesJndiName(String)
+ * @see #setExecutionContextFactoryJndiName(String)
+ * @see #setName(String)
+ */
+ public void setPassword( String password ) {
+ this.password = password;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized Reference getReference() {
+ String className = getClass().getName();
+ String factoryClassName = NamingContextObjectFactory.class.getName();
+ Reference ref = new Reference(className, factoryClassName, null);
+
+ if (getRepositoryName() != null) {
+ ref.add(new StringRefAddr(REPOSITORY_NAME, getRepositoryName()));
+ }
+ if (getName() != null) {
+ ref.add(new StringRefAddr(SOURCE_NAME, getName()));
+ }
+ if (getUsername() != null) {
+ ref.add(new StringRefAddr(USERNAME, getUsername()));
+ }
+ if (getPassword() != null) {
+ ref.add(new StringRefAddr(PASSWORD, getPassword()));
+ }
+ if (getConfigurationSourceName() != null) {
+ ref.add(new StringRefAddr(CONFIGURATION_SOURCE_NAME,
getConfigurationSourceName()));
+ }
+ if (getConfigurationSourceProjectionRules() != null) {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (String rule : getConfigurationSourceProjectionRules()) {
+ if (!first) {
+ sb.append("\n");
+ first = false;
+ }
+ sb.append(rule);
+ }
+ ref.add(new StringRefAddr(CONFIGURATION_SOURCE_PROJECTION_RULES,
sb.toString()));
+ }
+ if (getConnectionFactoriesJndiName() != null) {
+ ref.add(new StringRefAddr(CONNECTION_FACTORIES_JNDI_NAME,
getConnectionFactoriesJndiName()));
+ }
+ if (getExecutionContextFactoryJndiName() != null) {
+ ref.add(new StringRefAddr(EXECUTION_CONTEXT_FACTORY_JNDI_NAME,
getExecutionContextFactoryJndiName()));
+ }
+ if (getSecurityDomain() != null) {
+ ref.add(new StringRefAddr(SECURITY_DOMAIN, getSecurityDomain()));
+ }
+ if (getRepositoryJndiName() != null) {
+ ref.add(new StringRefAddr(REPOSITORY_JNDI_NAME, getRepositoryJndiName()));
+ }
+ ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
+ return ref;
+ }
+
+ public static class NamingContextObjectFactory implements ObjectFactory {
+
+ public NamingContextObjectFactory() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getObjectInstance( Object obj,
+ javax.naming.Name name,
+ Context nameCtx,
+ Hashtable<?, ?> environment ) throws
Exception {
+ if (obj instanceof Reference) {
+ Map<String, String> values = new HashMap<String, String>();
+ Reference ref = (Reference)obj;
+ Enumeration<?> en = ref.getAll();
+ while (en.hasMoreElements()) {
+ RefAddr subref = (RefAddr)en.nextElement();
+ if (subref instanceof StringRefAddr) {
+ String key = subref.getType();
+ Object value = subref.getContent();
+ if (value != null) values.put(key, value.toString());
+ }
+ }
+ String repositoryName =
values.get(FederatedRepositorySource.REPOSITORY_NAME);
+ String sourceName = values.get(FederatedRepositorySource.SOURCE_NAME);
+ String username = values.get(FederatedRepositorySource.USERNAME);
+ String password = values.get(FederatedRepositorySource.PASSWORD);
+ String configurationSourceName =
values.get(FederatedRepositorySource.CONFIGURATION_SOURCE_NAME);
+ String projectionRules =
values.get(FederatedRepositorySource.CONFIGURATION_SOURCE_PROJECTION_RULES);
+ String connectionFactoriesJndiName =
values.get(FederatedRepositorySource.CONNECTION_FACTORIES_JNDI_NAME);
+ String environmentJndiName =
values.get(FederatedRepositorySource.EXECUTION_CONTEXT_FACTORY_JNDI_NAME);
+ String repositoryJndiName =
values.get(FederatedRepositorySource.REPOSITORY_JNDI_NAME);
+ String securityDomain =
values.get(FederatedRepositorySource.SECURITY_DOMAIN);
+ String retryLimit = values.get(FederatedRepositorySource.RETRY_LIMIT);
+
+ // Create the source instance ...
+ FederatedRepositorySource source = new FederatedRepositorySource();
+ if (repositoryName != null) source.setRepositoryName(repositoryName);
+ if (sourceName != null) source.setName(sourceName);
+ if (username != null) source.setUsername(username);
+ if (password != null) source.setPassword(password);
+ if (configurationSourceName != null)
source.setConfigurationSourceName(configurationSourceName);
+ if (projectionRules != null) {
+ List<String> rules = StringUtil.splitLines(projectionRules);
+ source.setConfigurationSourceProjectionRules(rules.toArray(new
String[rules.size()]));
+ }
+ if (connectionFactoriesJndiName != null)
source.setConnectionFactoriesJndiName(connectionFactoriesJndiName);
+ if (environmentJndiName != null)
source.setExecutionContextFactoryJndiName(environmentJndiName);
+ if (repositoryJndiName != null)
source.setRepositoryJndiName(repositoryJndiName);
+ if (securityDomain != null) source.setSecurityDomain(securityDomain);
+ if (retryLimit != null)
source.setRetryLimit(Integer.parseInt(retryLimit));
+ return source;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return repositoryName.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof FederatedRepositorySource) {
+ FederatedRepositorySource that = (FederatedRepositorySource)obj;
+ // The repository name, source name, and federation service must all match
+ if (!this.getRepositoryName().equals(that.getRepositoryName())) return
false;
+ if (this.getName() == null) {
+ if (that.getName() != null) return false;
+ } else {
+ if (!this.getName().equals(that.getName())) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationException.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationException.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationException.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation;
+
+
+/**
+ *
+ * @author Randall Hauch
+ */
+public class FederationException extends RuntimeException {
+
+ /**
+ */
+ private static final long serialVersionUID = -27536888064529864L;
+
+ /**
+ *
+ */
+ public FederationException() {
+ }
+
+ /**
+ * @param message
+ */
+ public FederationException( String message ) {
+ super(message);
+
+ }
+
+ /**
+ * @param cause
+ */
+ public FederationException( Throwable cause ) {
+ super(cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public FederationException( String message, Throwable cause ) {
+ super(message, cause);
+
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,70 @@
+/*
+ * 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.connector.federation;
+
+import java.util.Locale;
+import java.util.Set;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author Randall Hauch
+ */
+public final class FederationI18n {
+
+ public static I18n requiredNodeDoesNotExistRelativeToNode;
+ public static I18n propertyIsRequired;
+
+ public static I18n interruptedWhileUsingFederationConfigurationRepository;
+ public static I18n unableToFindFederatedRepositoryInJndi;
+ public static I18n unableToFindExecutionContextFactoryInJndi;
+ public static I18n unableToCreateExecutionContext;
+ public static I18n unableToFindRepositoryConnectionFactoriesInJndi;
+ public static I18n noRepositoryConnectionFactories;
+ public static I18n federatedRepositoryCannotBeFound;
+ public static I18n unableToFindRepositorySourceByName;
+ public static I18n unableToCreateConnectionToFederatedRepository;
+ public static I18n unableToAuthenticateConnectionToFederatedRepository;
+ public static I18n repositoryHasBeenShutDown;
+ public static I18n repositoryPathInFederationBindingIsNotAbsolute;
+ public static I18n errorReadingMergePlan;
+ public static I18n errorAddingProjectionRuleParseMethod;
+
+ static {
+ try {
+ I18n.initialize(FederationI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(FederationI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(FederationI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(FederationI18n.class, locale);
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/Projection.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/Projection.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/Projection.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,734 @@
+/*
+ * 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.connector.federation;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.spi.graph.NamespaceRegistry;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * A projection of content from a source into the integrated/federated repository. Each
project consists of a set of {@link Rule
+ * rules} for a particular source, where each rule defines how content within a source
is
+ * {@link Rule#getPathInRepository(Path, PathFactory) is project into the repository} and
how the repository content is
+ * {@link Rule#getPathInSource(Path, PathFactory) projected into the source}. Different
rule subclasses are used for different
+ * types.
+ *
+ * @author Randall Hauch
+ */
+@Immutable
+public class Projection implements Comparable<Projection>, Serializable {
+
+ /**
+ * Initial version
+ */
+ private static final long serialVersionUID = 1L;
+ protected static final List<Method> parserMethods;
+ static {
+ parserMethods = new CopyOnWriteArrayList<Method>();
+ try {
+
parserMethods.add(Projection.class.getDeclaredMethod("parsePathRule",
String.class, ExecutionEnvironment.class));
+ } catch (Throwable err) {
+ Logger.getLogger(Projection.class).error(err,
FederationI18n.errorAddingProjectionRuleParseMethod);
+ }
+ }
+
+ /**
+ * Add a static method that can be used to parse {@link
Rule#getString(NamespaceRegistry, TextEncoder) rule definition
+ * strings}. These methods must be static, must accept a {@link String} definition as
the first parameter and an
+ * {@link ExecutionEnvironment} environment reference as the second parameter, and
should return the resulting {@link Rule}
+ * (or null if the definition format could not be understood by the method. Any
exceptions during
+ * {@link Method#invoke(Object, Object...) invocation} will be logged at the
+ * {@link Logger#trace(Throwable, String, Object...) trace} level.
+ *
+ * @param method the method to be added
+ * @see #addRuleParser(ClassLoader, String, String)
+ */
+ public static void addRuleParser( Method method ) {
+ if (method != null) parserMethods.add(method);
+ }
+
+ /**
+ * Add a static method that can be used to parse {@link
Rule#getString(NamespaceRegistry, TextEncoder) rule definition
+ * strings}. These methods must be static, must accept a {@link String} definition as
the first parameter and an
+ * {@link ExecutionEnvironment} environment reference as the second parameter, and
should return the resulting {@link Rule}
+ * (or null if the definition format could not be understood by the method. Any
exceptions during
+ * {@link Method#invoke(Object, Object...) invocation} will be logged at the
+ * {@link Logger#trace(Throwable, String, Object...) trace} level.
+ *
+ * @param classLoader the class loader that should be used to load the class on which
the method is defined; may not be null
+ * @param className the name of the class on which the static method is defined; may
not be null
+ * @param methodName the name of the method
+ * @throws SecurityException if there is a security exception while loading the class
or getting the method
+ * @throws NoSuchMethodException if the method does not exist on the class
+ * @throws ClassNotFoundException if the class could not be found given the supplied
class loader
+ * @throws IllegalArgumentException if the class loader reference is null, or if the
class name or method name are null or
+ * empty
+ * @see #addRuleParser(Method)
+ */
+ public static void addRuleParser( ClassLoader classLoader,
+ String className,
+ String methodName ) throws SecurityException,
NoSuchMethodException, ClassNotFoundException {
+ ArgCheck.isNotNull(classLoader, "classLoader");
+ ArgCheck.isNotEmpty(className, "className");
+ ArgCheck.isNotEmpty(methodName, "methodName");
+ Class<?> clazz = Class.forName(className, true, classLoader);
+ parserMethods.add(clazz.getMethod(className, String.class,
ExecutionEnvironment.class));
+ }
+
+ /**
+ * Remove the rule parser method.
+ *
+ * @param method the method to remove
+ * @return true if the method was removed, or false if the method was not a
registered rule parser method
+ */
+ public static boolean removeRuleParser( Method method ) {
+ return parserMethods.remove(method);
+ }
+
+ /**
+ * Remove the rule parser method.
+ *
+ * @param declaringClassName the name of the class on which the static method is
defined; may not be null
+ * @param methodName the name of the method
+ * @return true if the method was removed, or false if the method was not a
registered rule parser method
+ * @throws IllegalArgumentException if the class loader reference is null, or if the
class name or method name are null or
+ * empty
+ */
+ public static boolean removeRuleParser( String declaringClassName,
+ String methodName ) {
+ ArgCheck.isNotEmpty(declaringClassName, "declaringClassName");
+ ArgCheck.isNotEmpty(methodName, "methodName");
+ for (Method method : parserMethods) {
+ if (method.getName().equals(methodName) &&
method.getDeclaringClass().getName().equals(declaringClassName)) {
+ return parserMethods.remove(method);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Parse the string form of a rule definition and return the rule
+ *
+ * @param definition the definition of the rule that is to be parsed
+ * @param env the environment in which this method is being executed; may not be
null
+ * @return the rule, or null if the definition could not be parsed
+ */
+ public static Rule fromString( String definition,
+ ExecutionEnvironment env ) {
+ ArgCheck.isNotNull(env, "env");
+ definition = definition != null ? definition.trim() : "";
+ if (definition.length() == 0) return null;
+ for (Method method : parserMethods) {
+ try {
+ Rule rule = (Rule)method.invoke(null, definition, env);
+ if (rule != null) return rule;
+ } catch (Throwable err) {
+ String msg = "Error while parsing project rule definition
\"{0}\" using {1}";
+ Logger.getLogger(Projection.class).trace(err, msg, definition, method);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Pattern that identifies the form:
+ *
+ * <pre>
+ * repository_path [=> source_path [$ exception ]*]?
+ * </pre>
+ *
+ * where the following groups are captured on the first call to {@link
Matcher#find()}:
+ * <ol>
+ * <li><code>repository_path</code></li>
+ * <li><code>source_path</code></li>
+ * </ol>
+ * and the following groups are captured on subsequent calls to {@link
Matcher#find()}:
+ * <ol>
+ * <li>exception</code></li>
+ * </ol>
+ * <p>
+ * The regular expression is:
+ *
+ * <pre>
+ *
((?:[ˆ=$]|=(?!>))+)(?:(?:=>((?:[ˆ=$]|=(?!>))+))( \$
(?:(?:[ˆ=]|=(?!>))+))*)?
+ * </pre>
+ *
+ * </p>
+ */
+ protected static final String PATH_RULE_PATTERN_STRING =
"((?:[^=$]|=(?!>))+)(?:(?:=>((?:[^=$]|=(?!>))+))( \\$
(?:(?:[^=]|=(?!>))+))*)?";
+ protected static final Pattern PATH_RULE_PATTERN =
Pattern.compile(PATH_RULE_PATTERN_STRING);
+
+ /**
+ * Parse the string definition of a {@link PathRule}. This method is automatically
registered in the {@link #parserMethods
+ * parser methods} by the static initializer of {@link Projection}.
+ *
+ * @param definition the definition
+ * @param env the environment
+ * @return the path rule, or null if the definition is not in the right form
+ */
+ public static PathRule parsePathRule( String definition,
+ ExecutionEnvironment env ) {
+ definition = definition != null ? definition.trim() : "";
+ if (definition.length() == 0) return null;
+ Matcher matcher = PATH_RULE_PATTERN.matcher(definition);
+ if (!matcher.find()) return null;
+ String reposPathStr = matcher.group(1);
+ String sourcePathStr = matcher.group(2);
+ PathFactory pathFactory = env.getValueFactories().getPathFactory();
+ Path repositoryPath = pathFactory.create(reposPathStr);
+ Path sourcePath = pathFactory.create(sourcePathStr);
+
+ // Grab the exceptions ...
+ List<Path> exceptions = new LinkedList<Path>();
+ while (matcher.find()) {
+ String exceptionStr = matcher.group(1);
+ Path exception = pathFactory.create(exceptionStr);
+ exceptions.add(exception);
+ }
+ return new PathRule(repositoryPath, sourcePath, exceptions);
+ }
+
+ private final String sourceName;
+ private final List<Rule> rules;
+
+ /**
+ * Create a new federated projection for the supplied source, using the supplied
rules.
+ *
+ * @param sourceName the name of the source
+ * @param rules the projection rules
+ * @throws IllegalArgumentException if the source name or rule array is null, empty,
or contains all nulls
+ */
+ public Projection( String sourceName,
+ Rule... rules ) {
+ ArgCheck.isNotEmpty(sourceName, "sourceName");
+ ArgCheck.isNotEmpty(rules, "rules");
+ this.sourceName = sourceName;
+ List<Rule> rulesList = new ArrayList<Rule>();
+ for (Rule rule : rules) {
+ if (rule != null) rulesList.add(rule);
+ }
+ this.rules = Collections.unmodifiableList(rulesList);
+ ArgCheck.isNotEmpty(this.rules, "rules");
+ }
+
+ /**
+ * Get the name of the source to which this projection applies.
+ *
+ * @return the source name
+ * @see RepositorySource#getName()
+ */
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ /**
+ * Get the rules that define this projection.
+ *
+ * @return the unmodifiable list of immutable rules; never null
+ */
+ public List<Rule> getRules() {
+ return rules;
+ }
+
+ /**
+ * Get the paths in the source that correspond to the supplied path within the
repository. This method computes the paths
+ * given all of the rules. In general, most sources will probably project a node onto
a single repository node. However, some
+ * sources may be configured such that the same node in the repository is a
projection of multiple nodes within the source.
+ *
+ * @param canonicalPathInRepository the canonical path of the node within the
repository; may not be null
+ * @param factory the path factory; may not be null
+ * @return the set of unique paths in the source projected from the repository path;
never null
+ * @throws IllegalArgumentException if the factory reference is null
+ */
+ public Set<Path> getPathsInSource( Path canonicalPathInRepository,
+ PathFactory factory ) {
+ ArgCheck.isNotNull(factory, "factory");
+ assert canonicalPathInRepository == null ? true :
canonicalPathInRepository.equals(canonicalPathInRepository.getCanonicalPath());
+ Set<Path> paths = new HashSet<Path>();
+ for (Rule rule : getRules()) {
+ Path pathInSource = rule.getPathInSource(canonicalPathInRepository,
factory);
+ if (pathInSource != null) paths.add(pathInSource);
+ }
+ return paths;
+ }
+
+ /**
+ * Get the paths in the repository that correspond to the supplied path within the
source. This method computes the paths
+ * given all of the rules. In general, most sources will probably project a node onto
a single repository node. However, some
+ * sources may be configured such that the same node in the source is projected into
multiple nodes within the repository.
+ *
+ * @param canonicalPathInSource the canonical path of the node within the source; may
not be null
+ * @param factory the path factory; may not be null
+ * @return the set of unique paths in the repository projected from the source path;
never null
+ * @throws IllegalArgumentException if the factory reference is null
+ */
+ public Set<Path> getPathsInRepository( Path canonicalPathInSource,
+ PathFactory factory ) {
+ ArgCheck.isNotNull(factory, "factory");
+ assert canonicalPathInSource == null ? true :
canonicalPathInSource.equals(canonicalPathInSource.getCanonicalPath());
+ Set<Path> paths = new HashSet<Path>();
+ for (Rule rule : getRules()) {
+ Path pathInRepository = rule.getPathInRepository(canonicalPathInSource,
factory);
+ if (pathInRepository != null) paths.add(pathInRepository);
+ }
+ return paths;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return this.sourceName.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof Projection) {
+ Projection that = (Projection)obj;
+ if (!this.getSourceName().equals(that.getSourceName())) return false;
+ if (!this.getRules().equals(that.getRules())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo( Projection that ) {
+ if (this == that) return 0;
+ int diff = this.getSourceName().compareTo(that.getSourceName());
+ if (diff != 0) return diff;
+ Iterator<Rule> thisIter = this.getRules().iterator();
+ Iterator<Rule> thatIter = that.getRules().iterator();
+ while (thisIter.hasNext() && thatIter.hasNext()) {
+ diff = thisIter.next().compareTo(thatIter.next());
+ if (diff != 0) return diff;
+ }
+ if (thisIter.hasNext()) return 1;
+ if (thatIter.hasNext()) return -1;
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.sourceName);
+ sb.append(" { ");
+ boolean first = true;
+ for (Rule rule : this.getRules()) {
+ if (!first) sb.append(" ; ");
+ sb.append(rule.toString());
+ first = false;
+ }
+ sb.append(" }");
+ return super.toString();
+ }
+
+ /**
+ * A rule used within a project do define how content within a source is project into
the federated repository. This mapping
+ * is bi-directional, meaning it's possible to determine
+ * <ul>
+ * <li>the path in repository given a path in source; and</li>
+ * <li>the path in source given a path in repository.</li>
+ * </ul>
+ *
+ * @author Randall Hauch
+ */
+ @Immutable
+ public static abstract class Rule implements Comparable<Rule> {
+ /**
+ * Get the path in source that is projected from the supplied repository path, or
null if the supplied repository path is
+ * not projected into the source.
+ *
+ * @param pathInRepository the path in the repository; may not be null
+ * @param factory the path factory; may not be null
+ * @return the path in source if it is projected by this rule, or null otherwise
+ */
+ public abstract Path getPathInSource( Path pathInRepository,
+ PathFactory factory );
+
+ /**
+ * Get the path in repository that is projected from the supplied source path, or
null if the supplied source path is not
+ * projected into the repository.
+ *
+ * @param pathInSource the path in the source; may not be null
+ * @param factory the path factory; may not be null
+ * @return the path in repository if it is projected by this rule, or null
otherwise
+ */
+ public abstract Path getPathInRepository( Path pathInSource,
+ PathFactory factory );
+
+ public abstract String getString( NamespaceRegistry registry,
+ TextEncoder encoder );
+
+ public abstract String getString( TextEncoder encoder );
+
+ public abstract String getString();
+ }
+
+ /**
+ * A rule that is defined with a single {@link #getPathInSource() path in source} and
a single {@link #getPathInRepository()
+ * path in repository}, and which has a set of {@link #getExceptionsToRule() path
exceptions} (relative paths below the path
+ * in source).
+ *
+ * @author Randall Hauch
+ */
+ @Immutable
+ public static class PathRule extends Rule {
+ /** The path of the content as known to the source */
+ private final Path sourcePath;
+ /** The path where the content is to be placed ("projected") into the
repository */
+ private final Path repositoryPath;
+ /** The paths (relative to the source path) that identify exceptions to this rule
*/
+ private final List<Path> exceptions;
+ private final int hc;
+
+ public PathRule( Path repositoryPath,
+ Path sourcePath ) {
+ this(repositoryPath, sourcePath, (Path[])null);
+ }
+
+ public PathRule( Path repositoryPath,
+ Path sourcePath,
+ Path... exceptions ) {
+ assert sourcePath != null;
+ assert repositoryPath != null;
+ this.sourcePath = sourcePath;
+ this.repositoryPath = repositoryPath;
+ if (exceptions == null || exceptions.length == 0) {
+ this.exceptions = Collections.emptyList();
+ } else {
+ List<Path> exceptionList = new ArrayList<Path>();
+ for (Path exception : exceptions) {
+ if (exception != null) exceptionList.add(exception);
+ }
+ this.exceptions = Collections.unmodifiableList(exceptionList);
+ }
+ this.hc = HashCode.compute(sourcePath, repositoryPath, exceptions);
+ assert exceptionPathsAreRelative();
+ }
+
+ public PathRule( Path repositoryPath,
+ Path sourcePath,
+ List<Path> exceptions ) {
+ assert sourcePath != null;
+ assert repositoryPath != null;
+ this.sourcePath = sourcePath;
+ this.repositoryPath = repositoryPath;
+ if (exceptions == null || exceptions.isEmpty()) {
+ this.exceptions = Collections.emptyList();
+ } else {
+ this.exceptions = Collections.unmodifiableList(new
ArrayList<Path>(exceptions));
+ }
+ this.hc = HashCode.compute(sourcePath, repositoryPath, exceptions);
+ assert exceptionPathsAreRelative();
+ }
+
+ private boolean exceptionPathsAreRelative() {
+ if (this.exceptions != null) {
+ for (Path path : this.exceptions) {
+ if (path.isAbsolute()) return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The path where the content is to be placed ("projected") into the
repository.
+ *
+ * @return the projected path of the content in the repository; never null
+ */
+ public Path getPathInRepository() {
+ return repositoryPath;
+ }
+
+ /**
+ * The path of the content as known to the source
+ *
+ * @return the source-specific path of the content; never null
+ */
+ public Path getPathInSource() {
+ return sourcePath;
+ }
+
+ /**
+ * Get whether this rule has any exceptions.
+ *
+ * @return true if this rule has exceptions, or false if it has none.
+ */
+ public boolean hasExceptionsToRule() {
+ return exceptions.size() != 0;
+ }
+
+ /**
+ * Get the paths that define the exceptions to this rule. These paths are always
relative to the
+ * {@link #getPathInSource() path in source}.
+ *
+ * @return the unmodifiable exception paths; never null but possibly empty
+ */
+ public List<Path> getExceptionsToRule() {
+ return exceptions;
+ }
+
+ /**
+ * @param pathInSource
+ * @return true if the source path is included by this rule
+ */
+ protected boolean includes( Path pathInSource ) {
+ // Check whether the path is outside the source-specific path ...
+ if (this.sourcePath.isAtOrAbove(pathInSource)) {
+
+ // The path is inside the source-specific region, so check the exceptions
...
+ List<Path> exceptions = getExceptionsToRule();
+ if (exceptions.size() != 0) {
+ Path subpathInSource = pathInSource.relativeTo(this.sourcePath);
+ if (subpathInSource.size() != 0) {
+ for (Path exception : exceptions) {
+ if (subpathInSource.isAtOrBelow(exception)) return false;
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This method considers a path that is at or below the rule's {@link
#getPathInSource() source path} to be included,
+ * except if there are {@link #getExceptionsToRule() exceptions} that explicitly
disallow the path.
+ * </p>
+ *
+ * @see org.jboss.dna.connector.federation.Projection.Rule#getPathInSource(Path,
PathFactory)
+ */
+ @Override
+ public Path getPathInSource( Path pathInRepository,
+ PathFactory factory ) {
+ assert pathInRepository.equals(pathInRepository.getCanonicalPath());
+ // Project the repository path into the equivalent source path ...
+ Path pathInSource = projectPathInRepositoryToPathInSource(pathInRepository,
factory);
+
+ // Check whether the source path is included by this rule ...
+ return includes(pathInSource) ? pathInSource : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.Projection.Rule#getPathInRepository(org.jboss.dna.spi.graph.Path,
+ * org.jboss.dna.spi.graph.PathFactory)
+ */
+ @Override
+ public Path getPathInRepository( Path pathInSource,
+ PathFactory factory ) {
+ assert pathInSource.equals(pathInSource.getCanonicalPath());
+ // Check whether the source path is included by this rule ...
+ if (!includes(pathInSource)) return null;
+
+ // Project the repository path into the equivalent source path ...
+ return projectPathInSourceToPathInRepository(pathInSource, factory);
+ }
+
+ /**
+ * Convert a path defined in the source system into an equivalent path in the
repository system.
+ *
+ * @param pathInSource the path in the source system, which may include the
{@link #getPathInSource()}
+ * @param factory the path factory; may not be null
+ * @return the path in the repository system, which will be normalized and
absolute (including the
+ * {@link #getPathInRepository()}), or null if the path is not at or
under the {@link #getPathInSource()}
+ */
+ protected Path projectPathInSourceToPathInRepository( Path pathInSource,
+ PathFactory factory ) {
+ if (!this.sourcePath.isAtOrAbove(pathInSource)) return null;
+ // Remove the leading source path ...
+ Path relativeSourcePath = pathInSource.relativeTo(this.sourcePath);
+ // Prepend the region's root path ...
+ Path result = factory.create(this.repositoryPath, relativeSourcePath);
+ return result.getNormalizedPath();
+ }
+
+ /**
+ * Convert a path defined in the repository system into an equivalent path in the
source system.
+ *
+ * @param pathInRepository the path in the repository system, which may include
the {@link #getPathInRepository()}
+ * @param factory the path factory; may not be null
+ * @return the path in the source system, which will be normalized and absolute
(including the {@link #getPathInSource()}
+ * ), or null if the path is not at or under the {@link
#getPathInRepository()}
+ */
+ protected Path projectPathInRepositoryToPathInSource( Path pathInRepository,
+ PathFactory factory ) {
+ if (!this.repositoryPath.isAtOrAbove(pathInRepository)) return null;
+ // Find the relative path from the root of this region ...
+ Path pathInRegion = pathInRepository.relativeTo(this.repositoryPath);
+ // Prepend the path in source ...
+ Path result = factory.create(this.sourcePath, pathInRegion);
+ return result.getNormalizedPath();
+ }
+
+ @Override
+ public String getString( NamespaceRegistry registry,
+ TextEncoder encoder ) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getPathInRepository().getString(registry, encoder));
+ sb.append(" => ");
+ sb.append(this.getPathInSource().getString(registry, encoder));
+ if (this.getExceptionsToRule().size() != 0) {
+ for (Path exception : this.getExceptionsToRule()) {
+ sb.append(" $ ");
+ sb.append(exception.getString(registry, encoder));
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.Projection.Rule#getString(org.jboss.dna.common.text.TextEncoder)
+ */
+ @Override
+ public String getString( TextEncoder encoder ) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getPathInRepository().getString(encoder));
+ sb.append(" => ");
+ sb.append(this.getPathInSource().getString(encoder));
+ if (this.getExceptionsToRule().size() != 0) {
+ for (Path exception : this.getExceptionsToRule()) {
+ sb.append(" $ ");
+ sb.append(exception.getString(encoder));
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.connector.federation.Projection.Rule#getString()
+ */
+ @Override
+ public String getString() {
+ return getString(Path.JSR283_ENCODER);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PathRule) {
+ PathRule that = (PathRule)obj;
+ if (!this.getPathInRepository().equals(that.getPathInRepository()))
return false;
+ if (!this.getPathInSource().equals(that.getPathInSource())) return
false;
+ if (!this.getExceptionsToRule().equals(that.getExceptionsToRule()))
return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo( Rule other ) {
+ if (other == this) return 0;
+ if (other instanceof PathRule) {
+ PathRule that = (PathRule)other;
+ int diff =
this.getPathInRepository().compareTo(that.getPathInRepository());
+ if (diff != 0) return diff;
+ diff = this.getPathInSource().compareTo(that.getPathInSource());
+ if (diff != 0) return diff;
+ Iterator<Path> thisIter = this.getExceptionsToRule().iterator();
+ Iterator<Path> thatIter = that.getExceptionsToRule().iterator();
+ while (thisIter.hasNext() && thatIter.hasNext()) {
+ diff = thisIter.next().compareTo(thatIter.next());
+ if (diff != 0) return diff;
+ }
+ if (thisIter.hasNext()) return 1;
+ if (thatIter.hasNext()) return -1;
+ return 0;
+ }
+ return other.getClass().getName().compareTo(this.getClass().getName());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return getString();
+ }
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/ProjectionParser.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/ProjectionParser.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/ProjectionParser.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,243 @@
+/*
+ * 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.connector.federation;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.connector.federation.Projection.Rule;
+import org.jboss.dna.spi.graph.NamespaceRegistry;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+
+/**
+ * A parser library for {@link Projection projections} and {@link Projection.Rule
projection rules}.
+ *
+ * @author Randall Hauch
+ */
+public class ProjectionParser {
+ private static final ProjectionParser INSTANCE;
+
+ static {
+ INSTANCE = new ProjectionParser();
+ try {
+ INSTANCE.addRuleParser(Projection.class, "parsePathRule");
+ assert INSTANCE.parserMethods.size() == 1;
+ } catch (Throwable err) {
+ Logger.getLogger(Projection.class).error(err,
FederationI18n.errorAddingProjectionRuleParseMethod);
+ }
+ }
+
+ /**
+ * Get the shared projection parser, which is by default populated with the standard
parser rules.
+ *
+ * @return the parser; never null
+ */
+ public static ProjectionParser getInstance() {
+ return INSTANCE;
+ }
+
+ private final List<Method> parserMethods = new
CopyOnWriteArrayList<Method>();
+ protected final Logger logger;
+
+ public ProjectionParser() {
+ this.logger = Logger.getLogger(this.getClass());
+ }
+
+ /**
+ * Add a static method that can be used to parse {@link
Rule#getString(NamespaceRegistry, TextEncoder) rule definition
+ * strings}. These methods must be static, must accept a {@link String} definition as
the first parameter and an
+ * {@link ExecutionEnvironment} environment reference as the second parameter, and
should return the resulting {@link Rule}
+ * (or null if the definition format could not be understood by the method. Any
exceptions during
+ * {@link Method#invoke(Object, Object...) invocation} will be logged at the
+ * {@link Logger#trace(Throwable, String, Object...) trace} level.
+ *
+ * @param method the method to be added
+ * @see #addRuleParser(ClassLoader, String, String)
+ */
+ public void addRuleParser( Method method ) {
+ if (method != null) parserMethods.add(method);
+ }
+
+ /**
+ * Add a static method that can be used to parse {@link
Rule#getString(NamespaceRegistry, TextEncoder) rule definition
+ * strings}. These methods must be static, must accept a {@link String} definition as
the first parameter and an
+ * {@link ExecutionEnvironment} environment reference as the second parameter, and
should return the resulting {@link Rule}
+ * (or null if the definition format could not be understood by the method. Any
exceptions during
+ * {@link Method#invoke(Object, Object...) invocation} will be logged at the
+ * {@link Logger#trace(Throwable, String, Object...) trace} level.
+ *
+ * @param clazz the class on which the static method is defined; may not be null
+ * @param methodName the name of the method
+ * @throws SecurityException if there is a security exception while loading the class
or getting the method
+ * @throws NoSuchMethodException if the method does not exist on the class
+ * @throws IllegalArgumentException if the class loader reference is null, or if the
class name or method name are null or
+ * empty
+ * @see #addRuleParser(Method)
+ */
+ public void addRuleParser( Class<?> clazz,
+ String methodName ) throws SecurityException,
NoSuchMethodException {
+ ArgCheck.isNotNull(clazz, "clazz");
+ ArgCheck.isNotEmpty(methodName, "methodName");
+ parserMethods.add(clazz.getMethod(methodName, String.class,
ExecutionEnvironment.class));
+ }
+
+ /**
+ * Add a static method that can be used to parse {@link
Rule#getString(NamespaceRegistry, TextEncoder) rule definition
+ * strings}. These methods must be static, must accept a {@link String} definition as
the first parameter and an
+ * {@link ExecutionEnvironment} environment reference as the second parameter, and
should return the resulting {@link Rule}
+ * (or null if the definition format could not be understood by the method. Any
exceptions during
+ * {@link Method#invoke(Object, Object...) invocation} will be logged at the
+ * {@link Logger#trace(Throwable, String, Object...) trace} level.
+ *
+ * @param classLoader the class loader that should be used to load the class on which
the method is defined; may not be null
+ * @param className the name of the class on which the static method is defined; may
not be null
+ * @param methodName the name of the method
+ * @throws SecurityException if there is a security exception while loading the class
or getting the method
+ * @throws NoSuchMethodException if the method does not exist on the class
+ * @throws ClassNotFoundException if the class could not be found given the supplied
class loader
+ * @throws IllegalArgumentException if the class loader reference is null, or if the
class name or method name are null or
+ * empty
+ * @see #addRuleParser(Method)
+ */
+ public void addRuleParser( ClassLoader classLoader,
+ String className,
+ String methodName ) throws SecurityException,
NoSuchMethodException, ClassNotFoundException {
+ ArgCheck.isNotNull(classLoader, "classLoader");
+ ArgCheck.isNotEmpty(className, "className");
+ ArgCheck.isNotEmpty(methodName, "methodName");
+ Class<?> clazz = Class.forName(className, true, classLoader);
+ parserMethods.add(clazz.getMethod(methodName, String.class,
ExecutionEnvironment.class));
+ }
+
+ /**
+ * Remove the rule parser method.
+ *
+ * @param method the method to remove
+ * @return true if the method was removed, or false if the method was not a
registered rule parser method
+ */
+ public boolean removeRuleParser( Method method ) {
+ return parserMethods.remove(method);
+ }
+
+ /**
+ * Remove the rule parser method.
+ *
+ * @param declaringClassName the name of the class on which the static method is
defined; may not be null
+ * @param methodName the name of the method
+ * @return true if the method was removed, or false if the method was not a
registered rule parser method
+ * @throws IllegalArgumentException if the class loader reference is null, or if the
class name or method name are null or
+ * empty
+ */
+ public boolean removeRuleParser( String declaringClassName,
+ String methodName ) {
+ ArgCheck.isNotEmpty(declaringClassName, "declaringClassName");
+ ArgCheck.isNotEmpty(methodName, "methodName");
+ for (Method method : parserMethods) {
+ if (method.getName().equals(methodName) &&
method.getDeclaringClass().getName().equals(declaringClassName)) {
+ return parserMethods.remove(method);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return parserMethods
+ */
+ /*package*/List<Method> getParserMethods() {
+ return Collections.unmodifiableList(parserMethods);
+ }
+
+ /**
+ * Parse the string form of a rule definition and return the rule
+ *
+ * @param definition the definition of the rule that is to be parsed
+ * @param env the environment in which this method is being executed; may not be
null
+ * @return the rule, or null if the definition could not be parsed
+ */
+ public Rule ruleFromString( String definition,
+ ExecutionEnvironment env ) {
+ ArgCheck.isNotNull(env, "env");
+ definition = definition != null ? definition.trim() : "";
+ if (definition.length() == 0) return null;
+ for (Method method : parserMethods) {
+ try {
+ Rule rule = (Rule)method.invoke(null, definition, env);
+ if (rule != null) {
+ if (logger.isTraceEnabled()) {
+ String msg = "Success parsing project rule definition
\"{0}\" using {1}";
+ logger.trace(msg, definition, method);
+ }
+ return rule;
+ } else if (logger.isTraceEnabled()) {
+ String msg = "Unable to parse project rule definition
\"{0}\" using {1}";
+ logger.trace(msg, definition, method);
+ }
+ } catch (Throwable err) {
+ String msg = "Error while parsing project rule definition
\"{0}\" using {1}";
+ Logger.getLogger(Projection.class).trace(err, msg, definition, method);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Parse string forms of an arry of rule definitions and return the rules
+ *
+ * @param env the environment in which this method is being executed; may not be
null
+ * @param definitions the definition of the rules that are to be parsed
+ * @return the rule, or null if the definition could not be parsed
+ */
+ public Rule[] rulesFromStrings( ExecutionEnvironment env,
+ String... definitions ) {
+ List<Rule> rules = new LinkedList<Rule>();
+ for (String definition : definitions) {
+ Rule rule = ruleFromString(definition, env);
+ if (rule != null) rules.add(rule);
+ }
+ return rules.toArray(new Rule[rules.size()]);
+ }
+
+ /**
+ * Parse a single string containing one or more string forms of rule definitions, and
return the rules. The string contains
+ * each rule on a separate line.
+ *
+ * @param env the environment in which this method is being executed; may not be
null
+ * @param definitions the definitions of the rules that are to be parsed, each
definition separated by a newline character.
+ * @return the rule, or null if the definition could not be parsed
+ */
+ public Rule[] rulesFromString( ExecutionEnvironment env,
+ String definitions ) {
+ List<String> lines = StringUtil.splitLines(definitions);
+ List<Rule> rules = new LinkedList<Rule>();
+ for (String definition : lines) {
+ Rule rule = ruleFromString(definition, env);
+ if (rule != null) rules.add(rule);
+ }
+ return rules.toArray(new Rule[rules.size()]);
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/AbstractContribution.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/AbstractContribution.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/AbstractContribution.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,132 @@
+/*
+ * 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.connector.federation.contribution;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.Path.Segment;
+
+/**
+ * @author Randall Hauch
+ */
+public abstract class AbstractContribution implements Contribution {
+
+ /**
+ * This is the first version of this class. See the documentation of
BasicMergePlan.serialVersionUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ protected static final List<Segment> EMPTY_CHILDREN = Collections.emptyList();
+ protected static final Map<Name, Property> EMPTY_PROPERTIES =
Collections.emptyMap();
+
+ private final String sourceName;
+ private DateTime expirationTimeInUtc;
+
+ /**
+ * Create a contribution for the source with the supplied name.
+ *
+ * @param sourceName the name of the source, which may not be null or blank
+ */
+ protected AbstractContribution( String sourceName ) {
+ assert sourceName != null && sourceName.trim().length() != 0;
+ this.sourceName = sourceName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSourceName() {
+ return this.sourceName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<Segment> getChildren() {
+ return EMPTY_CHILDREN;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<Name, Property> getProperties() {
+ return EMPTY_PROPERTIES;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.contribution.Contribution#isExpired(org.jboss.dna.spi.graph.DateTime)
+ */
+ public boolean isExpired( DateTime utcTime ) {
+ assert utcTime != null;
+ assert utcTime.toUtcTimeZone().equals(utcTime); // check that it is passed UTC
time
+ return !expirationTimeInUtc.isAfter(utcTime);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public DateTime getExpirationTimeInUtc() {
+ return this.expirationTimeInUtc;
+ }
+
+ /**
+ * @param expirationTimeInUtc Sets expirationTimeInUtc to the specified value.
+ */
+ public void setExpirationTimeInUtc( DateTime expirationTimeInUtc ) {
+ this.expirationTimeInUtc = expirationTimeInUtc;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation returns the hash code of the {@link #getSourceName() source
name}, and is compatible with the
+ * implementation of {@link #equals(Object)}.
+ * </p>
+ */
+ @Override
+ public int hashCode() {
+ return this.sourceName.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation only compares the {@link #getSourceName() source name}.
+ * </p>
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof AbstractContribution) {
+ AbstractContribution that = (AbstractContribution)obj;
+ return this.getSourceName().equals(that.getSourceName());
+ }
+ return false;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,87 @@
+/*
+ * 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.connector.federation.contribution;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.Path.Segment;
+
+/**
+ * The contribution of a source to the information for a single federated node. Users of
this interface should treat contributions
+ * as generally being immutable, since some implementation will be immutable and will
return immutable {@link #getProperties()
+ * properties} and {@link #getChildren() children} containers. Thus, rather than make
changes to an existing contribution, a new
+ * contribution is created to replace the previous contribution.
+ *
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public interface Contribution extends Serializable {
+
+ /**
+ * Get the name of the source that made this contribution.
+ *
+ * @return the name of the contributing source
+ */
+ public String getSourceName();
+
+ /**
+ * Get the source-specific path of this information.
+ *
+ * @return the path as known to the source, or null for {@link EmptyContribution}
+ */
+ public Path getPathInSource();
+
+ /**
+ * Determine whether this contribution has expired given the supplied current time.
+ *
+ * @param utcTime the current time expressed in UTC; may not be null
+ * @return true if at least one contribution has expired, or false otherwise
+ */
+ public boolean isExpired( DateTime utcTime );
+
+ /**
+ * Get the expiration time, already in UTC.
+ *
+ * @return the expiration time in UTC
+ */
+ public DateTime getExpirationTimeInUtc();
+
+ /**
+ * Get the properties that make up this contribution. This map is immutable.
+ *
+ * @return the map of properties; never null
+ */
+ public Map<Name, Property> getProperties();
+
+ /**
+ * Get the children that make up this contribution. This list is immutable.
+ *
+ * @return the list of children; never null
+ */
+ public List<Segment> getChildren();
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,61 @@
+/*
+ * 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.connector.federation.contribution;
+
+import org.jboss.dna.spi.graph.Path;
+
+/**
+ * A source contribution that is empty. In other words, the source has no contribution to
make.
+ * <p>
+ * Note that this is different than an unknown contribution, which may occur when a
source is added to a federated repository
+ * after the contributions have already been determined for nodes. In this case, the new
source's contribution for a node is not
+ * known and must be determined.
+ * </p>
+ *
+ * @author Randall Hauch
+ */
+public class EmptyContribution extends AbstractContribution {
+
+ /**
+ * This is the first version of this class. See the documentation of
BasicMergePlan.serialVersionUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Create a contribution for the source with the supplied name.
+ *
+ * @param sourceName the name of the source, which may not be null or blank
+ */
+ public EmptyContribution( String sourceName ) {
+ super(sourceName);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.contribution.Contribution#getPathInSource()
+ */
+ public Path getPathInSource() {
+ return null;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,78 @@
+/*
+ * 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.connector.federation.contribution;
+
+import java.util.ArrayList;
+import java.util.List;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.Path.Segment;
+
+/**
+ * The contribution of a source to the information for a single federated node.
+ * <p>
+ * This class does return a mutable list of {@link #getChildren() children} and mutable
map of {@link #getProperties() properties}
+ * .
+ * </p>
+ *
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class NodeContribution extends PropertyContribution {
+
+ /**
+ * This is the first version of this class. See the documentation of
BasicMergePlan.serialVersionUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ private List<Segment> children;
+
+ /**
+ * Create a contribution of node properties and children from the source with the
supplied name.
+ *
+ * @param sourceName the name of the source, which may not be null or blank
+ * @param pathInSource the path in the source for this contributed information; may
not be null
+ * @param properties the properties from the source; may not be null
+ * @param children the children from the source; may not be null or empty
+ */
+ public NodeContribution( String sourceName,
+ Path pathInSource,
+ Iterable<Property> properties,
+ Iterable<Segment> children ) {
+ super(sourceName, pathInSource, properties);
+ this.children = new ArrayList<Segment>(1);
+ for (Segment child : children) {
+ this.children.add(child);
+ }
+ }
+
+ /**
+ * Get the children that make up this contribution. This list is immutable.
+ *
+ * @return the list of children; never null
+ */
+ @Override
+ public List<Segment> getChildren() {
+ return this.children;
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PropertyContribution.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PropertyContribution.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PropertyContribution.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,84 @@
+/*
+ * 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.connector.federation.contribution;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+
+/**
+ * The record of a source contributing only properties to a node.
+ * <p>
+ * This class does return a mutable mutable map of {@link #getProperties() properties}.
+ * </p>
+ *
+ * @author Randall Hauch
+ */
+public class PropertyContribution extends AbstractContribution {
+
+ /**
+ * This is the first version of this class. See the documentation of
BasicMergePlan.serialVersionUID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ private final Map<Name, Property> properties;
+ private final Path pathInSource;
+
+ /**
+ * Create a contribution of node properties from the source with the supplied name.
+ *
+ * @param sourceName the name of the source, which may not be null or blank
+ * @param pathInSource the path in the source for this contributed information; may
not be null
+ * @param properties the properties from the source; may not be null
+ */
+ public PropertyContribution( String sourceName,
+ Path pathInSource,
+ Iterable<Property> properties ) {
+ super(sourceName);
+ assert pathInSource != null;
+ this.properties = new HashMap<Name, Property>();
+ this.pathInSource = pathInSource;
+ for (Property property : properties) {
+ this.properties.put(property.getName(), property);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<Name, Property> getProperties() {
+ return this.properties;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.contribution.Contribution#getPathInSource()
+ */
+ public Path getPathInSource() {
+ return pathInSource;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,105 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.executor;
+
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.commands.ActsOnPath;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+
+/**
+ * @author Randall Hauch
+ * @param <T> the command type
+ */
+public class ActsOnProjectedPathCommand<T extends GraphCommand> implements
ActsOnPath, GraphCommand {
+
+ private final T delegate;
+ private final Path projectedPath;
+
+ protected ActsOnProjectedPathCommand( T delegate,
+ Path projectedPath ) {
+ assert delegate != null;
+ assert projectedPath != null;
+ this.delegate = delegate;
+ this.projectedPath = projectedPath;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.ActsOnPath#getPath()
+ */
+ public Path getPath() {
+ return projectedPath;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.GraphCommand#getError()
+ */
+ public Throwable getError() {
+ return delegate.getError();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.GraphCommand#hasError()
+ */
+ public boolean hasError() {
+ return delegate.hasError();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.GraphCommand#hasNoError()
+ */
+ public boolean hasNoError() {
+ return delegate.hasNoError();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.GraphCommand#isCancelled()
+ */
+ public boolean isCancelled() {
+ return delegate.isCancelled();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.GraphCommand#setError(java.lang.Throwable)
+ */
+ public void setError( Throwable error ) {
+ delegate.setError(error);
+ }
+
+ /**
+ * @return delegate
+ */
+ protected T getOriginalCommand() {
+ return delegate;
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,331 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.executor;
+
+import java.io.ObjectInputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.connector.federation.FederationI18n;
+import org.jboss.dna.connector.federation.Projection;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.connector.federation.merge.BasicMergePlan;
+import org.jboss.dna.spi.graph.Binary;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.ValueFactory;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetNodeCommand;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor;
+import org.jboss.dna.spi.graph.commands.impl.BasicGetNodeCommand;
+import org.jboss.dna.spi.graph.commands.impl.BasicGetPropertiesCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactories;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class FederatingCommandExecutor extends AbstractCommandExecutor {
+
+ private final Name mergePlanPropertyName;
+ private final Projection cacheProjection;
+ private final List<Projection> sourceProjections;
+ private final Set<String> sourceNames;
+ private final RepositoryConnectionFactories connectionFactories;
+ /** The set of all connections, including the cache connection */
+ private final Map<String, RepositoryConnection> connectionsBySourceName;
+ /** A direct reference to the cache connection */
+ private RepositoryConnection cacheConnection;
+
+ /**
+ * Create a command executor that federates (merges) the information from multiple
sources described by the source
+ * projections. The resulting command executor does not first consult a cache for the
merged information; if a cache is
+ * desired, see
+ * {@link #FederatingCommandExecutor(ExecutionEnvironment, String, Projection, List,
RepositoryConnectionFactories)
+ * constructor} that takes a {@link Projection cache projection}.
+ *
+ * @param env the execution environment in which the executor will be run; may not be
null
+ * @param sourceName the name of the {@link RepositorySource} that is making use of
this executor; may not be null or empty
+ * @param sourceProjections the source projections; may not be null
+ * @param connectionFactories the factory for connection factory instances
+ */
+ public FederatingCommandExecutor( ExecutionEnvironment env,
+ String sourceName,
+ List<Projection> sourceProjections,
+ RepositoryConnectionFactories connectionFactories )
{
+ this(env, sourceName, null, sourceProjections, connectionFactories);
+ }
+
+ /**
+ * Create a command executor that federates (merges) the information from multiple
sources described by the source
+ * projections. The resulting command executor will use the supplied {@link
Projection cache projection} to identify the
+ * {@link Projection#getSourceName() repository source} for the cache as well as the
{@link Projection#getRules() rules} for
+ * how the paths are mapped in the cache. This cache will be consulted first for the
requested information, and will be kept
+ * up to date as changes are made to the federated information.
+ *
+ * @param env the execution environment in which the executor will be run; may not be
null
+ * @param sourceName the name of the {@link RepositorySource} that is making use of
this executor; may not be null or empty
+ * @param cacheProjection the projection used for the cached information; may be null
if there is no cache
+ * @param sourceProjections the source projections; may not be null
+ * @param connectionFactories the factory for connection factory instances
+ */
+ public FederatingCommandExecutor( ExecutionEnvironment env,
+ String sourceName,
+ Projection cacheProjection,
+ List<Projection> sourceProjections,
+ RepositoryConnectionFactories connectionFactories )
{
+ super(env, sourceName);
+ assert sourceProjections != null;
+ assert connectionFactories != null;
+ this.cacheProjection = cacheProjection;
+ this.sourceProjections = sourceProjections;
+ this.connectionFactories = connectionFactories;
+ this.connectionsBySourceName = new HashMap<String,
RepositoryConnection>();
+ this.mergePlanPropertyName =
env.getValueFactories().getNameFactory().create("dna:mergePlan");
+ this.sourceNames = new HashSet<String>();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#close()
+ */
+ @Override
+ public void close() throws InterruptedException {
+ try {
+ super.close();
+ } finally {
+ // Make sure to close ALL open connections ...
+ for (RepositoryConnection connection : connectionsBySourceName.values()) {
+ if (connection == null) continue;
+ try {
+ connection.close();
+ } catch (Throwable t) {
+ Logger.getLogger(getClass()).debug("Error while closing
connection to {0}", connection.getSourceName());
+ }
+ }
+ connectionsBySourceName.clear();
+ }
+ }
+
+ protected RepositoryConnection getConnectionToCache() throws
RepositorySourceException, InterruptedException {
+ if (this.cacheConnection == null) {
+ this.cacheConnection = getConnection(this.cacheProjection);
+ }
+ assert this.cacheConnection != null;
+ return this.cacheConnection;
+ }
+
+ protected RepositoryConnection getConnection( Projection projection ) throws
RepositorySourceException, InterruptedException {
+ String sourceName = projection.getSourceName();
+ RepositoryConnection connection = connectionsBySourceName.get(sourceName);
+ if (connection == null) {
+ RepositoryConnectionFactory connectionFactory =
connectionFactories.getConnectionFactory(sourceName);
+ if (connectionFactory != null) {
+ connection = connectionFactory.getConnection();
+ }
+ connectionsBySourceName.put(sourceName, connection);
+ }
+ return connection;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This class overrides the {@link AbstractCommandExecutor#execute(GetNodeCommand)
default behavior} and instead processes the
+ * command in a more efficient manner.
+ * </p>
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetNodeCommand)
+ */
+ @Override
+ public void execute( GetNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+ for (Property property : nodeInfo.getProperties().values()) {
+ command.setProperty(property);
+ }
+ command.setChildren(nodeInfo.getChildren());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetPropertiesCommand)
+ */
+ @Override
+ public void execute( GetPropertiesCommand command ) throws RepositorySourceException,
InterruptedException {
+ BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+ for (Property property : nodeInfo.getProperties().values()) {
+ command.setProperty(property);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetChildrenCommand)
+ */
+ @Override
+ public void execute( GetChildrenCommand command ) throws RepositorySourceException,
InterruptedException {
+ BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+ command.setChildren(nodeInfo.getChildren());
+ }
+
+ /**
+ * Get the node information from the underlying sources or, if possible, from the
cache.
+ *
+ * @param path the path of the node to be returned
+ * @return the node information
+ * @throws RepositorySourceException
+ * @throws InterruptedException
+ */
+ protected BasicGetNodeCommand getNode( Path path ) throws RepositorySourceException,
InterruptedException {
+ // Check the cache first ...
+ RepositoryConnection cacheConnection = getConnectionToCache();
+ BasicGetNodeCommand fromCache = new BasicGetNodeCommand(path);
+ cacheConnection.execute(getEnvironment(), fromCache);
+ if (fromCache.hasError()) return fromCache;
+
+ // Look up the merge plan ...
+ BasicMergePlan basicMergePlan = getMergePlan(fromCache);
+ if (basicMergePlan != null) {
+ if (isCurrent(path, basicMergePlan)) return fromCache;
+ // Some of the merge plan is out of date, so we need to read the information
from those regions that are expired ...
+ BasicMergePlan newMergePlan = new BasicMergePlan();
+ // for (Projection projection : sourceProjections) {
+ // // Does this region apply to the path ...
+ // if (projection.appliesTo(path)) {
+ // // Get any existing contribution ...
+ // Contribution contribution =
mergePlan.getContributionFrom(region.getSourceName());
+ // if (contribution == null || contribution.isExpired(getCurrentTimeInUtc()))
{
+ // contribution = getContribution(contribution.getSourceName(), path);
+ // }
+ // newMergePlan.addContribution(contribution);
+ // }
+ // }
+ // for ( Contribution contribution : mergePlan.getContributions() ) {
+ // // Is the contribution still represented by a region?
+ //
+ // if ( contribution.isExpired(getCurrentTimeInUtc())) {
+ // contribution = getContribution(contribution.getSourceName(),path);
+ // }
+ // newMergePlan.addContribution(contribution);
+ // }
+
+ // What about other (new) regions?
+ } else {
+ // At this point, there is no merge plan, so read information from the
sources ...
+ // for (FederatedRegion region : regions) {
+ // if (!region.appliesTo(path)) continue;
+ // // Issue a command to get the node from the
+ // // BasicGetNode
+ // }
+ }
+ // And read the information from any new region ...
+ return null;
+ }
+
+ protected Contribution getContribution( String sourceName,
+ Path path ) {
+ return null;
+ }
+
+ protected BasicMergePlan getMergePlan( BasicGetPropertiesCommand command ) {
+ Property mergePlanProperty = command.getProperties().get(mergePlanPropertyName);
+ if (mergePlanProperty == null || mergePlanProperty.isEmpty()) {
+ return null;
+ }
+ ValueFactory<Binary> binaryFactory =
getEnvironment().getValueFactories().getBinaryFactory();
+ Binary binaryValue = binaryFactory.create(mergePlanProperty.getValues().next());
+ binaryValue.acquire();
+ ObjectInputStream stream = null;
+ BasicMergePlan basicMergePlan = null;
+ RepositorySourceException error = null;
+ try {
+ stream = new ObjectInputStream(binaryValue.getStream());
+ basicMergePlan = (BasicMergePlan)stream.readObject();
+ } catch (Throwable err) {
+ I18n msg = FederationI18n.errorReadingMergePlan;
+ error = new RepositorySourceException(getSourceName(),
msg.text(command.getPath()), err);
+ throw error;
+ } finally {
+ try {
+ if (stream != null) stream.close();
+ } catch (Throwable err) {
+ if (error == null) {
+ I18n msg = FederationI18n.errorReadingMergePlan;
+ error = new RepositorySourceException(getSourceName(),
msg.text(command.getPath()), err);
+ throw error;
+ }
+ } finally {
+ binaryValue.release();
+ }
+ }
+ return basicMergePlan;
+ }
+
+ /**
+ * Determine if the supplied plan is considered current
+ *
+ * @param path the path of the node at which (or below which) the merge plan applies
+ * @param plan the merge plan
+ * @return true if the merge plan is current, or false if it needs to be (at least
partially) rebuilt
+ */
+ protected boolean isCurrent( Path path,
+ BasicMergePlan plan ) {
+ // First check the time ...
+ DateTime now = getCurrentTimeInUtc();
+ if (plan.isExpired(now)) return false;
+
+ // Does the plan have any contributions from sources that don't exist ?
+ for (String contributingSource : plan.getNamesOfContributingSources()) {
+ if (!sourceNames.contains(contributingSource)) return false;
+ }
+
+ // Determine if any new source projections exists that aren't part of the
plan ...
+ for (String sourceName : sourceNames) {
+ if (plan.isSource(sourceName)) continue;
+ // The source is new ... see whether there are any regions that apply ...
+ // for (FederatedRegion region : this.regionsBySourceName.get(sourceName)) {
+ // // If the region's path is not at/above the path, the region
doesn't matter
+ // if (!region.appliesTo(path)) continue;
+ // // The region applies to the path ...
+ // return false;
+ // }
+ }
+ return true;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,37 @@
+/*
+ * 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.connector.federation.executor;
+
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedCopyBranchCommand extends ProjectedCopyNodeCommand implements
CopyBranchCommand {
+
+ public ProjectedCopyBranchCommand( CopyBranchCommand delegate,
+ Path projectedPath,
+ Path newProjectedPath ) {
+ super(delegate, projectedPath, newProjectedPath);
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,51 @@
+/*
+ * 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.connector.federation.executor;
+
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedCopyNodeCommand extends
ActsOnProjectedPathCommand<CopyNodeCommand> implements CopyNodeCommand {
+
+ private final Path newProjectedPath;
+
+ public ProjectedCopyNodeCommand( CopyNodeCommand delegate,
+ Path projectedPath,
+ Path newProjectedPath ) {
+ super(delegate, projectedPath);
+ assert newProjectedPath != null;
+ this.newProjectedPath = newProjectedPath;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.CopyNodeCommand#getNewPath()
+ */
+ public Path getNewPath() {
+ return newProjectedPath;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCreateNodeCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCreateNodeCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCreateNodeCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.executor;
+
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
+import org.jboss.dna.spi.graph.commands.NodeConflictBehavior;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedCreateNodeCommand extends
ActsOnProjectedPathCommand<CreateNodeCommand> implements CreateNodeCommand {
+
+ public ProjectedCreateNodeCommand( CreateNodeCommand delegate,
+ Path projectedPath ) {
+ super(delegate, projectedPath);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.CreateNodeCommand#getConflictBehavior()
+ */
+ public NodeConflictBehavior getConflictBehavior() {
+ return getOriginalCommand().getConflictBehavior();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.CreateNodeCommand#getProperties()
+ */
+ public Iterable<Property> getProperties() {
+ return getOriginalCommand().getProperties();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo( CreateNodeCommand that ) {
+ if (this == that) return 0;
+ return this.getPath().compareTo(that.getPath());
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,37 @@
+/*
+ * 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.connector.federation.executor;
+
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.commands.DeleteBranchCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedDeleteBranchCommand extends
ActsOnProjectedPathCommand<DeleteBranchCommand> implements DeleteBranchCommand {
+
+ public ProjectedDeleteBranchCommand( DeleteBranchCommand delegate,
+ Path projectedPath ) {
+ super(delegate, projectedPath);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,117 @@
+/*
+ * 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.connector.federation.executor;
+
+import java.util.Iterator;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Path.Segment;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedGetChildrenCommand extends
ActsOnProjectedPathCommand<GetChildrenCommand> implements GetChildrenCommand {
+
+ /**
+ */
+ private static final long serialVersionUID = 1L;
+
+ public ProjectedGetChildrenCommand( GetChildrenCommand delegate,
+ Path projectedPath ) {
+ super(delegate, projectedPath);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.GetChildrenCommand#setChild(org.jboss.dna.spi.graph.Name)
+ */
+ public void setChild( Name nameOfChild ) {
+ getOriginalCommand().setChild(nameOfChild);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.GetChildrenCommand#setChildren(java.util.Iterator)
+ */
+ public void setChildren( Iterator<Segment> namesOfChildren ) {
+ getOriginalCommand().setChildren(namesOfChildren);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.GetChildrenCommand#setChildren(java.lang.Iterable)
+ */
+ public void setChildren( Iterable<Segment> namesOfChildren ) {
+ getOriginalCommand().setChildren(namesOfChildren);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.GetChildrenCommand#setChildren(org.jboss.dna.spi.graph.Path.Segment[])
+ */
+ public void setChildren( Segment... namesOfChildren ) {
+ getOriginalCommand().setChildren(namesOfChildren);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.GetChildrenCommand#setNoChildren()
+ */
+ public void setNoChildren() {
+ getOriginalCommand().setNoChildren();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.cache.Cacheable#getCachePolicy()
+ */
+ public CachePolicy getCachePolicy() {
+ return getOriginalCommand().getCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.cache.Cacheable#getTimeLoaded()
+ */
+ public long getTimeLoaded() {
+ return getOriginalCommand().getTimeLoaded();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.cache.Cacheable#setCachePolicy(org.jboss.dna.spi.cache.CachePolicy)
+ */
+ public void setCachePolicy( CachePolicy cachePolicy ) {
+ getOriginalCommand().setCachePolicy(cachePolicy);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,52 @@
+/*
+ * 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.connector.federation.executor;
+
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetNodeCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedGetNodeCommand extends ProjectedGetChildrenCommand implements
GetNodeCommand {
+
+ /**
+ */
+ private static final long serialVersionUID = 1L;
+
+ public ProjectedGetNodeCommand( GetChildrenCommand delegate,
+ Path projectedPath ) {
+ super(delegate, projectedPath);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.GetPropertiesCommand#setProperty(org.jboss.dna.spi.graph.Property)
+ */
+ public void setProperty( Property property ) {
+ ((GetNodeCommand)getOriginalCommand()).setProperty(property);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,80 @@
+/*
+ * 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.connector.federation.executor;
+
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedGetPropertiesCommand extends
ActsOnProjectedPathCommand<GetPropertiesCommand>
+ implements GetPropertiesCommand {
+
+ /**
+ */
+ private static final long serialVersionUID = 1L;
+
+ public ProjectedGetPropertiesCommand( GetPropertiesCommand delegate,
+ Path projectedPath ) {
+ super(delegate, projectedPath);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.cache.Cacheable#getCachePolicy()
+ */
+ public CachePolicy getCachePolicy() {
+ return getOriginalCommand().getCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.cache.Cacheable#getTimeLoaded()
+ */
+ public long getTimeLoaded() {
+ return getOriginalCommand().getTimeLoaded();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.cache.Cacheable#setCachePolicy(org.jboss.dna.spi.cache.CachePolicy)
+ */
+ public void setCachePolicy( CachePolicy cachePolicy ) {
+ getOriginalCommand().setCachePolicy(cachePolicy);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.GetPropertiesCommand#setProperty(org.jboss.dna.spi.graph.Property)
+ */
+ public void setProperty( Property property ) {
+ getOriginalCommand().setProperty(property);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,61 @@
+/*
+ * 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.connector.federation.executor;
+
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
+import org.jboss.dna.spi.graph.commands.NodeConflictBehavior;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedMoveBranchCommand extends
ActsOnProjectedPathCommand<MoveBranchCommand> implements MoveBranchCommand {
+
+ private final Path newProjectedPath;
+
+ public ProjectedMoveBranchCommand( MoveBranchCommand delegate,
+ Path projectedPath,
+ Path newProjectedPath ) {
+ super(delegate, projectedPath);
+ assert newProjectedPath != null;
+ this.newProjectedPath = newProjectedPath;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.MoveBranchCommand#getConflictBehavior()
+ */
+ public NodeConflictBehavior getConflictBehavior() {
+ return getOriginalCommand().getConflictBehavior();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.MoveBranchCommand#getNewPath()
+ */
+ public Path getNewPath() {
+ return this.newProjectedPath;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,82 @@
+/*
+ * 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.connector.federation.executor;
+
+import java.util.Iterator;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.commands.RecordBranchCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedRecordBranchCommand extends
ActsOnProjectedPathCommand<RecordBranchCommand> implements RecordBranchCommand {
+
+ public ProjectedRecordBranchCommand( RecordBranchCommand delegate,
+ Path projectedPath ) {
+ super(delegate, projectedPath);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.RecordBranchCommand#record(org.jboss.dna.spi.graph.Path,
java.lang.Iterable)
+ */
+ public boolean record( Path path,
+ Iterable<Property> properties ) {
+ path = relativePathFrom(path);
+ return getOriginalCommand().record(path, properties);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.RecordBranchCommand#record(org.jboss.dna.spi.graph.Path,
java.util.Iterator)
+ */
+ public boolean record( Path path,
+ Iterator<Property> properties ) {
+ path = relativePathFrom(path);
+ return getOriginalCommand().record(path, properties);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.RecordBranchCommand#record(org.jboss.dna.spi.graph.Path,
+ * org.jboss.dna.spi.graph.Property[])
+ */
+ public boolean record( Path path,
+ Property... properties ) {
+ path = relativePathFrom(path);
+ return getOriginalCommand().record(path, properties);
+ }
+
+ protected Path relativePathFrom( Path path ) {
+ if (path == null) return null;
+ if (path.isAbsolute()) {
+ // The path is absolute, so compute the relative path w/r/t the new path ...
+ path = path.relativeTo(this.getPath());
+ }
+ return path;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommand.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommand.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,48 @@
+/*
+ * 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.connector.federation.executor;
+
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectedSetPropertiesCommand extends
ActsOnProjectedPathCommand<SetPropertiesCommand>
+ implements SetPropertiesCommand {
+
+ public ProjectedSetPropertiesCommand( SetPropertiesCommand delegate,
+ Path projectedPath ) {
+ super(delegate, projectedPath);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.ActsOnProperties#getProperties()
+ */
+ public Iterable<Property> getProperties() {
+ return getOriginalCommand().getProperties();
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,247 @@
+/*
+ * 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.connector.federation.executor;
+
+import java.util.Set;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.connector.federation.Projection;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
+import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
+import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
+import org.jboss.dna.spi.graph.commands.DeleteBranchCommand;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetNodeCommand;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
+import org.jboss.dna.spi.graph.commands.RecordBranchCommand;
+import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactories;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class SingleProjectionCommandExecutor extends AbstractCommandExecutor {
+
+ private final Projection projection;
+ private final PathFactory pathFactory;
+ private final RepositoryConnectionFactories factories;
+ private RepositoryConnection connection;
+
+ /**
+ * @param env the execution environment in which the executor will be run; may not be
null
+ * @param sourceName the name of the {@link RepositorySource} that is making use of
this executor; may not be null or empty
+ * @param projection the projection used for the cached information; may not be null
and must have exactly one
+ * {@link Projection#getRules() rule}
+ * @param connectionFactories the factory for connection factory instances
+ */
+ public SingleProjectionCommandExecutor( ExecutionEnvironment env,
+ String sourceName,
+ Projection projection,
+ RepositoryConnectionFactories
connectionFactories ) {
+ this(env, sourceName, null, projection, connectionFactories);
+ }
+
+ /**
+ * @param env the execution environment in which the executor will be run; may not be
null
+ * @param sourceName the name of the {@link RepositorySource} that is making use of
this executor; may not be null or empty
+ * @param now the current time; may be null if the system time is to be used
+ * @param projection the projection used for the cached information; may not be null
and must have exactly one
+ * {@link Projection#getRules() rule}
+ * @param connectionFactories the factory for connection factory instances
+ */
+ public SingleProjectionCommandExecutor( ExecutionEnvironment env,
+ String sourceName,
+ DateTime now,
+ Projection projection,
+ RepositoryConnectionFactories
connectionFactories ) {
+ super(env, sourceName, now);
+ assert connectionFactories != null;
+ assert projection != null;
+ assert projection.getRules().size() == 1;
+ this.projection = projection;
+ this.factories = connectionFactories;
+ this.pathFactory = env.getValueFactories().getPathFactory();
+ assert this.pathFactory != null;
+ }
+
+ protected RepositoryConnection getConnection() throws RepositorySourceException,
InterruptedException {
+ if (connection == null) {
+ // Create a connection ...
+ RepositoryConnectionFactory connectionFactory =
this.factories.getConnectionFactory(this.projection.getSourceName());
+ connection = connectionFactory.getConnection();
+ }
+ return connection;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#close()
+ */
+ @Override
+ public void close() throws InterruptedException {
+ if (this.connection != null) {
+ try {
+ this.connection.close();
+ } finally {
+ this.connection = null;
+ }
+ }
+ super.close();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetChildrenCommand)
+ */
+ @Override
+ public void execute( GetChildrenCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedGetChildrenCommand(command, pathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetPropertiesCommand)
+ */
+ @Override
+ public void execute( GetPropertiesCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedGetPropertiesCommand(command, pathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetNodeCommand)
+ */
+ @Override
+ public void execute( GetNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedGetNodeCommand(command, pathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CreateNodeCommand)
+ */
+ @Override
+ public void execute( CreateNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedCreateNodeCommand(command, pathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.SetPropertiesCommand)
+ */
+ @Override
+ public void execute( SetPropertiesCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedSetPropertiesCommand(command, pathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.DeleteBranchCommand)
+ */
+ @Override
+ public void execute( DeleteBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedDeleteBranchCommand(command, pathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.MoveBranchCommand)
+ */
+ @Override
+ public void execute( MoveBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ Path newPathInSource = getPathInSource(command.getNewPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedMoveBranchCommand(command, pathInSource, newPathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.RecordBranchCommand)
+ */
+ @Override
+ public void execute( RecordBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedRecordBranchCommand(command, pathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CopyBranchCommand)
+ */
+ @Override
+ public void execute( CopyBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ Path newPathInSource = getPathInSource(command.getNewPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedCopyBranchCommand(command, pathInSource, newPathInSource));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CopyNodeCommand)
+ */
+ @Override
+ public void execute( CopyNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ Path pathInSource = getPathInSource(command.getPath());
+ Path newPathInSource = getPathInSource(command.getNewPath());
+ getConnection().execute(this.getEnvironment(), new
ProjectedCopyNodeCommand(command, pathInSource, newPathInSource));
+ }
+
+ protected Path getPathInSource( Path pathInRepository ) {
+ Set<Path> paths = this.projection.getPathsInSource(pathInRepository,
pathFactory);
+ if (!paths.isEmpty()) {
+ return paths.iterator().next();
+ }
+ return this.projection.getPathsInSource(pathInRepository,
pathFactory).iterator().next();
+ }
+
+ protected Path getPathInRepository( Path pathInSource ) {
+ return this.projection.getPathsInRepository(pathInSource,
pathFactory).iterator().next();
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/BasicFederatedNode.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/BasicFederatedNode.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/BasicFederatedNode.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,148 @@
+/*
+ * 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.connector.federation.merge;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.UUID;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Property;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class BasicFederatedNode implements FederatedNode {
+
+ private final UUID uuid;
+
+ // private Name name;
+
+ /**
+ * Create a new federated node instance.
+ *
+ * @param uuid the UUID; may not be null
+ */
+ public BasicFederatedNode( UUID uuid ) {
+ assert uuid != null;
+ this.uuid = uuid;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Name getName() {
+ return null;
+ }
+
+ /**
+ * @param name Sets name to the specified value; may not be null
+ */
+ public void setName( Name name ) {
+ assert name != null;
+ // this.name = name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<String> getContributingSources() {
+ Set<String> names = new HashSet<String>();
+ return names;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<Property> getProperties() {
+ // Compute merged properties ...
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Property getProperty( Name propertyName ) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getPropertyCount() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<Name> getPropertyNames() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeAllProperties() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setAllProperties( Property... properties ) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setAllProperties( Iterable<Property> properties ) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setProperties( Property... properties ) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setProperties( Iterable<Property> properties ) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Property setPropertyIfAbsent( Property property ) {
+ return null;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/BasicMergePlan.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/BasicMergePlan.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/BasicMergePlan.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,205 @@
+/*
+ * 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.connector.federation.merge;
+
+import java.io.InvalidClassException;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.connector.federation.contribution.EmptyContribution;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Property;
+
+/**
+ * This class represents the details about how information from different sources are
merged into a single federated node.
+ * <p>
+ * A merge plan basically consists of the individual contribution from each source and
the information about how these
+ * contributions were merged into the single federated node.
+ * </p>
+ * <p>
+ * Merge plans are designed to be {@link Serializable serializable}, as they are
persisted on the federated node and deserialized
+ * to assist in the management of the federated node.
+ * </p>
+ *
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class BasicMergePlan implements Serializable {
+
+ /**
+ * Define the earliest version of this class that is supported. The Java runtime,
upon deserialization, compares the
+ * serialized object's version to this, and if less than this version will throw
a {@link InvalidClassException}. If, however,
+ * the serialized object's version is compatible with this class, it will be
deserialized successfully.
+ * <p>
+ * <a
href="http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/v...
documentation</a> describes
+ * the following changes can be made without negatively affecting the deserialization
of older versions:
+ * <ul>
+ * <li>Adding fields - When the class being reconstituted has a field that does
not occur in the stream, that field in the
+ * object will be initialized to the default value for its type. If class-specific
initialization is needed, the class may
+ * provide a readObject method that can initialize the field to nondefault
values.</i>
+ * <li>Adding classes - The stream will contain the type hierarchy of each
object in the stream. Comparing this hierarchy in
+ * the stream with the current class can detect additional classes. Since there is no
information in the stream from which to
+ * initialize the object, the class's fields will be initialized to the default
values.</i>
+ * <li>Removing classes - Comparing the class hierarchy in the stream with that
of the current class can detect that a class
+ * has been deleted. In this case, the fields and objects corresponding to that class
are read from the stream. Primitive
+ * fields are discarded, but the objects referenced by the deleted class are created,
since they may be referred to later in
+ * the stream. They will be garbage-collected when the stream is garbage-collected or
reset.</i>
+ * <li>Adding writeObject/readObject methods - If the version reading the
stream has these methods then readObject is
+ * expected, as usual, to read the required data written to the stream by the default
serialization. It should call
+ * defaultReadObject first before reading any optional data. The writeObject method
is expected as usual to call
+ * defaultWriteObject to write the required data and then may write optional
data.</i>
+ * <li>Removing writeObject/readObject methods - If the class reading the
stream does not have these methods, the required
+ * data will be read by default serialization, and the optional data will be
discarded.</i>
+ * <li>Adding java.io.Serializable - This is equivalent to adding types. There
will be no values in the stream for this class
+ * so its fields will be initialized to default values. The support for subclassing
nonserializable classes requires that the
+ * class's supertype have a no-arg constructor and the class itself will be
initialized to default values. If the no-arg
+ * constructor is not available, the InvalidClassException is thrown.</i>
+ * <li>Changing the access to a field - The access modifiers public, package,
protected, and private have no effect on the
+ * ability of serialization to assign values to the fields.</i>
+ * <li>Changing a field from static to nonstatic or transient to nontransient -
When relying on default serialization to
+ * compute the serializable fields, this change is equivalent to adding a field to
the class. The new field will be written to
+ * the stream but earlier classes will ignore the value since serialization will not
assign values to static or transient
+ * fields.</i>
+ * </ul>
+ * All other kinds of modifications should be avoided.
+ * </p>
+ */
+ private static final long serialVersionUID = 1L;
+
+ private final Map<String, Contribution> contributions = new HashMap<String,
Contribution>();
+ private Map<Name, Property> annotations = null;
+ private DateTime expirationTimeInUtc;
+
+ /**
+ * Create this version
+ */
+ public BasicMergePlan() {
+ }
+
+ /**
+ * Determine whether this merge plan has expired given the supplied current time. The
{@link #getExpirationTimeInUtc()
+ * expiration time} is the earliest time that any of the {@link
#getContributionFrom(String) contributions}
+ * {@link Contribution#getExpirationTimeInUtc()}.
+ *
+ * @param utcTime the current time expressed in UTC; may not be null
+ * @return true if at least one contribution has expired, or false otherwise
+ */
+ public boolean isExpired( DateTime utcTime ) {
+ assert utcTime != null;
+ assert utcTime.toUtcTimeZone().equals(utcTime); // check that it is passed UTC
time
+ return !expirationTimeInUtc.isAfter(utcTime);
+ }
+
+ /**
+ * Get the expiration time (in UTC) that is the earliest time that any of the {@link
#getContributionFrom(String)
+ * contributions} {@link Contribution#getExpirationTimeInUtc()}.
+ *
+ * @return the expiration time in UTC, or null if there is no known expiration time
+ */
+ public DateTime getExpirationTimeInUtc() {
+ return expirationTimeInUtc;
+ }
+
+ /**
+ * Get the contribution from the source with the supplied name. Note that
contributions always include sources that contribute
+ * information and sources that contribute no information. If a source is not
included in this list, its contributions are
+ * <i>unknown</i>; that is, it is unknown whether that source does or
does not contribute to the node.
+ *
+ * @param sourceName the name of the source
+ * @return the contribution, or null if the contribution of the source is unknown
+ */
+ public Contribution getContributionFrom( String sourceName ) {
+ return contributions.get(sourceName);
+ }
+
+ /**
+ * Return whether the named source was consulted for a contribution.
+ *
+ * @param sourceName the name of the source
+ * @return true if the source has some {@link Contribution contribution} (even if it
is an {@link EmptyContribution})
+ */
+ public boolean isSource( String sourceName ) {
+ return contributions.containsKey(sourceName);
+ }
+
+ /**
+ * Get the names of the contributing sources.
+ *
+ * @return the names of the sources that have some contribution
+ */
+ public Set<String> getNamesOfContributingSources() {
+ return contributions.keySet();
+ }
+
+ /**
+ * Add the supplied contribution, replacing and returning any previous contribution
for the same source.
+ *
+ * @param contribution the new contribution
+ * @return the previous contribution for the source, or null if there was no previous
contribution.
+ */
+ public Contribution addContribution( Contribution contribution ) {
+ assert contribution != null;
+ Contribution previous = contributions.put(contribution.getSourceName(),
contribution);
+ DateTime contributionExpirationInUtc = contribution.getExpirationTimeInUtc();
+ if (expirationTimeInUtc == null ||
contributionExpirationInUtc.isBefore(expirationTimeInUtc)) {
+ expirationTimeInUtc = contributionExpirationInUtc;
+ }
+ return previous;
+ }
+
+ /**
+ * Get the plan annotation property with the given name. Plan annotations are custom
properties that may be set by
+ * MergeProcessor implementations to store custom properties on the plan. This method
does nothing if the supplied name is
+ * null
+ *
+ * @param name the name of the annotation
+ * @return the existing annotation, or null if there is no annotation with the
supplied name
+ * @see #setAnnotation(Property)
+ */
+ public Property getAnnotation( Name name ) {
+ if (name == null) return null;
+ if (this.annotations == null) return null;
+ return this.annotations.get(name);
+ }
+
+ /**
+ * Set the plan annotation property. This method replaces and returns any existing
annotation property with the same name.
+ * This method also returns immediately if the supplied annotation is null.
+ *
+ * @param annotation the new annotation
+ * @return the previous annotation property with the same name, or null if there was
no previous annotation property for the
+ * name
+ * @see #getAnnotation(Name)
+ */
+ public Property setAnnotation( Property annotation ) {
+ if (annotation == null) return null;
+ if (this.annotations == null) {
+ this.annotations = new HashMap<Name, Property>();
+ }
+ return this.annotations.put(annotation.getName(), annotation);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/DoubleContributionMergePlan.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/DoubleContributionMergePlan.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/DoubleContributionMergePlan.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,115 @@
+/*
+ * 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.connector.federation.merge;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class DoubleContributionMergePlan extends MergePlan {
+
+ private static final long serialVersionUID = 1L;
+ private final Contribution contribution1;
+ private final Contribution contribution2;
+
+ /**
+ * @param contribution1 the first contribution for this merge plan
+ * @param contribution2 the second contribution for this merge plan
+ */
+ public DoubleContributionMergePlan( Contribution contribution1,
+ Contribution contribution2 ) {
+ assert contribution1 != null;
+ assert contribution2 != null;
+ this.contribution1 = contribution1;
+ this.contribution2 = contribution2;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.connector.federation.merge.MergePlan#getContributionCount()
+ */
+ @Override
+ public int getContributionCount() {
+ return 2;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.merge.MergePlan#getContributionFrom(java.lang.String)
+ */
+ @Override
+ public Contribution getContributionFrom( String sourceName ) {
+ if (contribution1.getSourceName().equals(sourceName)) return contribution1;
+ if (contribution2.getSourceName().equals(sourceName)) return contribution2;
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator<Contribution> iterator() {
+ return new Iterator<Contribution>() {
+ private int next = 2;
+
+ public boolean hasNext() {
+ return next > 0;
+ }
+
+ @SuppressWarnings( "synthetic-access" )
+ public Contribution next() {
+ if (next == 2) {
+ next = 1;
+ return contribution2;
+ }
+ if (next == 1) {
+ next = 0;
+ return contribution1;
+ }
+ throw new NoSuchElementException();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.merge.MergePlan#isSource(java.lang.String)
+ */
+ @Override
+ public boolean isSource( String sourceName ) {
+ return contribution1.getSourceName().equals(sourceName) ||
contribution2.getSourceName().equals(sourceName);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FederatedNode.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FederatedNode.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FederatedNode.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,140 @@
+/*
+ * 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.connector.federation.merge;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.UUID;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Property;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public interface FederatedNode {
+ /**
+ * Get the unique identifier for this federated node.
+ *
+ * @return the UUID; never null
+ */
+ UUID getUuid();
+
+ /**
+ * Get the name of this node.
+ *
+ * @return the node name; never null
+ */
+ Name getName();
+
+ /**
+ * Get the property with the given name.
+ *
+ * @param propertyName the property name
+ * @return the property, or null if the property does not exist
+ * @throws IllegalArgumentException if the name is null
+ */
+ Property getProperty( Name propertyName );
+
+ /**
+ * Get the number of properties on this node. This value is technically an estimate,
as it may not exactly match the number of
+ * properties returned by {@link #getProperties()} or {@link #getPropertyNames()}.
+ *
+ * @return the approximate number of properties.
+ */
+ int getPropertyCount();
+
+ /**
+ * Get the properties. This method returns a consistent set of properties at the
moment this method is called, and is not
+ * affected by additions or change to the properties. In other words, it is safe for
concurrent operations and is not a
+ * fail-fast iterator.
+ *
+ * @return the properties on this node via an immutable iterator
+ */
+ Iterator<Property> getProperties();
+
+ /**
+ * Get the names of the properties for this node. This method returns a consistent
set of names at the moment this method is
+ * called, and is not affected by additions or change to the properties. In other
words, it is safe for concurrent operations
+ * and is not a fail-fast iterator.
+ *
+ * @return the property names via an immutable iterator
+ */
+ Iterator<Name> getPropertyNames();
+
+ /**
+ * Set the property if it is not already set.
+ *
+ * @param property the property
+ * @return the existing property, or null if there was no property and the supplied
property was set
+ * @throws IllegalArgumentException if the property is null
+ */
+ Property setPropertyIfAbsent( Property property );
+
+ /**
+ * Set the supplied properties. This method will overwrite any existing properties
with the new properties if they have the
+ * same {@link Property#getName() property name}. This method ignores any null
property references, and does nothing if there
+ * are no properties supplied.
+ *
+ * @param properties the properties that should be set
+ */
+ void setProperties( Property... properties );
+
+ /**
+ * Set the supplied properties. This method will overwrite any existing properties
with the new properties if they have the
+ * same {@link Property#getName() property name}. This method ignores any null
property references, and does nothing if there
+ * are no properties supplied.
+ *
+ * @param properties the properties that should be set
+ */
+ void setProperties( Iterable<Property> properties );
+
+ /**
+ * Replace all existing properties with the supplied properties. This method ignores
any null property references, and does
+ * nothing if there are no properties supplied.
+ *
+ * @param properties the properties that should be set
+ */
+ void setAllProperties( Property... properties );
+
+ /**
+ * Replace all existing properties with the supplied properties. This method ignores
any null property references, and does
+ * nothing if there are no properties supplied.
+ *
+ * @param properties the properties that should replace the existing properties
+ */
+ void setAllProperties( Iterable<Property> properties );
+
+ /**
+ * Remove all properties, except for the {@link #getName() name} and {@link
#getUuid() identifier}.
+ */
+ void removeAllProperties();
+
+ /**
+ * Get the sources that have contributed information to this node.
+ *
+ * @return the names of the sources that have contributed content to this node.
+ */
+ Set<String> getContributingSources();
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,228 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import java.io.InvalidClassException;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.connector.federation.contribution.EmptyContribution;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Property;
+
+/**
+ * This class represents the details about how information from different sources are
merged into a single federated node.
+ * <p>
+ * A merge plan basically consists of the individual contribution from each source and
the information about how these
+ * contributions were merged into the single federated node.
+ * </p>
+ * <p>
+ * Merge plans are designed to be {@link Serializable serializable}, as they are
persisted on the federated node and deserialized
+ * to assist in the management of the federated node.
+ * </p>
+ *
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public abstract class MergePlan implements Serializable, Iterable<Contribution> {
+
+ public static MergePlan create( Contribution... contributions ) {
+ ArgCheck.isNotNull(contributions, "contributions");
+ switch (contributions.length) {
+ case 1:
+ return new SingleContributionMergePlan(contributions[0]);
+ case 2:
+ return new DoubleContributionMergePlan(contributions[0],
contributions[1]);
+ case 3:
+ return new TripleContributionMergePlan(contributions[0],
contributions[1], contributions[2]);
+ default:
+ return new MultipleContributionMergePlan(contributions);
+ }
+ }
+
+ public static MergePlan addContribution( MergePlan plan,
+ Contribution contribution ) {
+ if (plan instanceof MultipleContributionMergePlan) {
+ MultipleContributionMergePlan multiPlan =
(MultipleContributionMergePlan)plan;
+ multiPlan.addContribution(contribution);
+ return multiPlan;
+ }
+ if (plan instanceof SingleContributionMergePlan) {
+ MergePlan newPlan = new DoubleContributionMergePlan(plan.iterator().next(),
contribution);
+ newPlan.setAnnotations(plan.getAnnotations());
+ }
+ if (plan instanceof DoubleContributionMergePlan) {
+ Iterator<Contribution> iterator = plan.iterator();
+ MergePlan newPlan = new TripleContributionMergePlan(iterator.next(),
iterator.next(), contribution);
+ newPlan.setAnnotations(plan.getAnnotations());
+ }
+ MultipleContributionMergePlan newPlan = new MultipleContributionMergePlan();
+ for (Contribution existingContribution : plan) {
+ newPlan.addContribution(existingContribution);
+ }
+ newPlan.addContribution(contribution);
+ newPlan.setAnnotations(plan.getAnnotations());
+ return newPlan;
+ }
+
+ /**
+ * Define the earliest version of this class that is supported. The Java runtime,
upon deserialization, compares the
+ * serialized object's version to this, and if less than this version will throw
a {@link InvalidClassException}. If, however,
+ * the serialized object's version is compatible with this class, it will be
deserialized successfully.
+ * <p>
+ * <a
href="http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/v...
documentation</a> describes
+ * the following changes can be made without negatively affecting the deserialization
of older versions:
+ * <ul>
+ * <li>Adding fields - When the class being reconstituted has a field that does
not occur in the stream, that field in the
+ * object will be initialized to the default value for its type. If class-specific
initialization is needed, the class may
+ * provide a readObject method that can initialize the field to nondefault
values.</i>
+ * <li>Adding classes - The stream will contain the type hierarchy of each
object in the stream. Comparing this hierarchy in
+ * the stream with the current class can detect additional classes. Since there is no
information in the stream from which to
+ * initialize the object, the class's fields will be initialized to the default
values.</i>
+ * <li>Removing classes - Comparing the class hierarchy in the stream with that
of the current class can detect that a class
+ * has been deleted. In this case, the fields and objects corresponding to that class
are read from the stream. Primitive
+ * fields are discarded, but the objects referenced by the deleted class are created,
since they may be referred to later in
+ * the stream. They will be garbage-collected when the stream is garbage-collected or
reset.</i>
+ * <li>Adding writeObject/readObject methods - If the version reading the
stream has these methods then readObject is
+ * expected, as usual, to read the required data written to the stream by the default
serialization. It should call
+ * defaultReadObject first before reading any optional data. The writeObject method
is expected as usual to call
+ * defaultWriteObject to write the required data and then may write optional
data.</i>
+ * <li>Removing writeObject/readObject methods - If the class reading the
stream does not have these methods, the required
+ * data will be read by default serialization, and the optional data will be
discarded.</i>
+ * <li>Adding java.io.Serializable - This is equivalent to adding types. There
will be no values in the stream for this class
+ * so its fields will be initialized to default values. The support for subclassing
nonserializable classes requires that the
+ * class's supertype have a no-arg constructor and the class itself will be
initialized to default values. If the no-arg
+ * constructor is not available, the InvalidClassException is thrown.</i>
+ * <li>Changing the access to a field - The access modifiers public, package,
protected, and private have no effect on the
+ * ability of serialization to assign values to the fields.</i>
+ * <li>Changing a field from static to nonstatic or transient to nontransient -
When relying on default serialization to
+ * compute the serializable fields, this change is equivalent to adding a field to
the class. The new field will be written to
+ * the stream but earlier classes will ignore the value since serialization will not
assign values to static or transient
+ * fields.</i>
+ * </ul>
+ * All other kinds of modifications should be avoided.
+ * </p>
+ */
+ private static final long serialVersionUID = 1L;
+
+ private Map<Name, Property> annotations = null;
+ private DateTime expirationTimeInUtc;
+
+ /**
+ * Create an empty merge plan
+ */
+ protected MergePlan() {
+ }
+
+ /**
+ * Determine whether this merge plan has expired given the supplied current time. The
{@link #getExpirationTimeInUtc()
+ * expiration time} is the earliest time that any of the {@link
#getContributionFrom(String) contributions}
+ * {@link Contribution#getExpirationTimeInUtc()}.
+ *
+ * @param utcTime the current time expressed in UTC; may not be null
+ * @return true if at least one contribution has expired, or false otherwise
+ */
+ public boolean isExpired( DateTime utcTime ) {
+ assert utcTime != null;
+ assert utcTime.toUtcTimeZone().equals(utcTime); // check that it is passed UTC
time
+ return !expirationTimeInUtc.isAfter(utcTime);
+ }
+
+ /**
+ * Get the expiration time (in UTC) that is the earliest time that any of the {@link
#getContributionFrom(String)
+ * contributions} {@link Contribution#getExpirationTimeInUtc()}.
+ *
+ * @return the expiration time in UTC, or null if there is no known expiration time
+ */
+ public DateTime getExpirationTimeInUtc() {
+ return expirationTimeInUtc;
+ }
+
+ /**
+ * Get the contribution from the source with the supplied name. Note that
contributions always include sources that contribute
+ * information and sources that contribute no information. If a source is not
included in this list, its contributions are
+ * <i>unknown</i>; that is, it is unknown whether that source does or
does not contribute to the node.
+ *
+ * @param sourceName the name of the source
+ * @return the contribution, or null if the contribution of the source is unknown
+ */
+ public abstract Contribution getContributionFrom( String sourceName );
+
+ /**
+ * Return whether the named source was consulted for a contribution.
+ *
+ * @param sourceName the name of the source
+ * @return true if the source has some {@link Contribution contribution} (even if it
is an {@link EmptyContribution})
+ */
+ public abstract boolean isSource( String sourceName );
+
+ public abstract int getContributionCount();
+
+ /**
+ * Get the plan annotation property with the given name. Plan annotations are custom
properties that may be set by
+ * MergeProcessor implementations to store custom properties on the plan. This method
does nothing if the supplied name is
+ * null
+ *
+ * @param name the name of the annotation
+ * @return the existing annotation, or null if there is no annotation with the
supplied name
+ * @see #setAnnotation(Property)
+ */
+ public Property getAnnotation( Name name ) {
+ if (name == null) return null;
+ if (this.annotations == null) return null;
+ return this.annotations.get(name);
+ }
+
+ /**
+ * Set the plan annotation property. This method replaces and returns any existing
annotation property with the same name.
+ * This method also returns immediately if the supplied annotation is null.
+ *
+ * @param annotation the new annotation
+ * @return the previous annotation property with the same name, or null if there was
no previous annotation property for the
+ * name
+ * @see #getAnnotation(Name)
+ */
+ public Property setAnnotation( Property annotation ) {
+ if (annotation == null) return null;
+ if (this.annotations == null) {
+ this.annotations = new HashMap<Name, Property>();
+ }
+ return this.annotations.put(annotation.getName(), annotation);
+ }
+
+ protected void setAnnotations( Map<Name, Property> annotations ) {
+ this.annotations = annotations;
+ }
+
+ /**
+ * @return annotations
+ */
+ protected Map<Name, Property> getAnnotations() {
+ return annotations;
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlan.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlan.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlan.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,116 @@
+/*
+ * 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.connector.federation.merge;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class MultipleContributionMergePlan extends MergePlan {
+
+ private static final long serialVersionUID = 1L;
+ private final List<Contribution> contributions;
+
+ /**
+ * @param contributions the contributions for this merge plan
+ */
+ public MultipleContributionMergePlan( Contribution... contributions ) {
+ assert contributions != null;
+ this.contributions = new CopyOnWriteArrayList<Contribution>();
+ for (int i = 0; i != contributions.length; ++i) {
+ assert contributions[i] != null;
+ this.contributions.add(contributions[i]);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.connector.federation.merge.MergePlan#getContributionCount()
+ */
+ @Override
+ public int getContributionCount() {
+ return contributions.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.merge.MergePlan#getContributionFrom(java.lang.String)
+ */
+ @Override
+ public Contribution getContributionFrom( String sourceName ) {
+ for (Contribution contribution : contributions) {
+ if (contribution.getSourceName().equals(sourceName)) return contribution;
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator<Contribution> iterator() {
+ final Iterator<Contribution> iterator = this.contributions.iterator();
+ return new Iterator<Contribution>() {
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ public Contribution next() {
+ return iterator.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.merge.MergePlan#isSource(java.lang.String)
+ */
+ @Override
+ public boolean isSource( String sourceName ) {
+ for (Contribution contribution : contributions) {
+ if (contribution.getSourceName().equals(sourceName)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param contribution
+ */
+ public void addContribution( Contribution contribution ) {
+ this.contributions.add(contribution);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SingleContributionMergePlan.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SingleContributionMergePlan.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/SingleContributionMergePlan.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,104 @@
+/*
+ * 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.connector.federation.merge;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class SingleContributionMergePlan extends MergePlan {
+
+ private static final long serialVersionUID = 1L;
+ private final Contribution contribution;
+
+ /**
+ * @param contribution the contribution for this merge plan
+ */
+ public SingleContributionMergePlan( Contribution contribution ) {
+ assert contribution != null;
+ this.contribution = contribution;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.connector.federation.merge.MergePlan#getContributionCount()
+ */
+ @Override
+ public int getContributionCount() {
+ return 1;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.merge.MergePlan#getContributionFrom(java.lang.String)
+ */
+ @Override
+ public Contribution getContributionFrom( String sourceName ) {
+ return isSource(sourceName) ? contribution : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator<Contribution> iterator() {
+ return new Iterator<Contribution>() {
+ private boolean next = true;
+
+ public boolean hasNext() {
+ return next;
+ }
+
+ @SuppressWarnings( "synthetic-access" )
+ public Contribution next() {
+ if (next) {
+ next = false;
+ return contribution;
+ }
+ throw new NoSuchElementException();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.merge.MergePlan#isSource(java.lang.String)
+ */
+ @Override
+ public boolean isSource( String sourceName ) {
+ return contribution.getSourceName().equals(sourceName);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/TripleContributionMergePlan.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/TripleContributionMergePlan.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/TripleContributionMergePlan.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,126 @@
+/*
+ * 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.connector.federation.merge;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class TripleContributionMergePlan extends MergePlan {
+
+ private static final long serialVersionUID = 1L;
+ private final Contribution contribution1;
+ private final Contribution contribution2;
+ private final Contribution contribution3;
+
+ /**
+ * @param contribution1 the first contribution for this merge plan
+ * @param contribution2 the second contribution for this merge plan
+ * @param contribution3 the third contribution for this merge plan
+ */
+ public TripleContributionMergePlan( Contribution contribution1,
+ Contribution contribution2,
+ Contribution contribution3 ) {
+ assert contribution1 != null;
+ assert contribution2 != null;
+ assert contribution3 != null;
+ this.contribution1 = contribution1;
+ this.contribution2 = contribution2;
+ this.contribution3 = contribution3;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.connector.federation.merge.MergePlan#getContributionCount()
+ */
+ @Override
+ public int getContributionCount() {
+ return 3;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.merge.MergePlan#getContributionFrom(java.lang.String)
+ */
+ @Override
+ public Contribution getContributionFrom( String sourceName ) {
+ if (contribution1.getSourceName().equals(sourceName)) return contribution1;
+ if (contribution2.getSourceName().equals(sourceName)) return contribution2;
+ if (contribution3.getSourceName().equals(sourceName)) return contribution3;
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator<Contribution> iterator() {
+ return new Iterator<Contribution>() {
+ private int next = 3;
+
+ public boolean hasNext() {
+ return next > 0;
+ }
+
+ @SuppressWarnings( "synthetic-access" )
+ public Contribution next() {
+ if (next == 3) {
+ next = 2;
+ return contribution3;
+ }
+ if (next == 2) {
+ next = 1;
+ return contribution2;
+ }
+ if (next == 1) {
+ next = 0;
+ return contribution1;
+ }
+ throw new NoSuchElementException();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.merge.MergePlan#isSource(java.lang.String)
+ */
+ @Override
+ public boolean isSource( String sourceName ) {
+ return contribution1.getSourceName().equals(sourceName) ||
contribution2.getSourceName().equals(sourceName)
+ || contribution3.getSourceName().equals(sourceName);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
===================================================================
---
trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,38 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2008, Red Hat Middleware LLC, and individual contributors
+# as indicated by the @author tags. See the copyright.txt file in the
+# distribution for a full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+#
+requiredNodeDoesNotExistRelativeToNode = The required node {0} does not exist relative to
{1}
+propertyIsRequired = The {0} property is required but has no value
+
+interruptedWhileUsingFederationConfigurationRepository = Interrupted while using
federation configuration repository "{0}"
+unableToFindFederatedRepositoryInJndi = Unable to find a FederatedRepository instance in
JNDI under "{1}" when creating connection to federated source "{0}"
+unableToFindExecutionContextFactoryInJndi = Unable to find an ExecutionContextFactory
instance in JNDI under "{1}" when creating connection to federated source
"{0}"
+unableToCreateExecutionContext = Unable to create ExecutionContext for connection to
federated source "{0}" when using factory in JNDI under "{1}" and
security domain "{2}"
+unableToFindRepositoryConnectionFactoriesInJndi = Unable to find an
RepositoryConnectionFactories instance in JNDI under "{1}" when creating
connection to federated source "{0}"
+noRepositoryConnectionFactories = No RepositoryConnectionFactories instance was specified
directly or indirectly found in JNDI when creating connection to federated source
"{0}"
+federatedRepositoryCannotBeFound = The federated repository "{0}" cannot be
found
+unableToFindRepositorySourceByName = Unable to find the repository source
"{0}"
+unableToCreateConnectionToFederatedRepository = Unable to connect to the repository
"{0}". Check the Federation Service configuration.
+unableToAuthenticateConnectionToFederatedRepository = Unable to authenticate
"{1}" for repository "{0}"
+repositoryHasBeenShutDown = The "{0}" repository has been shut down and may no
longer be used.
+repositoryPathInFederationBindingIsNotAbsolute = The repository path in a federation
binding must be absolute, but was "{0}"
+errorReadingMergePlan = Error while reading merge plan for {0}
+errorAddingProjectionRuleParseMethod = Error while adding a parsing method for a
federation projection rule
\ No newline at end of file
Added:
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryConnectionTest.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryConnectionTest.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryConnectionTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,132 @@
+/*
+ * 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.connector.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import java.util.concurrent.TimeUnit;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.executor.CommandExecutor;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedRepositoryConnectionTest {
+
+ private FederatedRepositoryConnection connection;
+ private String sourceName;
+ @Mock
+ private FederatedRepositorySource source;
+ @Mock
+ private FederatedRepository repository;
+
+ @Before
+ public void beforeEach() {
+ MockitoAnnotations.initMocks(this);
+ sourceName = "Source X";
+ stub(source.getName()).toReturn(sourceName);
+ connection = new FederatedRepositoryConnection(repository, sourceName);
+ }
+
+ @Test
+ public void shouldHaveRepository() {
+ assertThat(connection.getRepository(), is(repository));
+ }
+
+ @Test
+ public void shouldHaveNoXaResource() {
+ assertThat(connection.getXAResource(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCheckRepositoryAdminsStartedStateForPingResult() {
+ stub(repository.isRunning()).toReturn(true);
+ assertThat(connection.ping(1, TimeUnit.SECONDS), is(true));
+ verify(repository, times(1)).isRunning();
+ }
+
+ @Test( expected = RepositorySourceException.class )
+ public void shouldFailExecutionIfRepositoryAdminsIsNotStarted() throws Exception {
+ stub(repository.isRunning()).toReturn(false);
+ ExecutionEnvironment env = mock(ExecutionEnvironment.class);
+ GraphCommand command = mock(GraphCommand.class);
+ connection.execute(env, command);
+ }
+
+ @Test
+ public void shouldReturnImmediatelyWhenExecutingNullOrEmptyCommandArray() throws
Exception {
+ stub(repository.isRunning()).toReturn(true);
+ ExecutionEnvironment env = mock(ExecutionEnvironment.class);
+ connection.execute(env, (GraphCommand[])null);
+ verify(repository, times(1)).isRunning();
+ connection.execute(env, new GraphCommand[0]);
+ verify(repository, times(2)).isRunning();
+ }
+
+ @Test
+ public void shouldSkipNullCommandReferencesWhenExecuting() throws Exception {
+ stub(repository.isRunning()).toReturn(true);
+ ExecutionEnvironment env = mock(ExecutionEnvironment.class);
+ CommandExecutor executor = mock(CommandExecutor.class);
+ stub(repository.getExecutor(env, sourceName)).toReturn(executor);
+ connection.execute(env, new GraphCommand[] {null, null, null});
+ verify(repository, times(1)).isRunning();
+ }
+
+ @Test
+ public void shouldAddListenerToRepositoryWhenSetOnConnection() {
+ // Old listener is no-op, so it is not removed from repository ...
+ RepositorySourceListener listener = mock(RepositorySourceListener.class);
+ connection.setListener(listener);
+ verify(repository, times(1)).addListener(listener);
+
+ // Old listener is NOT no-op, so it is removed from repository ...
+ RepositorySourceListener listener2 = mock(RepositorySourceListener.class);
+ connection.setListener(listener2);
+ verify(repository, times(1)).removeListener(listener);
+ verify(repository, times(1)).addListener(listener2);
+ }
+
+ @Test
+ public void shouldRemoveListenerFromRepositoryWhenConnectionIsClosed() {
+ // Old listener is NOT no-op, so it is removed from repository ...
+ RepositorySourceListener listener2 = mock(RepositorySourceListener.class);
+ connection.setListener(listener2);
+ verify(repository, times(1)).addListener(listener2);
+
+ // Closing connection will remove listener ...
+ connection.close();
+ verify(repository, times(1)).removeListener(listener2);
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,309 @@
+/*
+ * 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.connector.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import org.jboss.dna.spi.ExecutionContextFactory;
+import org.jboss.dna.spi.graph.connection.BasicExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactories;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.jboss.dna.spi.graph.connection.SimpleRepository;
+import org.jboss.dna.spi.graph.connection.SimpleRepositorySource;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedRepositorySourceTest {
+
+ private FederatedRepositorySource source;
+ private String sourceName;
+ private String repositoryName;
+ private String username;
+ private String credentials;
+ private String executionContextFactoryJndiName;
+ private String connectionFactoriesJndiName;
+ private String configurationSourceName;
+ private String securityDomain;
+ private SimpleRepository configRepository;
+ private SimpleRepositorySource configRepositorySource;
+ private ExecutionEnvironment env;
+ @Mock
+ private FederatedRepositoryConnection connection;
+ @Mock
+ private Context jndiContext;
+ @Mock
+ private RepositoryConnectionFactories connectionFactories;
+ @Mock
+ private ExecutionContextFactory executionContextFactory;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ env = new BasicExecutionEnvironment();
+ env.getNamespaceRegistry().register("dna",
"http://www.jboss.org/dna");
+ executionContextFactoryJndiName = "context factory jndi name";
+ connectionFactoriesJndiName = "connection factories jndi name";
+ configurationSourceName = "configuration source name";
+ repositoryName = "Test Repository";
+ securityDomain = "security domain";
+ source = new FederatedRepositorySource(repositoryName);
+ sourceName = "federated source";
+ username = "valid username";
+ credentials = "valid password";
+ source.setName(sourceName);
+ source.setUsername(username);
+ source.setPassword(credentials);
+ source.setConfigurationSourceName(configurationSourceName);
+ source.setConfigurationSourceProjectionRules(new String[]
{"/dna:system/dna:federation/ => /dna:repositories/Test Repository"});
+ source.setConnectionFactoriesJndiName(connectionFactoriesJndiName);
+ source.setExecutionContextFactoryJndiName(executionContextFactoryJndiName);
+ source.setContext(jndiContext);
+ source.setSecurityDomain(securityDomain);
+ configRepository = new SimpleRepository("Configuration Repository");
+ configRepository.setProperty(env, "/dna:repositories/Test Repository",
"dna:timeToExpire", "100000");
+ configRepository.setProperty(env, "/dna:repositories/Test Repository",
"dna:timeToCache", "100000");
+ configRepository.setProperty(env, "/dna:repositories/Test
Repository/dna:cache", "dna:projectionRules", "/ => /");
+ configRepository.setProperty(env,
+ "/dna:repositories/Test
Repository/dna:projections/source 1/",
+ "dna:projectionRules",
+ "/ => /s1");
+ configRepository.setProperty(env,
+ "/dna:repositories/Test
Repository/dna:projections/source 2/",
+ "dna:projectionRules",
+ "/ => /s1");
+ configRepositorySource = new SimpleRepositorySource();
+ configRepositorySource.setRepositoryName(configRepository.getRepositoryName());
+ configRepositorySource.setName(configurationSourceName);
+
stub(connectionFactories.getConnectionFactory(configurationSourceName)).toReturn(configRepositorySource);
+
stub(jndiContext.lookup(executionContextFactoryJndiName)).toReturn(executionContextFactory);
+
stub(jndiContext.lookup(connectionFactoriesJndiName)).toReturn(connectionFactories);
+ stub(executionContextFactory.create(eq(securityDomain),
anyCallbackHandler())).toReturn(env);
+ }
+
+ protected static CallbackHandler anyCallbackHandler() {
+ return argThat(new ArgumentMatcher<CallbackHandler>() {
+ @Override
+ public boolean matches( Object callback ) {
+ return callback != null;
+ }
+ });
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ SimpleRepository.shutdownAll();
+ }
+
+ @Test
+ public void shouldCreateConnectionsByAuthenticateUsingFederationRepository() throws
Exception {
+ connection = (FederatedRepositoryConnection)source.getConnection();
+ assertThat(connection, is(sameInstance(connection)));
+ }
+
+ @Test( expected = RepositorySourceException.class )
+ public void shouldNotCreateConnectionWhenAuthenticationFails() throws Exception {
+ // Stub the execution context factory to throw a LoginException to simulate
failed authentication
+ stub(executionContextFactory.create(eq(securityDomain),
anyCallbackHandler())).toThrow(new LoginException());
+ source.getConnection();
+ }
+
+ @Test( expected = NullPointerException.class )
+ public void
shouldPropogateAllExceptionsExceptLoginExceptionThrownFromExecutionContextFactory() throws
Exception {
+ // Stub the execution context factory to throw a LoginException to simulate
failed authentication
+ stub(executionContextFactory.create(eq(securityDomain),
anyCallbackHandler())).toThrow(new NullPointerException());
+ source.getConnection();
+ }
+
+ @Test
+ public void shouldHaveNameSuppliedInConstructor() {
+ source = new FederatedRepositorySource(repositoryName);
+ assertThat(source.getRepositoryName(), is(repositoryName));
+ }
+
+ @Test
+ public void shouldHaveNullSourceNameUponConstruction() {
+ source = new FederatedRepositorySource(repositoryName);
+ assertThat(source.getName(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowSettingName() {
+ source.setName("Something");
+ assertThat(source.getName(), is("Something"));
+ source.setName("another name");
+ assertThat(source.getName(), is("another name"));
+ }
+
+ @Test
+ public void shouldAllowSettingNameToNull() {
+ source.setName("some name");
+ source.setName(null);
+ assertThat(source.getName(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowSettingUsername() {
+ source.setUsername("Something");
+ assertThat(source.getUsername(), is("Something"));
+ source.setUsername("another name");
+ assertThat(source.getUsername(), is("another name"));
+ }
+
+ @Test
+ public void shouldAllowSettingUsernameToNull() {
+ source.setUsername("some name");
+ source.setUsername(null);
+ assertThat(source.getUsername(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowSettingCredentials() {
+ source.setPassword("Something");
+ assertThat(source.getPassword(), is("Something"));
+ source.setPassword("another name");
+ assertThat(source.getPassword(), is("another name"));
+ }
+
+ @Test
+ public void shouldAllowSettingCredentialsToNull() {
+ source.setPassword("some name");
+ source.setPassword(null);
+ assertThat(source.getPassword(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldHaveDefaultRetryLimit() {
+ assertThat(source.getRetryLimit(),
is(FederatedRepositorySource.DEFAULT_RETRY_LIMIT));
+ }
+
+ @Test
+ public void shouldSetRetryLimitToZeroWhenSetWithNonPositiveValue() {
+ source.setRetryLimit(0);
+ assertThat(source.getRetryLimit(), is(0));
+ source.setRetryLimit(-1);
+ assertThat(source.getRetryLimit(), is(0));
+ source.setRetryLimit(-100);
+ assertThat(source.getRetryLimit(), is(0));
+ }
+
+ @Test
+ public void shouldAllowRetryLimitToBeSet() {
+ for (int i = 0; i != 100; ++i) {
+ source.setRetryLimit(i);
+ assertThat(source.getRetryLimit(), is(i));
+ }
+ }
+
+ @Test
+ public void shouldCreateJndiReferenceAndRecreatedObjectFromReference() throws
Exception {
+ int retryLimit = 100;
+ source.setPassword(credentials);
+ source.setUsername(username);
+ source.setRetryLimit(retryLimit);
+ source.setName("Some source");
+ source.setConfigurationSourceName("config source");
+ source.setConfigurationSourceProjectionRules(new String[] {"/dna:system
=> /a/b/c"});
+ source.setConnectionFactoriesJndiName("connection factories jndi
name");
+ source.setRepositoryJndiName("repository jndi name");
+ source.setExecutionContextFactoryJndiName("env jndi name");
+
+ Reference ref = source.getReference();
+ assertThat(ref.getClassName(), is(FederatedRepositorySource.class.getName()));
+ assertThat(ref.getFactoryClassName(),
is(FederatedRepositorySource.NamingContextObjectFactory.class.getName()));
+
+ Map<String, Object> refAttributes = new HashMap<String, Object>();
+ Enumeration<RefAddr> enumeration = ref.getAll();
+ while (enumeration.hasMoreElements()) {
+ RefAddr addr = enumeration.nextElement();
+ refAttributes.put(addr.getType(), addr.getContent());
+ }
+
+ assertThat((String)refAttributes.remove(FederatedRepositorySource.USERNAME),
is(username));
+ assertThat((String)refAttributes.remove(FederatedRepositorySource.PASSWORD),
is(credentials));
+ assertThat((String)refAttributes.remove(FederatedRepositorySource.SOURCE_NAME),
is(source.getName()));
+
assertThat((String)refAttributes.remove(FederatedRepositorySource.REPOSITORY_NAME),
is(repositoryName));
+ assertThat((String)refAttributes.remove(FederatedRepositorySource.RETRY_LIMIT),
is(Integer.toString(retryLimit)));
+
assertThat((String)refAttributes.remove(FederatedRepositorySource.CONFIGURATION_SOURCE_NAME),
+ is(source.getConfigurationSourceName()));
+
assertThat((String)refAttributes.remove(FederatedRepositorySource.CONFIGURATION_SOURCE_PROJECTION_RULES),
+ is("/dna:system => /a/b/c"));
+
assertThat((String)refAttributes.remove(FederatedRepositorySource.CONNECTION_FACTORIES_JNDI_NAME),
+ is(source.getConnectionFactoriesJndiName()));
+
assertThat((String)refAttributes.remove(FederatedRepositorySource.EXECUTION_CONTEXT_FACTORY_JNDI_NAME),
+ is(source.getExecutionContextFactoryJndiName()));
+
assertThat((String)refAttributes.remove(FederatedRepositorySource.REPOSITORY_JNDI_NAME),
+ is(source.getRepositoryJndiName()));
+
assertThat((String)refAttributes.remove(FederatedRepositorySource.SECURITY_DOMAIN),
is(securityDomain));
+ assertThat(refAttributes.isEmpty(), is(true));
+
+ // Recreate the object, use a newly constructed source ...
+ FederatedRepositorySource.NamingContextObjectFactory factory = new
FederatedRepositorySource.NamingContextObjectFactory();
+ Name name = mock(Name.class);
+ Context context = mock(Context.class);
+ Hashtable<?, ?> env = new Hashtable<Object, Object>();
+ FederatedRepositorySource recoveredSource =
(FederatedRepositorySource)factory.getObjectInstance(ref, name, context, env);
+ assertThat(recoveredSource, is(notNullValue()));
+
+ assertThat(recoveredSource.getName(), is(source.getName()));
+ assertThat(recoveredSource.getUsername(), is(source.getUsername()));
+ assertThat(recoveredSource.getPassword(), is(source.getPassword()));
+ assertThat(recoveredSource.getRepositoryName(), is(source.getRepositoryName()));
+ assertThat(recoveredSource.getRetryLimit(), is(source.getRetryLimit()));
+ assertThat(recoveredSource.getConfigurationSourceName(),
is(source.getConfigurationSourceName()));
+ assertThat(recoveredSource.getConfigurationSourceProjectionRules(),
is(source.getConfigurationSourceProjectionRules()));
+ assertThat(recoveredSource.getConnectionFactoriesJndiName(),
is(source.getConnectionFactoriesJndiName()));
+ assertThat(recoveredSource.getExecutionContextFactoryJndiName(),
is(source.getExecutionContextFactoryJndiName()));
+ assertThat(recoveredSource.getRepositoryJndiName(),
is(source.getRepositoryJndiName()));
+ assertThat(recoveredSource.getSecurityDomain(), is(source.getSecurityDomain()));
+
+ assertThat(recoveredSource.equals(source), is(true));
+ assertThat(source.equals(recoveredSource), is(true));
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryTest.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryTest.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,146 @@
+/*
+ * 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.connector.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import org.jboss.dna.spi.graph.connection.BasicExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactories;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedRepositoryTest {
+
+ private ExecutionEnvironment env;
+ private FederatedRepository repository;
+ @Mock
+ private FederatedRepositoryConfig config;
+ @Mock
+ private RepositorySourceListener listener1;
+ @Mock
+ private RepositorySourceListener listener2;
+ @Mock
+ private RepositoryConnectionFactories connectionFactories;
+
+ // private BasicRepositoryConnectionPool connectionPool;
+
+ @Before
+ public void beforeEach() {
+ MockitoAnnotations.initMocks(this);
+ env = new BasicExecutionEnvironment();
+ repository = new FederatedRepository(env, connectionFactories, config);
+ }
+
+ @Test
+ public void shouldHaveNoNameUponCreation() {
+ assertThat(repository.getName(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldHaveNoListenersUponCreation() {
+ assertThat(repository.getListeners(), is(notNullValue()));
+ assertThat(repository.getListeners().isEmpty(), is(true));
+ }
+
+ @Test
+ public void shouldNotAddNullListener() {
+ assertThat(repository.addListener(null), is(false));
+ }
+
+ @Test
+ public void shouldNotAddListenerIfAlreadyInList() {
+ assertThat(repository.getListeners().size(), is(0));
+ assertThat(repository.addListener(listener1), is(true));
+ assertThat(repository.getListeners().size(), is(1));
+ assertThat(repository.addListener(listener1), is(false));
+ assertThat(repository.getListeners().size(), is(1));
+ }
+
+ @Test
+ public void shouldAddDifferentListeners() {
+ assertThat(repository.getListeners().size(), is(0));
+ assertThat(repository.addListener(listener1), is(true));
+ assertThat(repository.getListeners().size(), is(1));
+ assertThat(repository.addListener(listener2), is(true));
+ assertThat(repository.getListeners().size(), is(2));
+ assertThat(repository.getListeners(), hasItems(listener1, listener2));
+ assertThat(repository.getListeners().get(0), is(sameInstance(listener1)));
+ assertThat(repository.getListeners().get(1), is(sameInstance(listener2)));
+ }
+
+ @Test
+ public void shouldAllowReorderingOfListeners() {
+ assertThat(repository.getListeners().size(), is(0));
+ assertThat(repository.addListener(listener1), is(true));
+ assertThat(repository.addListener(listener2), is(true));
+ assertThat(repository.getListeners().size(), is(2));
+ assertThat(repository.getListeners(), hasItems(listener1, listener2));
+ repository.getListeners().remove(0);
+ repository.getListeners().add(1, listener1);
+ assertThat(repository.getListeners(), hasItems(listener2, listener1));
+ assertThat(repository.getListeners().get(0), is(sameInstance(listener2)));
+ assertThat(repository.getListeners().get(1), is(sameInstance(listener1)));
+ }
+
+ @Test
+ public void shouldAllowRemovalOfListeners() {
+ assertThat(repository.getListeners().size(), is(0));
+ assertThat(repository.addListener(listener1), is(true));
+ assertThat(repository.addListener(listener2), is(true));
+ assertThat(repository.getListeners(), hasItems(listener1, listener2));
+ assertThat(repository.removeListener(listener1), is(true));
+ assertThat(repository.getListeners(), hasItems(listener2));
+ assertThat(repository.removeListener(listener2), is(true));
+ assertThat(repository.getListeners(), hasItems(new RepositorySourceListener[]
{}));
+ }
+
+ @Test
+ public void shouldNotRemoveListenerThatIsNotAlreadyRegistered() {
+ assertThat(repository.getListeners().size(), is(0));
+ assertThat(repository.addListener(listener1), is(true));
+ assertThat(repository.getListeners().size(), is(1));
+ assertThat(repository.removeListener(listener2), is(false));
+ }
+
+ @Test
+ public void shouldHaveConfigurationAfterInitialization() {
+ assertThat(repository.getConfiguration(), is(notNullValue()));
+ assertThat(repository.getConfiguration(), is(sameInstance(config)));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowSettingConfigurationToNull() {
+ repository.setConfiguration(null);
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederationI18nTest.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederationI18nTest.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederationI18nTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,34 @@
+/*
+ * 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.connector.federation;
+
+import org.jboss.dna.common.AbstractI18nTest;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederationI18nTest extends AbstractI18nTest {
+
+ public FederationI18nTest() {
+ super(FederationI18n.class);
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionParserTest.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionParserTest.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionParserTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectionParserTest {
+
+ private ProjectionParser parser;
+
+ @Test
+ public void shouldInitializeSingletonWithParserMethods() {
+ parser = ProjectionParser.getInstance();
+ assertThat(parser.getParserMethods().size(), is(1));
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionPathRuleTest.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionPathRuleTest.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionPathRuleTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,249 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.common.text.UrlEncoder;
+import org.jboss.dna.spi.graph.NamespaceRegistry;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.connection.BasicExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectionPathRuleTest {
+
+ private ExecutionEnvironment env;
+ private Projection.PathRule rule;
+ private PathFactory pathFactory;
+ private Path repositoryPath;
+ private Path sourcePath;
+ private Path[] validExceptions;
+ private NamespaceRegistry registry;
+ private TextEncoder encoder;
+
+ @Before
+ public void beforeEach() {
+ env = new BasicExecutionEnvironment();
+ pathFactory = env.getValueFactories().getPathFactory();
+ registry = env.getNamespaceRegistry();
+ encoder = new UrlEncoder();
+ repositoryPath = pathFactory.create("/a/b/c");
+ sourcePath = pathFactory.create("/x/y");
+ validExceptions = new Path[] {pathFactory.create("e/f"),
pathFactory.create("e/g")};
+ rule = new Projection.PathRule(repositoryPath, sourcePath, validExceptions);
+ }
+
+ @Test
+ public void
shouldCreateInstanceWithValidRepositoryPathAndValidSourcePathAndNoExceptions() {
+ rule = new Projection.PathRule(repositoryPath, sourcePath);
+ assertThat(rule.getPathInRepository(), is(sameInstance(repositoryPath)));
+ assertThat(rule.getPathInSource(), is(sameInstance(sourcePath)));
+ assertThat(rule.hasExceptionsToRule(), is(false));
+ }
+
+ @Test
+ public void
shouldCreateInstanceWithValidRepositoryPathAndValidSourcePathAndValidExceptions() {
+ rule = new Projection.PathRule(repositoryPath, sourcePath, validExceptions);
+ assertThat(rule.getPathInRepository(), is(sameInstance(repositoryPath)));
+ assertThat(rule.getPathInSource(), is(sameInstance(sourcePath)));
+ assertThat(rule.hasExceptionsToRule(), is(true));
+ assertThat(rule.getExceptionsToRule(), hasItems(validExceptions));
+ }
+
+ @Test( expected = AssertionError.class )
+ public void
shouldFailToCreateInstanceWithNullRepositoryPathAndValidSourcePathAndNoExceptions() {
+ repositoryPath = null;
+ new Projection.PathRule(repositoryPath, sourcePath);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void
shouldFailToCreateInstanceWithValidRepositoryPathAndNullSourcePathAndNoExceptions() {
+ sourcePath = null;
+ new Projection.PathRule(repositoryPath, sourcePath);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void
shouldFailToCreateInstanceWithValidRepositoryPathAndValidSourcePathAndAbsoluteExceptions()
{
+ Path relativePath = validExceptions[0];
+ Path absolutePath = pathFactory.create("/j/k/l/m");
+ new Projection.PathRule(repositoryPath, sourcePath, relativePath, absolutePath);
+ }
+
+ @Test
+ public void shouldIncludeRepositoryPathsAtPathInRepository() {
+ assertThat(rule.includes(sourcePath), is(true));
+ }
+
+ @Test
+ public void shouldIncludeRepositoryPathsBelowPathInRepositoryThatAreNotExcluded() {
+ assertThat(rule.includes(pathFactory.create(sourcePath, "m")),
is(true));
+ assertThat(rule.includes(pathFactory.create(sourcePath, "m/n")),
is(true));
+ assertThat(rule.includes(pathFactory.create(sourcePath, "o/p")),
is(true));
+ assertThat(rule.includes(pathFactory.create(sourcePath, "e/e")),
is(true));
+ assertThat(rule.includes(pathFactory.create(sourcePath, "e")),
is(true));
+ }
+
+ @Test
+ public void shouldNotIncludeRepositoryPathsBelowPathInRepositoryThatAreExcluded() {
+ assertThat(rule.includes(pathFactory.create(sourcePath, "e/f")),
is(false));
+ assertThat(rule.includes(pathFactory.create(sourcePath, "e/g")),
is(false));
+ assertThat(rule.includes(pathFactory.create(sourcePath, "e/f/g")),
is(false));
+ assertThat(rule.includes(pathFactory.create(sourcePath, "e/g/h")),
is(false));
+ }
+
+ @Test
+ public void shouldNotIncludeRepositoryPathsNotBelowPathInRepository() {
+ assertThat(rule.includes(pathFactory.create("/m/n")), is(false));
+ assertThat(rule.includes(pathFactory.create("/x/y[3]")), is(false));
+ }
+
+ @Test
+ public void shouldProjectRepositoryPathIntoSourcePath() {
+ assertThat(rule.projectPathInRepositoryToPathInSource(repositoryPath,
pathFactory), is(sourcePath));
+ }
+
+ @Test
+ public void shouldProjectPathBelowRepositoryPathIntoPathBelowSourcePath() {
+ Path pathInRepository = pathFactory.create(repositoryPath, "m/n");
+ Path pathInSource = pathFactory.create(sourcePath, "m/n");
+ assertThat(rule.projectPathInRepositoryToPathInSource(pathInRepository,
pathFactory), is(pathInSource));
+
+ pathInRepository = pathFactory.create(repositoryPath, "m");
+ pathInSource = pathFactory.create(sourcePath, "m");
+ assertThat(rule.projectPathInRepositoryToPathInSource(pathInRepository,
pathFactory), is(pathInSource));
+
+ pathInRepository = pathFactory.create(repositoryPath, "m/n[3]");
+ pathInSource = pathFactory.create(sourcePath, "m/n[3]");
+ assertThat(rule.projectPathInRepositoryToPathInSource(pathInRepository,
pathFactory), is(pathInSource));
+ }
+
+ @Test
+ public void shouldProjectSourcePathIntoRepositoryPath() {
+ assertThat(rule.projectPathInSourceToPathInRepository(sourcePath, pathFactory),
is(repositoryPath));
+ }
+
+ @Test
+ public void shouldProjectPathBelowSourcePathIntoPathBelowRepositoryPath() {
+ Path pathInRepository = pathFactory.create(repositoryPath, "m/n");
+ Path pathInSource = pathFactory.create(sourcePath, "m/n");
+ assertThat(rule.projectPathInSourceToPathInRepository(pathInSource, pathFactory),
is(pathInRepository));
+
+ pathInRepository = pathFactory.create(repositoryPath, "m");
+ pathInSource = pathFactory.create(sourcePath, "m");
+ assertThat(rule.projectPathInSourceToPathInRepository(pathInSource, pathFactory),
is(pathInRepository));
+
+ pathInRepository = pathFactory.create(repositoryPath, "m/n[3]");
+ pathInSource = pathFactory.create(sourcePath, "m/n[3]");
+ assertThat(rule.projectPathInSourceToPathInRepository(pathInSource, pathFactory),
is(pathInRepository));
+ }
+
+ @Test
+ public void
shouldGetPathsInRepositoryGivenPathsInSourceAtOrBelowSourcePathIfNotExcluded() {
+ assertThat(rule.getPathInRepository(sourcePath, pathFactory),
is(repositoryPath));
+ assertThatGetPathInRepositoryReturnsCorrectPathInSource("");
+ assertThatGetPathInRepositoryReturnsCorrectPathInSource("m/n");
+ assertThatGetPathInRepositoryReturnsCorrectPathInSource("m[0]");
+ assertThatGetPathInRepositoryReturnsCorrectPathInSource("m[0]/n/o/p");
+ }
+
+ protected void assertThatGetPathInRepositoryReturnsCorrectPathInSource( String
subpath ) {
+ assertThat(rule.getPathInRepository(pathFactory.create(sourcePath, subpath),
pathFactory),
+ is(pathFactory.create(repositoryPath, subpath)));
+ }
+
+ @Test
+ public void
shouldGetNullPathInRepositoryGivenPathsInSourceAtOrBelowSourcePathIfExcluded() {
+ assertThat(rule.getPathInRepository(pathFactory.create(sourcePath,
"e/f"), pathFactory), is(nullValue()));
+ assertThat(rule.getPathInRepository(pathFactory.create(sourcePath,
"e/g"), pathFactory), is(nullValue()));
+ assertThat(rule.getPathInRepository(pathFactory.create(sourcePath,
"e/f/h"), pathFactory), is(nullValue()));
+ assertThat(rule.getPathInRepository(pathFactory.create(sourcePath,
"e/g/h"), pathFactory), is(nullValue()));
+ }
+
+ @Test
+ public void
shouldGetNullPathInRepositoryGivenPathsInRepositoryNotAtOrBelowSourcePath() {
+ assertThat(rule.getPathInRepository(pathFactory.create("/m/n"),
pathFactory), is(nullValue()));
+ }
+
+ @Test
+ public void
shouldGetPathsInSourceGivenPathsInRepositoryAtOrBelowRepositoryPathIfNotExcluded() {
+ assertThat(rule.getPathInSource(repositoryPath, pathFactory), is(sourcePath));
+ assertThatGetPathInSourceReturnsCorrectPathInRepository("");
+ assertThatGetPathInSourceReturnsCorrectPathInRepository("m/n");
+ assertThatGetPathInSourceReturnsCorrectPathInRepository("m[0]");
+ assertThatGetPathInSourceReturnsCorrectPathInRepository("m[0]/n/o/p");
+
+ }
+
+ protected void assertThatGetPathInSourceReturnsCorrectPathInRepository( String
subpath ) {
+ assertThat(rule.getPathInSource(pathFactory.create(repositoryPath, subpath),
pathFactory),
+ is(pathFactory.create(sourcePath, subpath)));
+ }
+
+ @Test
+ public void
shouldGetNullPathInSourceGivenPathsInRepositoryAtOrBelowRepositoryPathIfExcluded() {
+ assertThat(rule.getPathInSource(pathFactory.create(repositoryPath,
"e/f"), pathFactory), is(nullValue()));
+ assertThat(rule.getPathInSource(pathFactory.create(repositoryPath,
"e/g"), pathFactory), is(nullValue()));
+ assertThat(rule.getPathInSource(pathFactory.create(repositoryPath,
"e/f/h"), pathFactory), is(nullValue()));
+ assertThat(rule.getPathInSource(pathFactory.create(repositoryPath,
"e/g/h"), pathFactory), is(nullValue()));
+ }
+
+ @Test
+ public void
shouldGetNullPathInSourceGivenPathsInRepositoryNotAtOrBelowRepositoryPath() {
+ assertThat(rule.getPathInSource(pathFactory.create("/m/n"),
pathFactory), is(nullValue()));
+ }
+
+ @Test
+ public void shouldConvertToString() {
+ assertThat(rule.getString(registry, encoder), is("/a/b/c => /x/y $ e/f $
e/g"));
+
+ repositoryPath = pathFactory.create("/a/b/c");
+ sourcePath = pathFactory.create("/");
+ rule = new Projection.PathRule(repositoryPath, sourcePath, validExceptions);
+ assertThat(rule.getString(registry, encoder), is("/a/b/c => / $ e/f $
e/g"));
+
+ repositoryPath = pathFactory.create("/");
+ sourcePath = pathFactory.create("/");
+ rule = new Projection.PathRule(repositoryPath, sourcePath, validExceptions);
+ assertThat(rule.getString(registry, encoder), is("/ => / $ e/f $
e/g"));
+ }
+
+ @Test
+ public void shouldHaveToString() {
+ assertThat(rule.toString(), is("/{}a/{}b/{}c => /{}x/{}y $ {}e/{}f $
{}e/{}g"));
+
+ repositoryPath = pathFactory.create("/a/b/c");
+ sourcePath = pathFactory.create("/");
+ rule = new Projection.PathRule(repositoryPath, sourcePath, validExceptions);
+ assertThat(rule.toString(), is("/{}a/{}b/{}c => / $ {}e/{}f $
{}e/{}g"));
+ }
+
+}
Added:
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionTest.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionTest.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,231 @@
+/*
+ * 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.connector.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.stub;
+import java.util.Set;
+import org.jboss.dna.connector.federation.Projection;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.connection.BasicExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class ProjectionTest {
+
+ private ExecutionEnvironment env;
+ private String sourceName;
+ private Projection.Rule[] rules;
+ private Projection projection;
+ private PathFactory pathFactory;
+ @Mock
+ private Projection.Rule mockRule1;
+ @Mock
+ private Projection.Rule mockRule2;
+ @Mock
+ private Projection.Rule mockRule3;
+
+ @Before
+ public void beforeEach() {
+ MockitoAnnotations.initMocks(this);
+ env = new BasicExecutionEnvironment();
+ pathFactory = env.getValueFactories().getPathFactory();
+ sourceName = "Valid name";
+ rules = new Projection.Rule[] {mockRule1, mockRule2, mockRule3};
+ projection = new Projection(sourceName, rules);
+ }
+
+ @Test
+ public void shouldCreateInstanceWithValidNameAndValidRules() {
+ projection = new Projection(sourceName, rules);
+ assertThat(projection.getSourceName(), is(sourceName));
+ assertThat(projection.getRules().size(), is(rules.length));
+ assertThat(projection.getRules(), hasItems(mockRule1, mockRule2, mockRule3));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToCreateInstanceWithNullNameAndValidRules() {
+ sourceName = null;
+ projection = new Projection(sourceName, rules);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToCreateInstanceWithEmptyNameAndValidRules() {
+ sourceName = "";
+ projection = new Projection(sourceName, rules);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToCreateInstanceWithBlankNameAndValidRules() {
+ sourceName = " \t ";
+ projection = new Projection(sourceName, rules);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToCreateInstanceWithValidNameAndNullRules() {
+ rules = null;
+ projection = new Projection(sourceName, rules);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToCreateInstanceWithValidNameAndEmptyRules() {
+ rules = new Projection.Rule[] {};
+ projection = new Projection(sourceName, rules);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToCreateInstanceWithValidNameAndRulesArrayContainingAllNulls()
{
+ projection = new Projection(sourceName, null, null, null);
+ }
+
+ @Test
+ public void
shouldCreateInstanceWithValidNameAndRulesAndShouldPruneNullRuleReferences() {
+ projection = new Projection(sourceName, mockRule1, null, mockRule3);
+ assertThat(projection.getRules().size(), is(2));
+ assertThat(projection.getRules(), hasItems(mockRule1, mockRule3));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToGetPathsInSourceGivenValidPathAndNullPathFactory() {
+ Path pathInRepository = pathFactory.create("/a/b/c");
+ projection.getPathsInSource(pathInRepository, null);
+ }
+
+ @Test
+ public void shouldGetNoPathsInSourceGivenNullPathInRepository() {
+ Set<Path> pathsInSource = projection.getPathsInSource(null, pathFactory);
+ assertThat(pathsInSource.isEmpty(), is(true));
+ }
+
+ @Test
+ public void shouldGetNoPathsInSourceGivenPathInRepositoryAndNoApplicableRules() {
+ Path pathInRepository = pathFactory.create("/a/b/c");
+ stub(mockRule1.getPathInSource(pathInRepository, pathFactory)).toReturn(null);
+ stub(mockRule2.getPathInSource(pathInRepository, pathFactory)).toReturn(null);
+ stub(mockRule3.getPathInSource(pathInRepository, pathFactory)).toReturn(null);
+ Set<Path> pathsInSource = projection.getPathsInSource(pathInRepository,
pathFactory);
+ assertThat(pathsInSource.isEmpty(), is(true));
+ }
+
+ @Test
+ public void shouldGetPathInSourceGivenPathInRepositoryAndOneApplicableRules() {
+ Path pathInRepository = pathFactory.create("/a/b/c");
+ Path pathInSource = pathFactory.create("/d/e/f");
+ stub(mockRule1.getPathInSource(pathInRepository,
pathFactory)).toReturn(pathInSource);
+ stub(mockRule2.getPathInSource(pathInRepository, pathFactory)).toReturn(null);
+ stub(mockRule3.getPathInSource(pathInRepository, pathFactory)).toReturn(null);
+ Set<Path> pathsInSource = projection.getPathsInSource(pathInRepository,
pathFactory);
+ assertThat(pathsInSource, hasItems(pathInSource));
+ }
+
+ @Test
+ public void shouldGetPathsInSourceGivenPathInRepositoryAndMultipleApplicableRules()
{
+ Path pathInRepository = pathFactory.create("/a/b/c");
+ Path pathInSource1 = pathFactory.create("/d/e/f");
+ Path pathInSource2 = pathFactory.create("/d/e/g");
+ Path pathInSource3 = pathFactory.create("/d/e/h");
+ stub(mockRule1.getPathInSource(pathInRepository,
pathFactory)).toReturn(pathInSource1);
+ stub(mockRule2.getPathInSource(pathInRepository,
pathFactory)).toReturn(pathInSource2);
+ stub(mockRule3.getPathInSource(pathInRepository,
pathFactory)).toReturn(pathInSource3);
+ Set<Path> pathsInSource = projection.getPathsInSource(pathInRepository,
pathFactory);
+ assertThat(pathsInSource, hasItems(pathInSource1, pathInSource2,
pathInSource3));
+ }
+
+ @Test
+ public void
shouldGetPathsInSourceGivenPathInRepositoryAndMultipleApplicableRulesReturningDuplicatePathsInSource()
{
+ Path pathInRepository = pathFactory.create("/a/b/c");
+ Path pathInSource1 = pathFactory.create("/d/e/f");
+ Path pathInSource23 = pathFactory.create("/d/e/g");
+ stub(mockRule1.getPathInSource(pathInRepository,
pathFactory)).toReturn(pathInSource1);
+ stub(mockRule2.getPathInSource(pathInRepository,
pathFactory)).toReturn(pathInSource23);
+ stub(mockRule3.getPathInSource(pathInRepository,
pathFactory)).toReturn(pathInSource23);
+ Set<Path> pathsInSource = projection.getPathsInSource(pathInRepository,
pathFactory);
+ assertThat(pathsInSource, hasItems(pathInSource1, pathInSource23));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToGetPathsInRepositoryGivenValidPathAndNullPathFactory() {
+ Path pathInSource = pathFactory.create("/a/b/c");
+ projection.getPathsInRepository(pathInSource, null);
+ }
+
+ @Test
+ public void shouldGetNoPathsInRepositoryGivenNullPathInSource() {
+ Set<Path> pathsInRepository = projection.getPathsInRepository(null,
pathFactory);
+ assertThat(pathsInRepository.isEmpty(), is(true));
+ }
+
+ @Test
+ public void shouldGetNoPathsInRepositoryGivenPathInSourceAndNoApplicableRules() {
+ Path pathInSource = pathFactory.create("/d/e/f");
+ stub(mockRule1.getPathInRepository(pathInSource, pathFactory)).toReturn(null);
+ stub(mockRule2.getPathInRepository(pathInSource, pathFactory)).toReturn(null);
+ stub(mockRule3.getPathInRepository(pathInSource, pathFactory)).toReturn(null);
+ Set<Path> pathsInRepository = projection.getPathsInRepository(pathInSource,
pathFactory);
+ assertThat(pathsInRepository.isEmpty(), is(true));
+ }
+
+ @Test
+ public void shouldGetPathInRepositoryGivenPathInSourceAndOneApplicableRules() {
+ Path pathInRepository = pathFactory.create("/a/b/c");
+ Path pathInSource = pathFactory.create("/d/e/f");
+ stub(mockRule1.getPathInRepository(pathInSource,
pathFactory)).toReturn(pathInRepository);
+ stub(mockRule2.getPathInRepository(pathInSource, pathFactory)).toReturn(null);
+ stub(mockRule3.getPathInRepository(pathInSource, pathFactory)).toReturn(null);
+ Set<Path> pathsInRepository = projection.getPathsInRepository(pathInSource,
pathFactory);
+ assertThat(pathsInRepository, hasItems(pathInRepository));
+ }
+
+ @Test
+ public void shouldGetPathsInRepositoryGivenPathInSourceAndMultipleApplicableRules()
{
+ Path pathInSource = pathFactory.create("/a/b/c");
+ Path pathInRepository1 = pathFactory.create("/d/e/f");
+ Path pathInRepository2 = pathFactory.create("/d/e/g");
+ Path pathInRepository3 = pathFactory.create("/d/e/h");
+ stub(mockRule1.getPathInRepository(pathInSource,
pathFactory)).toReturn(pathInRepository1);
+ stub(mockRule2.getPathInRepository(pathInSource,
pathFactory)).toReturn(pathInRepository2);
+ stub(mockRule3.getPathInRepository(pathInSource,
pathFactory)).toReturn(pathInRepository3);
+ Set<Path> pathsInRepository = projection.getPathsInRepository(pathInSource,
pathFactory);
+ assertThat(pathsInRepository, hasItems(pathInRepository1, pathInRepository2,
pathInRepository3));
+ }
+
+ @Test
+ public void
shouldGetPathsInRepositoryGivenPathInSourceAndMultipleApplicableRulesReturningDuplicatePathsInRepository()
{
+ Path pathInSource = pathFactory.create("/a/b/c");
+ Path pathInRepository1 = pathFactory.create("/d/e/f");
+ Path pathInRepository23 = pathFactory.create("/d/e/g");
+ stub(mockRule1.getPathInRepository(pathInSource,
pathFactory)).toReturn(pathInRepository1);
+ stub(mockRule2.getPathInRepository(pathInSource,
pathFactory)).toReturn(pathInRepository23);
+ stub(mockRule3.getPathInRepository(pathInSource,
pathFactory)).toReturn(pathInRepository23);
+ Set<Path> pathsInRepository = projection.getPathsInRepository(pathInSource,
pathFactory);
+ assertThat(pathsInRepository, hasItems(pathInRepository1, pathInRepository23));
+ }
+}
Added:
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java
===================================================================
---
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java
(rev 0)
+++
trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class BasicFederatedNodeTest {
+
+ @Before
+ public void beforeEach() {
+ }
+
+ @Test
+ public void shouldDoSomething() {
+
+ }
+
+}
Modified: trunk/dna-repository/pom.xml
===================================================================
--- trunk/dna-repository/pom.xml 2008-07-23 17:17:39 UTC (rev 368)
+++ trunk/dna-repository/pom.xml 2008-07-24 19:52:13 UTC (rev 369)
@@ -43,6 +43,17 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-federation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-federation</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<!--
Rules
-->
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 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -41,6 +41,7 @@
public static I18n unableToUnregisterRepositoryInJndi;
public static I18n unableToRemoveRepository;
public static I18n unableToFindRepositoryWithName;
+ public static I18n unableToFindRepositorySourceWithName;
public static I18n errorProcessingEvents;
public static I18n errorFindingPropertyNameInPropertyAddedEvent;
public static I18n errorFindingPropertyNameInPropertyChangedEvent;
@@ -122,17 +123,7 @@
public static I18n warningSequencingXmlDocument;
// Federation
- public static I18n interruptedWhileConnectingToFederationConfigurationRepository;
- public static I18n interruptedWhileUsingFederationConfigurationRepository;
- public static I18n
interruptedWhileClosingConnectionToFederationConfigurationRepository;
- public static I18n federatedRepositoryCannotBeFound;
- public static I18n unableToConnectToFederationConfigurationRepository;
- public static I18n unableToFindRepositorySourceByName;
- public static I18n unableToCreateConnectionToFederatedRepository;
- public static I18n unableToAuthenticateConnectionToFederatedRepository;
- public static I18n repositoryHasBeenShutDown;
- public static I18n repositoryPathInFederationBindingIsNotAbsolute;
- public static I18n errorReadingMergePlan;
+ public static I18n errorStartingRepositoryService;
static {
try {
Copied: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
(from rev 346,
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java)
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
(rev 0)
+++
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,368 @@
+/*
+ * 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.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.collection.SimpleProblems;
+import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.component.StandardClassLoaderFactory;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.Reflection;
+import org.jboss.dna.connector.federation.FederatedRepositorySource;
+import org.jboss.dna.connector.federation.FederationException;
+import org.jboss.dna.connector.federation.Projection;
+import org.jboss.dna.connector.federation.executor.FederatingCommandExecutor;
+import org.jboss.dna.connector.federation.executor.SingleProjectionCommandExecutor;
+import org.jboss.dna.repository.services.AbstractServiceAdministrator;
+import org.jboss.dna.repository.services.AdministeredService;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.ValueFactory;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.executor.CommandExecutor;
+import org.jboss.dna.spi.graph.commands.executor.NoOpCommandExecutor;
+import org.jboss.dna.spi.graph.commands.impl.BasicCompositeCommand;
+import org.jboss.dna.spi.graph.commands.impl.BasicGetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.impl.BasicGetNodeCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class RepositoryService implements AdministeredService {
+
+ protected static final String CLASSNAME_PROPERTY_NAME = "dna:classname";
+ protected static final String CLASSPATH_PROPERTY_NAME = "dna:classpath";
+ protected static final String PROJECTION_RULES_PROPERTY_NAME =
"dna:projectionRules";
+ protected static final String CACHE_POLICY_TIME_TO_EXPIRE =
"dna:timeToExpire";
+ protected static final String CACHE_POLICY_TIME_TO_CACHE =
"dna:timeToCache";
+
+ /**
+ * The administrative component for this service.
+ *
+ * @author Randall Hauch
+ */
+ protected class Administrator extends AbstractServiceAdministrator {
+
+ protected Administrator() {
+ super(RepositoryI18n.federationServiceName, State.PAUSED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean doCheckIsTerminated() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doStart( State fromState ) {
+ super.doStart(fromState);
+ startService();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.repository.services.ServiceAdministrator#awaitTermination(long,
java.util.concurrent.TimeUnit)
+ */
+ public boolean awaitTermination( long timeout,
+ TimeUnit unit ) {
+ return true;
+ }
+ }
+
+ private final ClassLoaderFactory classLoaderFactory;
+ private final ExecutionEnvironment env;
+ private final RepositorySourceManager sources;
+ private final Projection configurationProjection;
+ private final Administrator administrator = new Administrator();
+ private final AtomicBoolean started = new AtomicBoolean(false);
+
+ /**
+ * Create a federation service instance
+ *
+ * @param sources the source manager
+ * @param configurationProjection the projection defining where the service can find
configuration information for the
+ * different repositories that it is to manage
+ * @param env the execution environment in which this service should run
+ * @param classLoaderFactory the class loader factory used to instantiate {@link
RepositorySource} instances; may be null if
+ * this instance should use a default factory that attempts to load classes
first from the
+ * {@link Thread#getContextClassLoader() thread's current context class
loader} and then from the class loader that
+ * loaded this class.
+ * @throws IllegalArgumentException if the bootstrap source is null or the execution
context is null
+ */
+ public RepositoryService( RepositorySourceManager sources,
+ Projection configurationProjection,
+ ExecutionEnvironment env,
+ ClassLoaderFactory classLoaderFactory ) {
+ ArgCheck.isNotNull(configurationProjection,
"configurationProjection");
+ ArgCheck.isNotNull(sources, "sources");
+ ArgCheck.isNotNull(env, "env");
+ this.sources = sources;
+ this.configurationProjection = configurationProjection;
+ this.env = env;
+ this.classLoaderFactory = classLoaderFactory != null ? classLoaderFactory : new
StandardClassLoaderFactory();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ServiceAdministrator getAdministrator() {
+ return this.administrator;
+ }
+
+ /**
+ * @return configurationProjection
+ */
+ public Projection getConfigurationProjection() {
+ return configurationProjection;
+ }
+
+ /**
+ * @return sources
+ */
+ public RepositorySourceManager getRepositorySourceManager() {
+ return sources;
+ }
+
+ /**
+ * @return env
+ */
+ public ExecutionEnvironment getExecutionEnvironment() {
+ return env;
+ }
+
+ /**
+ * @return classLoaderFactory
+ */
+ public ClassLoaderFactory getClassLoaderFactory() {
+ return this.classLoaderFactory;
+ }
+
+ public String getJndiName() {
+ // TODO
+ return null;
+ }
+
+ protected synchronized void startService() {
+ if (this.started.get() == false) {
+ Problems problems = new SimpleProblems();
+
+ //
------------------------------------------------------------------------------------
+ // Read the configuration ...
+ //
------------------------------------------------------------------------------------
+ ValueFactories valueFactories = env.getValueFactories();
+ PathFactory pathFactory = valueFactories.getPathFactory();
+ NameFactory nameFactory = valueFactories.getNameFactory();
+
+ final String configurationSourceName =
configurationProjection.getSourceName();
+ RepositoryConnectionFactory factory =
sources.getConnectionFactory(configurationSourceName);
+ if (factory == null) {
+ throw new
FederationException(RepositoryI18n.unableToFindRepositorySourceWithName.text(configurationSourceName));
+ }
+
+ // Create a federating command executor to execute the commands and merge the
results into a single set of
+ // commands.
+ List<Projection> projections =
Collections.singletonList(configurationProjection);
+ CommandExecutor executor = null;
+ if (configurationProjection.getRules().size() == 1) {
+ // There is just a single projection for the configuration repository, so
just use an executor that
+ // translates the paths using the projection
+ executor = new SingleProjectionCommandExecutor(env,
configurationSourceName, configurationProjection, sources);
+ } else if (configurationProjection.getRules().size() == 0) {
+ // There is no projection for the configuration repository, so just use a
no-op executor
+ executor = new NoOpCommandExecutor(env, configurationSourceName);
+ } else {
+ // The configuration repository has more than one projection, so we need
to merge the results
+ executor = new FederatingCommandExecutor(env, configurationSourceName,
null, projections, sources);
+ }
+
+ // Read the configuration and the repository sources, located as child
nodes/branches under "/dna:sources",
+ // and then instantiate and register each in the "sources" manager
+ Path configurationRoot = pathFactory.create("/");
+ try {
+ Path sourcesNode = pathFactory.create(configurationRoot,
nameFactory.create("dna:sources"));
+ BasicGetChildrenCommand getSources = new
BasicGetChildrenCommand(sourcesNode);
+ executor.execute(getSources);
+ if (getSources.hasNoError()) {
+
+ // Build the commands to get each of the children ...
+ List<Path.Segment> children = getSources.getChildren();
+ if (!children.isEmpty()) {
+ BasicCompositeCommand commands = new BasicCompositeCommand();
+ for (Path.Segment child : getSources.getChildren()) {
+ final Path pathToSource = pathFactory.create(sourcesNode,
child);
+ commands.add(new BasicGetNodeCommand(pathToSource));
+ }
+ executor.execute(commands);
+
+ // Iterate over each source node obtained ...
+ for (GraphCommand command : commands) {
+ BasicGetNodeCommand getSourceCommand =
(BasicGetNodeCommand)command;
+ if (getSourceCommand.hasNoError()) {
+ RepositorySource source =
createRepositorySource(getSourceCommand.getPath(),
+
getSourceCommand.getProperties(),
+
problems);
+ if (source != null) sources.addSource(source, true);
+ }
+ }
+ }
+ }
+ } catch (Throwable err) {
+ throw new
FederationException(RepositoryI18n.errorStartingRepositoryService.text());
+ }
+ this.started.set(true);
+ }
+ }
+
+ /**
+ * Instantiate the {@link RepositorySource} described by the supplied properties.
+ *
+ * @param path the path to the node where these properties were found; never null
+ * @param properties the properties; never null
+ * @param problems the problems container in which any problems should be reported;
never null
+ * @return the repository source instance, or null if it could not be created
+ */
+ @SuppressWarnings( "null" )
+ protected RepositorySource createRepositorySource( Path path,
+ Map<Name, Property>
properties,
+ Problems problems ) {
+ ValueFactories valueFactories = env.getValueFactories();
+ NameFactory nameFactory = valueFactories.getNameFactory();
+ ValueFactory<String> stringFactory = valueFactories.getStringFactory();
+
+ // Get the classname and classpath ...
+ Property classnameProperty =
properties.get(nameFactory.create(CLASSNAME_PROPERTY_NAME));
+ Property classpathProperty =
properties.get(nameFactory.create(CLASSPATH_PROPERTY_NAME));
+ if (classnameProperty == null) {
+ problems.addError(RepositoryI18n.requiredPropertyIsMissingFromNode,
CLASSNAME_PROPERTY_NAME, path);
+ }
+ // If the classpath property is null or empty, the default classpath will be
used
+ if (problems.hasErrors()) return null;
+
+ // Create the instance ...
+ String classname = stringFactory.create(classnameProperty.getValues().next());
+ String[] classpath = classpathProperty == null ? new String[] {} :
stringFactory.create(classpathProperty.getValuesAsArray());
+ ClassLoader classLoader = this.classLoaderFactory.getClassLoader(classpath);
+ RepositorySource source = null;
+ try {
+ Class<?> sourceClass = classLoader.loadClass(classname);
+ source = (RepositorySource)sourceClass.newInstance();
+ } catch (ClassNotFoundException err) {
+ problems.addError(err, RepositoryI18n.unableToLoadClassUsingClasspath,
classname, classpath);
+ } catch (IllegalAccessException err) {
+ problems.addError(err, RepositoryI18n.unableToAccessClassUsingClasspath,
classname, classpath);
+ } catch (Throwable err) {
+ problems.addError(err, RepositoryI18n.unableToInstantiateClassUsingClasspath,
classname, classpath);
+ }
+
+ // Try to set the name property to the local name of the node...
+ Reflection reflection = new Reflection(source.getClass());
+ try {
+ reflection.invokeSetterMethodOnTarget("name", source,
path.getLastSegment().getName().getLocalName());
+ } catch (SecurityException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (NoSuchMethodException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (IllegalArgumentException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (IllegalAccessException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (InvocationTargetException err) {
+ // Do nothing ... assume not a JavaBean property
+ }
+
+ // Now set all the properties that we can, ignoring any property that doesn't
fit pattern ...
+ for (Map.Entry<Name, Property> entry : properties.entrySet()) {
+ Name propertyName = entry.getKey();
+ Property property = entry.getValue();
+ String javaPropertyName = propertyName.getLocalName();
+ if (property.isEmpty()) continue;
+ Object value = null;
+ if (property.isSingle()) {
+ value = property.getValues().next();
+ } else if (property.isMultiple()) {
+ value = property.getValuesAsArray();
+ }
+ try {
+ reflection.invokeSetterMethodOnTarget(javaPropertyName, source, value);
+ } catch (SecurityException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (NoSuchMethodException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (IllegalArgumentException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (IllegalAccessException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (InvocationTargetException err) {
+ // Do nothing ... assume not a JavaBean property
+ }
+ }
+ return source;
+ }
+
+ /**
+ * Get the current set of federated repository names.
+ *
+ * @return the names of the repository, which is a mutable copy of the names that is
not backed by the actual sources
+ */
+ public Set<String> getFederatedRepositoryNames() {
+ Set<String> repositoryNames = new HashSet<String>();
+ for (RepositorySource source : sources.getSources()) {
+ if (source instanceof FederatedRepositorySource) {
+ repositoryNames.add(source.getName());
+ }
+ }
+ return repositoryNames;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ return false;
+ }
+}
Property changes on:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Copied:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositorySourceManager.java
(from rev 339,
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositorySourceManager.java)
===================================================================
---
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositorySourceManager.java
(rev 0)
+++
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositorySourceManager.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,348 @@
+/*
+ * 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.Collection;
+import java.util.Collections;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.jboss.dna.repository.services.AbstractServiceAdministrator;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactories;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * @author Randall Hauch
+ */
+public class RepositorySourceManager implements RepositoryConnectionFactories {
+
+ /**
+ * The administrative component for this service.
+ *
+ * @author Randall Hauch
+ */
+ protected class Administrator extends AbstractServiceAdministrator {
+
+ protected Administrator() {
+ super(RepositoryI18n.federationServiceName, State.STARTED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doStart( State fromState ) {
+ super.doStart(fromState);
+ RepositorySourceManager.this.start();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doShutdown( State fromState ) {
+ super.doShutdown(fromState);
+ RepositorySourceManager.this.shutdown();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean awaitTermination( long timeout,
+ TimeUnit unit ) throws InterruptedException {
+ return RepositorySourceManager.this.awaitTermination(timeout, unit);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean doCheckIsTerminated() {
+ return RepositorySourceManager.this.isTerminated();
+ }
+
+ }
+
+ private final ServiceAdministrator administrator = new Administrator();
+ private final ReadWriteLock sourcesLock = new ReentrantReadWriteLock();
+ private final CopyOnWriteArrayList<RepositorySource> sources = new
CopyOnWriteArrayList<RepositorySource>();
+ private RepositoryConnectionFactories delegate;
+
+ /**
+ * Create a new manager instance.
+ *
+ * @param delegate the factories object that this instance should delegate to in the
event that a source is not found in this
+ * manager; may be null if there is no delegate
+ */
+ public RepositorySourceManager( RepositoryConnectionFactories delegate ) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * @return delegate
+ */
+ public RepositoryConnectionFactories getDelegate() {
+ return delegate;
+ }
+
+ /**
+ * @param delegate Sets delegate to the specified value.
+ */
+ public void setDelegate( RepositoryConnectionFactories delegate ) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * @return administrator
+ */
+ public ServiceAdministrator getAdministrator() {
+ return this.administrator;
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ protected void start() {
+ // Do not establish connections to the sources; these will be established as
needed
+
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ protected void shutdown() {
+ // Close all connections to the sources. This is done inside the sources write
lock.
+ try {
+ this.sourcesLock.readLock().lock();
+ for (RepositorySource source : this.sources) {
+ if (source instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)source;
+ pool.shutdown();
+ }
+ }
+ } finally {
+ this.sourcesLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Utility method called by the administrator.
+ *
+ * @param timeout
+ * @param unit
+ * @return true if all pools were terminated in the supplied time (or were already
terminated), or false if the timeout
+ * occurred before all the connections were closed
+ * @throws InterruptedException
+ */
+ protected boolean awaitTermination( long timeout,
+ TimeUnit unit ) throws InterruptedException {
+ // Check whether all source pools are shut down. This is done inside the sources
write lock.
+ try {
+ this.sourcesLock.readLock().lock();
+ for (RepositorySource source : this.sources) {
+ if (source instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)source;
+ if (!pool.awaitTermination(timeout, unit)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ } finally {
+ this.sourcesLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Returns true if this federated repository is in the process of terminating after
{@link ServiceAdministrator#shutdown()}
+ * has been called on the {@link #getAdministrator() administrator}, but the
federated repository has connections that have
+ * not yet normally been {@link RepositoryConnection#close() closed}. This method may
be useful for debugging. A return of
+ * <tt>true</tt> reported a sufficient period after shutdown may indicate
that connection users have ignored or suppressed
+ * interruption, causing this repository not to properly terminate.
+ *
+ * @return true if terminating but not yet terminated, or false otherwise
+ * @see #isTerminated()
+ */
+ public boolean isTerminating() {
+ try {
+ this.sourcesLock.readLock().lock();
+ for (RepositorySource source : this.sources) {
+ if (source instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)source;
+ if (pool.isTerminating()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } finally {
+ this.sourcesLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Return true if this federated repository has completed its termination and no
longer has any open connections.
+ *
+ * @return true if terminated, or false otherwise
+ * @see #isTerminating()
+ */
+ public boolean isTerminated() {
+ try {
+ this.sourcesLock.readLock().lock();
+ for (RepositorySource source : this.sources) {
+ if (source instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)source;
+ if (!pool.isTerminated()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ } finally {
+ this.sourcesLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get an unmodifiable collection of {@link RepositorySource federated sources}.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @return the sources
+ */
+ public Collection<RepositorySource> getSources() {
+ return Collections.unmodifiableCollection(this.sources);
+ }
+
+ /**
+ * Add the supplied federated source. This method returns false if the source is
null.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param source the source to add
+ * @param force true if the valid source should be added even if there is an existing
source with the supplied name
+ * @return true if the source is added, or false if the reference is null or if there
is already an existing source with the
+ * supplied name.
+ */
+ public boolean addSource( RepositorySource source,
+ boolean force ) {
+ if (source == null) return false;
+ try {
+ this.sourcesLock.writeLock().lock();
+ for (RepositorySource existingSource : this.sources) {
+ if (existingSource.getName().equals(source.getName())) return false;
+ }
+ return force ? this.sources.add(source) : this.sources.addIfAbsent(source);
+ } finally {
+ this.sourcesLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Remove from this federated repository the supplied source (or a source with the
same name as that supplied). This call
+ * shuts down the connections in the source in an orderly fashion, allowing those
connection currently in use to be used and
+ * closed normally, but preventing further connections from being used.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param source the source to be removed
+ * @param timeToAwait the amount of time to wait while all of the source's
connections are closed, or non-positive if the call
+ * should not wait at all
+ * @param unit the time unit to be used for <code>timeToAwait</code>
+ * @return true if the source was removed, or false if the source was not a source
for this repository.
+ * @throws InterruptedException if the thread is interrupted while awaiting closing
of the connections
+ */
+ public boolean removeSource( RepositorySource source,
+ long timeToAwait,
+ TimeUnit unit ) throws InterruptedException {
+ // Use the name; don't use the object equality ...
+ return removeSource(source.getName(), timeToAwait, unit) != null;
+ }
+
+ /**
+ * Remove from this federated repository the source with the supplied name. This call
shuts down the connections in the source
+ * in an orderly fashion, allowing those connection currently in use to be used and
closed normally, but preventing further
+ * connections from being used.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @param name the name of the source to be removed
+ * @param timeToAwait the amount of time to wait while all of the source's
connections are closed, or non-positive if the call
+ * should not wait at all
+ * @param unit the time unit to be used for <code>timeToAwait</code>
+ * @return the source with the supplied name that was removed, or null if no existing
source matching the supplied name could
+ * be found
+ * @throws InterruptedException if the thread is interrupted while awaiting closing
of the connections
+ */
+ public RepositorySource removeSource( String name,
+ long timeToAwait,
+ TimeUnit unit ) throws InterruptedException {
+ try {
+ this.sourcesLock.writeLock().lock();
+ for (RepositorySource existingSource : this.sources) {
+ if (existingSource.getName().equals(name)) {
+ // Shut down the connection pool if it is one ...
+ if (existingSource instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool =
(RepositoryConnectionPool)existingSource;
+ pool.shutdown();
+ if (timeToAwait > 0l) pool.awaitTermination(timeToAwait,
unit);
+ }
+ }
+ return existingSource;
+ }
+ } finally {
+ this.sourcesLock.writeLock().unlock();
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.connection.RepositoryConnectionFactories#getConnectionFactory(java.lang.String)
+ */
+ public RepositoryConnectionFactory getConnectionFactory( String sourceName ) {
+ try {
+ this.sourcesLock.readLock().lock();
+ for (RepositorySource existingSource : this.sources) {
+ if (existingSource.getName().equals(sourceName)) return existingSource;
+ }
+ RepositoryConnectionFactories delegate = this.delegate;
+ if (delegate != null) {
+ return delegate.getConnectionFactory(sourceName);
+ }
+ } finally {
+ this.sourcesLock.readLock().unlock();
+ }
+ return null;
+ }
+
+}
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 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2008-07-24
19:52:13 UTC (rev 369)
@@ -23,11 +23,12 @@
serviceShutdowAndMayNotBeStarted = The {0} has been shutdown and may not be (re)started
serviceShutdowAndMayNotBePaused = The {0} has been shutdown and my not be paused
serviceNotShutdowAndMayNotBeTerminated = The {0} has not been shutdown and may not be
terminated
-unableToFindRepositoryInJndi = Unable to find a JCR repository in JNDI at
"{0}"
-unableToRegisterRepositoryInJndi = Unable to register a JCR repository in JNDI at
"{0}"
-unableToUnregisterRepositoryInJndi = Unable to unregister a JCR repository at JNDI at
"{0}"
-unableToRemoveRepository = Unable to remove a JCR repository named "{0}"
-unableToFindRepositoryWithName = Unable to find a JCR repository named "{0}"
+unableToFindRepositoryInJndi = Unable to find a repository in JNDI at "{0}"
+unableToRegisterRepositoryInJndi = Unable to register a repository in JNDI at
"{0}"
+unableToUnregisterRepositoryInJndi = Unable to unregister a repository at JNDI at
"{0}"
+unableToRemoveRepository = Unable to remove a repository named "{0}"
+unableToFindRepositoryWithName = Unable to find a repository named "{0}"
+unableToFindRepositorySourceWithName = Unable to find a repository source named
"{0}"
errorProcessingEvents = Error processing events from {0}
errorFindingPropertyNameInPropertyAddedEvent = Error finding the name of the added
property in the event path {0}
errorFindingPropertyNameInPropertyChangedEvent = Error finding the name of the changed
property in the event path {0}
@@ -101,14 +102,4 @@
canceledSequencingXmlDocument = Canceled sequencing XML
warningSequencingXmlDocument = A warning was received while sequencing XML: {0}
-interruptedWhileConnectingToFederationConfigurationRepository = Interrupted while
connecting to federation configuration repository "{0}"
-interruptedWhileUsingFederationConfigurationRepository = Interrupted while using
federation configuration repository "{0}"
-interruptedWhileClosingConnectionToFederationConfigurationRepository = Interrupted while
closing connection to federation configuration repository "{0}"
-federatedRepositoryCannotBeFound = The federated repository "{0}" cannot be
found
-unableToConnectToFederationConfigurationRepository = Unable to connect to federation
configuration repository "{0}"
-unableToFindRepositorySourceByName = Unable to find the repository source
"{0}"
-unableToCreateConnectionToFederatedRepository = Unable to connect to the repository
"{0}". Check the Federation Service configuration.
-unableToAuthenticateConnectionToFederatedRepository = Unable to authenticate
"{1}" for repository "{0}"
-repositoryHasBeenShutDown = The "{0}" repository has been shut down and may no
longer be used.
-repositoryPathInFederationBindingIsNotAbsolute = The repository path in a federation
binding must be absolute, but was "{0}"
-errorReadingMergePlan = Error while reading merge plan for {0}
\ No newline at end of file
+errorStartingRepositoryService = Error while starting repository service
Copied:
trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java
(from rev 346,
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederationServiceTest.java)
===================================================================
---
trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java
(rev 0)
+++
trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,293 @@
+/*
+ * 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.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import java.util.concurrent.TimeUnit;
+import org.jboss.dna.common.component.ClassLoaderFactory;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.connector.federation.FederationException;
+import org.jboss.dna.connector.federation.Projection;
+import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.spi.graph.NamespaceRegistry;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.SimpleRepository;
+import org.jboss.dna.spi.graph.connection.SimpleRepositorySource;
+import org.jboss.dna.spi.graph.impl.BasicNamespaceRegistry;
+import org.jboss.dna.spi.graph.impl.BasicPropertyFactory;
+import org.jboss.dna.spi.graph.impl.StandardValueFactories;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class RepositoryServiceTest {
+
+ public static final String CLASSNAME = RepositoryService.CLASSNAME_PROPERTY_NAME;
+ public static final String CLASSPATH = RepositoryService.CLASSPATH_PROPERTY_NAME;
+ public static final String PROJECTION_RULES =
RepositoryService.PROJECTION_RULES_PROPERTY_NAME;
+ public static final String TIME_TO_EXPIRE =
RepositoryService.CACHE_POLICY_TIME_TO_EXPIRE;
+ public static final String TIME_TO_CACHE =
RepositoryService.CACHE_POLICY_TIME_TO_CACHE;
+
+ private RepositoryService service;
+ private Projection configProjection;
+ private StandardValueFactories valueFactories;
+ private PropertyFactory propertyFactory;
+ private PathFactory pathFactory;
+ private String configSourceName;
+ private SimpleRepository configRepository;
+ private SimpleRepositorySource configRepositorySource;
+ @Mock
+ private ExecutionEnvironment env;
+ @Mock
+ private RepositorySourceManager sources;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ NamespaceRegistry registry = new BasicNamespaceRegistry();
+ registry.register("dna", "http://www.jboss.org/dna");
+ valueFactories = new StandardValueFactories(registry);
+ pathFactory = valueFactories.getPathFactory();
+ propertyFactory = new BasicPropertyFactory(valueFactories);
+ Path pathInRepository = pathFactory.create("/");
+ Path pathInSource = pathFactory.create("/reposX");
+ configSourceName = "configSource";
+ Projection.Rule configProjectionRule = new Projection.PathRule(pathInRepository,
pathInSource);
+ configProjection = new Projection(configSourceName, configProjectionRule);
+ configRepository = new SimpleRepository("Configuration Repository");
+ configRepositorySource = new SimpleRepositorySource();
+ configRepositorySource.setRepositoryName(configRepository.getRepositoryName());
+ configRepositorySource.setName(configSourceName);
+
stub(sources.getConnectionFactory(configSourceName)).toReturn(configRepositorySource);
+ stub(env.getValueFactories()).toReturn(valueFactories);
+ stub(env.getPropertyFactory()).toReturn(propertyFactory);
+ stub(env.getNamespaceRegistry()).toReturn(registry);
+ service = new RepositoryService(sources, configProjection, env, null);
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ service.getAdministrator().shutdown();
+ service.getAdministrator().awaitTermination(4, TimeUnit.SECONDS);
+ SimpleRepository.shutdownAll();
+ Logger.getLogger(getClass()).trace("");
+ }
+
+ @Test
+ public void shouldHaveServiceAdministratorAfterInstantiation() {
+ assertThat(service.getAdministrator(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldHaveConfigurationRegionAfterInstantiation() {
+ assertThat(service.getConfigurationProjection(), is(notNullValue()));
+ assertThat(service.getConfigurationProjection(),
is(sameInstance(configProjection)));
+ }
+
+ @Test
+ public void shouldHaveAnExecutionEnvironmentAfterInstantiation() {
+ assertThat(service.getExecutionEnvironment(), is(notNullValue()));
+ assertThat(service.getExecutionEnvironment(), is(sameInstance(env)));
+ }
+
+ @Test
+ public void
shouldHaveNonNullClassLoaderFactoryAfterInstantiatingWithNullClassLoaderFactoryReference()
{
+ assertThat(service.getClassLoaderFactory(), is(notNullValue()));
+ }
+
+ @Test
+ public void
shouldHaveNonNullClassLoaderFactoryAfterInstantiatingWithClassLoaderFactoryReference() {
+ ClassLoaderFactory classLoaderFactory = mock(ClassLoaderFactory.class);
+ service = new RepositoryService(sources, configProjection, env,
classLoaderFactory);
+ assertThat(service.getClassLoaderFactory(), is(notNullValue()));
+ assertThat(service.getClassLoaderFactory(),
is(sameInstance(classLoaderFactory)));
+ }
+
+ @Test
+ public void shouldHaveNullJndiNameAfterInstantiation() {
+ assertThat(service.getJndiName(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowShuttingDownBeforeStartingUp() throws Exception {
+ assertThat(service.getAdministrator().getState(),
is(ServiceAdministrator.State.PAUSED));
+ service.getAdministrator().shutdown();
+ service.getAdministrator().awaitTermination(1, TimeUnit.SECONDS);
+ assertThat(service.getAdministrator().getState(),
is(ServiceAdministrator.State.TERMINATED));
+ }
+
+ @Test( expected = FederationException.class )
+ public void shouldFailToStartUpIfConfigurationRepositorySourceIsNotFound() {
+ stub(sources.getConnectionFactory(configSourceName)).toReturn(null);
+ service.getAdministrator().start();
+ }
+
+ @Test( expected = FederationException.class )
+ public void shouldFailToStartUpIfUnableToConnectToConfigurationRepository() throws
Exception {
+ RepositorySource mockSource = mock(RepositorySource.class);
+ stub(sources.getConnectionFactory(configSourceName)).toReturn(mockSource);
+ stub(mockSource.getConnection()).toThrow(new UnsupportedOperationException());
+ service.getAdministrator().start();
+ }
+
+ @Test( expected = FederationException.class )
+ public void
shouldFailToStartUpIfInterruptedWhileConnectingToConfigurationRepository() throws
Exception {
+ RepositorySource mockSource = mock(RepositorySource.class);
+ stub(sources.getConnectionFactory(configSourceName)).toReturn(mockSource);
+ stub(mockSource.getConnection()).toThrow(new InterruptedException());
+ service.getAdministrator().start();
+ }
+
+ @Test
+ public void shouldStartUpUsingConfigurationRepositoryThatContainsSomeSources() {
+ // Use a real source manager for this test ...
+ sources = new RepositorySourceManager(sources);
+ sources.addSource(configRepositorySource, true);
+ assertThat(sources.getSources(),
hasItems((RepositorySource)configRepositorySource));
+ assertThat(sources.getSources().size(), is(1));
+ service = new RepositoryService(sources, configProjection, env, null);
+
+ // Set up the configuration repository to contain 3 sources ...
+ configRepository.create(env, "/reposX/dna:sources");
+ configRepository.setProperty(env, "/reposX/dna:sources/source A",
CLASSNAME, SimpleRepositorySource.class.getName());
+ configRepository.setProperty(env, "/reposX/dna:sources/source A",
CLASSPATH, "");
+ configRepository.setProperty(env, "/reposX/dna:sources/source A",
"repositoryName", "sourceReposA");
+ configRepository.setProperty(env, "/reposX/dna:sources/source A",
"retryLimit", 3);
+
+ configRepository.setProperty(env, "/reposX/dna:sources/source B",
CLASSNAME, SimpleRepositorySource.class.getName());
+ configRepository.setProperty(env, "/reposX/dna:sources/source B",
CLASSPATH, "");
+ configRepository.setProperty(env, "/reposX/dna:sources/source B",
"repositoryName", "sourceReposB");
+
+ configRepository.setProperty(env, "/reposX/dna:sources/source C",
CLASSNAME, SimpleRepositorySource.class.getName());
+ configRepository.setProperty(env, "/reposX/dna:sources/source C",
CLASSPATH, "");
+ configRepository.setProperty(env, "/reposX/dna:sources/source C",
"repositoryName", "sourceReposC");
+
+ // Now, start up the service ...
+ service.getAdministrator().start();
+
+ // and verify that the sources were added to the manager...
+ assertThat(sources.getSources().size(), is(4));
+ assertThat(sources.getConnectionFactory("source A"),
is(instanceOf(SimpleRepositorySource.class)));
+ assertThat(sources.getConnectionFactory("source B"),
is(instanceOf(SimpleRepositorySource.class)));
+ assertThat(sources.getConnectionFactory("source C"),
is(instanceOf(SimpleRepositorySource.class)));
+
+ SimpleRepositorySource sourceA =
(SimpleRepositorySource)sources.getConnectionFactory("source A");
+ assertThat(sourceA.getName(), is("source A"));
+ assertThat(sourceA.getRepositoryName(), is("sourceReposA"));
+ assertThat(sourceA.getRetryLimit(), is(3));
+
+ SimpleRepositorySource sourceB =
(SimpleRepositorySource)sources.getConnectionFactory("source B");
+ assertThat(sourceB.getName(), is("source B"));
+ assertThat(sourceB.getRepositoryName(), is("sourceReposB"));
+ assertThat(sourceB.getRetryLimit(),
is(SimpleRepositorySource.DEFAULT_RETRY_LIMIT));
+
+ SimpleRepositorySource sourceC =
(SimpleRepositorySource)sources.getConnectionFactory("source C");
+ assertThat(sourceC.getName(), is("source C"));
+ assertThat(sourceC.getRepositoryName(), is("sourceReposC"));
+ assertThat(sourceC.getRetryLimit(),
is(SimpleRepositorySource.DEFAULT_RETRY_LIMIT));
+ }
+
+ @Test
+ public void shouldStartUpUsingConfigurationRepositoryThatContainsNoSources() {
+ // Set up the configuration repository to contain NO sources ...
+ configRepository.create(env, "/reposX/dna:sources");
+
+ // Now, start up the service ...
+ service.getAdministrator().start();
+
+ // and verify that the configuration source was obtained from the manager ...
+ verify(sources, times(2)).getConnectionFactory(configSourceName); // once for
checking source, second for getting
+
+ // and verify that the sources were never added to the manager...
+ verifyNoMoreInteractions(sources);
+ }
+
+ @Test
+ public void
shouldStartUpAndCreateRepositoryUsingConfigurationRepositoryThatContainsNoSources() {
+ // Set up the configuration repository ...
+ configRepository.create(env, "/reposX/dna:sources");
+ configRepository.setProperty(env, "/reposX/dna:sources/source A",
CLASSNAME, SimpleRepositorySource.class.getName());
+ configRepository.setProperty(env, "/reposX/dna:sources/source A",
CLASSPATH, "");
+ configRepository.setProperty(env, "/reposX/dna:sources/source A",
"repositoryName", "sourceReposA");
+ configRepository.setProperty(env, "/reposX/dna:sources/source A",
"retryLimit", 3);
+
+ String fedReposPath = "/reposX/dna:repositories/fed repos/";
+ configRepository.setProperty(env, fedReposPath, TIME_TO_CACHE,
"10000");
+ configRepository.setProperty(env, fedReposPath, TIME_TO_EXPIRE,
"20000");
+ configRepository.setProperty(env, fedReposPath + "dna:regions/source
A", PROJECTION_RULES, "/a/b/c => /sx/sy");
+ configRepository.setProperty(env, fedReposPath + "dna:regions/source
B", PROJECTION_RULES, "/ => /");
+ configRepository.setProperty(env, fedReposPath + "dna:regions/source
C", PROJECTION_RULES, "/d/e/f => /");
+ configRepository.setProperty(env, fedReposPath + "dna:regions/source
D", PROJECTION_RULES, "/ => /x/y/z");
+
+ // Now, start up the service ...
+ service.getAdministrator().start();
+
+ // // Create the repository ...
+ // FederatedRepositorySource repository =
(FederatedRepositorySource)sources.getConnectionFactory("fed repos");
+ // assertThat(repository, is(notNullValue()));
+ // assertThat(repository.getName(), is("fed repos"));
+ // assertThat(repository.getDefaultCachePolicy().getTimeToCache(), is(10000l));
+ // assertThat(repository.getDefaultCachePolicy().getTimeToExpire(), is(20000l));
+ // assertThat(repository.getCacheProjection(),
is(sameInstance(configProjection)));
+ //
assertThat(repository.getConfiguration().getSourceProjections().get(0).getPathsInSource(pathFactory.create("/a/b/c"),
+ // pathFactory),
+ // hasItems(pathFactory.create("/sx/sy")));
+ //
assertThat(repository.getConfiguration().getSourceProjections().get(0).getSourceName(),
is("source A"));
+ //
assertThat(repository.getConfiguration().getSourceProjections().get(1).getPathsInSource(pathFactory.create("/"),
+ // pathFactory),
+ // hasItems(pathFactory.create("/")));
+ //
assertThat(repository.getConfiguration().getSourceProjections().get(1).getSourceName(),
is("source B"));
+ //
assertThat(repository.getConfiguration().getSourceProjections().get(2).getPathsInSource(pathFactory.create("/d/e/f"),
+ // pathFactory),
+ // hasItems(pathFactory.create("/")));
+ //
assertThat(repository.getConfiguration().getSourceProjections().get(2).getSourceName(),
is("source C"));
+ //
assertThat(repository.getConfiguration().getSourceProjections().get(3).getPathsInSource(pathFactory.create("/"),
+ // pathFactory),
+ // hasItems(pathFactory.create("/x/y/z")));
+ //
assertThat(repository.getConfiguration().getSourceProjections().get(3).getSourceName(),
is("source A"));
+ //
+ // for (int i = 0; i != 10; ++i) {
+ // assertThat(service.getRepository("fed repos"),
is(sameInstance(repository)));
+ // }
+ }
+
+}
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/ExecutionContextFactory.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/ExecutionContextFactory.java
(rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/ExecutionContextFactory.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,91 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.spi;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+
+/**
+ * A factory for creating {@link ExecutionEnvironment} instances. Each execution
environment is affiliated with a JAAS
+ * {@link Subject}, and thus the factory methods take the same parameters that the JAAS
{@link LoginContext} take.
+ *
+ * @author Randall Hauch
+ */
+public interface ExecutionContextFactory {
+
+ /**
+ * Create an {@link ExecutionEnvironment} for the supplied {@link LoginContext}.
+ *
+ * @param loginContext the JAAS login context
+ * @return the execution context
+ * @throws IllegalArgumentException if the <code>loginContext</code> is
null
+ */
+ ExecutionEnvironment create( LoginContext loginContext );
+
+ /**
+ * @param name the name of the JAAS login context
+ * @return the execution context
+ * @throws IllegalArgumentException if the <code>name</code> is null
+ * @throws LoginException if there <code>name</code> is invalid (or there
is no login context named "other"), or if the
+ * default callback handler JAAS property was not set or could not be loaded
+ */
+ ExecutionEnvironment create( String name ) throws LoginException;
+
+ /**
+ * @param name the name of the JAAS login context
+ * @param subject the subject to authenticate
+ * @return the execution context
+ * @throws LoginException if there <code>name</code> is invalid (or there
is no login context named "other"), if the default
+ * callback handler JAAS property was not set or could not be loaded, or if
the <code>subject</code> is null or
+ * unknown
+ */
+ ExecutionEnvironment create( String name,
+ Subject subject ) throws LoginException;
+
+ /**
+ * @param name the name of the JAAS login context
+ * @param callbackHandler the callback handler that will be used by {@link
LoginModule}s to communicate with the user.
+ * @return the execution context
+ * @throws LoginException if there <code>name</code> is invalid (or there
is no login context named "other"), or if the
+ * <code>callbackHandler</code> is null
+ */
+ ExecutionEnvironment create( String name,
+ CallbackHandler callbackHandler ) throws
LoginException;
+
+ /**
+ * @param name the name of the JAAS login context
+ * @param subject the subject to authenticate
+ * @param callbackHandler the callback handler that will be used by {@link
LoginModule}s to communicate with the user.
+ * @return the execution context
+ * @throws LoginException if there <code>name</code> is invalid (or there
is no login context named "other"), if the default
+ * callback handler JAAS property was not set or could not be loaded, if the
<code>subject</code> is null or unknown,
+ * or if the <code>callbackHandler</code> is null
+ */
+ ExecutionEnvironment create( String name,
+ Subject subject,
+ CallbackHandler callbackHandler ) throws
LoginException;
+
+}
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/SpiI18n.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/SpiI18n.java 2008-07-23 17:17:39 UTC
(rev 368)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/SpiI18n.java 2008-07-24 19:52:13 UTC
(rev 369)
@@ -59,6 +59,11 @@
public static I18n pathExpressionHasInvalidSelect;
public static I18n pathExpressionHasInvalidMatch;
+ public static I18n executingGraphCommand;
+ public static I18n executedGraphCommand;
+ public static I18n closingCommandExecutor;
+ public static I18n closedCommandExecutor;
+
static {
try {
I18n.initialize(SpiI18n.class);
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/Path.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/Path.java 2008-07-23 17:17:39 UTC
(rev 368)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/Path.java 2008-07-24 19:52:13 UTC
(rev 369)
@@ -105,14 +105,14 @@
public static final TextDecoder URL_DECODER = new
UrlEncoder().setSlashEncoded(true);
/**
- * The default text encoder to be used when none is otherwise specified. This is
currently the
- * {@link #JSR283_ENCODER JSR-283 encoder}.
+ * The default text encoder to be used when none is otherwise specified. This is
currently the {@link #JSR283_ENCODER JSR-283
+ * encoder}.
*/
public static final TextEncoder DEFAULT_ENCODER = JSR283_ENCODER;
/**
- * The default text decoder to be used when none is otherwise specified. This is
currently the
- * {@link #JSR283_ENCODER JSR-283 encoder}.
+ * The default text decoder to be used when none is otherwise specified. This is
currently the {@link #JSR283_ENCODER JSR-283
+ * encoder}.
*/
public static final TextDecoder DEFAULT_DECODER = JSR283_DECODER;
@@ -274,20 +274,40 @@
public boolean isRoot();
/**
- * Determine whether this path represents the same as the supplied path. This is
equivalent to calling
- * <code>this.compareTo(other) == 0 </code>.
+ * Determine whether this path represents the same as the supplied path. This is
equivalent to calling <code>
+ * this.compareTo(other) == 0 </code>.
*
- * @param other the other path to compare with this path
+ * @param other the other path to compare with this path; may be null
* @return true if the paths are equivalent, or false otherwise
*/
- public boolean isSame( Path other );
+ public boolean isSameAs( Path other );
/**
+ * Determine whether this path is the {@link #isSameAs(Path) same as} to or a {@link
#isAncestorOf(Path) ancestor of} the
+ * supplied path. This method is equivalent to (but may be more efficient than)
calling <code>isSame(other) ||
+ * isAncestor(other)</code>, and is a convenience method that is identical to
calling <code>other.isAtOrBelow(this)</code>.
+ *
+ * @param other the other path to compare with this path; may be null
+ * @return true if the paths are equivalent or if this path is considered an ancestor
of the other path, or false otherwise
+ */
+ public boolean isAtOrAbove( Path other );
+
+ /**
+ * Determine whether this path is the {@link #isSameAs(Path) same as} to or a {@link
#isDecendantOf(Path) decendant of} the
+ * supplied path. This method is equivalent to (but may be more efficient than)
calling <code>isSame(other) ||
+ * isAncestor(other)</code>.
+ *
+ * @param other the other path to compare with this path; may be null
+ * @return true if the paths are equivalent or if this path is considered a decendant
of the other path, or false otherwise
+ */
+ public boolean isAtOrBelow( Path other );
+
+ /**
* Determine whether this path is an ancestor of the supplied path. A path is
considered an ancestor of another path if the
* the ancestor path appears in its entirety at the beginning of the decendant path,
and where the decendant path contains at
* least one additional segment.
*
- * @param decendant the path that may be the decendant
+ * @param decendant the path that may be the decendant; may be null
* @return true if this path is an ancestor of the supplied path, or false otherwise
*/
public boolean isAncestorOf( Path decendant );
@@ -296,14 +316,14 @@
* Determine whether this path is an decendant of the supplied path. A path is
considered a decendant of another path if the
* the decendant path starts exactly with the entire ancestor path but contains at
least one additional segment.
*
- * @param ancestor the path that may be the ancestor
+ * @param ancestor the path that may be the ancestor; may be null
* @return true if this path is an decendant of the supplied path, or false
otherwise
*/
public boolean isDecendantOf( Path ancestor );
/**
- * Return whether this path is an absolute path. A path is either relative or {@link
#isAbsolute() absolute}. An absolute
- * path starts with a "/".
+ * Return whether this path is an absolute path. A path is either relative or {@link
#isAbsolute() absolute}. An absolute path
+ * starts with a "/".
*
* @return true if the path is absolute, or false otherwise
*/
@@ -372,11 +392,11 @@
public Path getAncestor();
/**
- * Return the path to the ancestor of the supplied degree. An ancestor of degree
<code>x</code> is the path that is
- * <code>x</code> levels up along the path. For example,
<code>degree = 0</code> returns this path, while
- * <code>degree = 1</code> returns the parent of this path,
<code>degree = 2</code> returns the grandparent of this path,
- * and so on. Note that the result may be unexpected if this path is not {@link
#isNormalized() normalized}, as a
- * non-normalized path contains ".." and "." segments.
+ * Return the path to the ancestor of the supplied degree. An ancestor of degree
<code>x</code> is the path that is <code>x
+ * </code> levels up along the path. For example, <code>degree =
0</code> returns this path, while <code>degree = 1</code>
+ * returns the parent of this path, <code>degree = 2</code> returns the
grandparent of this path, and so on. Note that the
+ * result may be unexpected if this path is not {@link #isNormalized() normalized},
as a non-normalized path contains ".." and
+ * "." segments.
*
* @param degree
* @return the ancestor of the supplied degree
@@ -426,21 +446,20 @@
*
* @param beginIndex the beginning index, inclusive.
* @return the specified subpath
- * @exception IndexOutOfBoundsException if the <code>beginIndex</code> is
negative or larger than the length of this
- * <code>Path</code> object
+ * @exception IndexOutOfBoundsException if the <code>beginIndex</code> is
negative or larger than the length of this <code>
+ * Path</code> object
*/
public Path subpath( int beginIndex );
/**
- * Return a new path consisting of the segments between the
<code>beginIndex</code> index (inclusive) and the
- * <code>endIndex</code> index (exclusive).
+ * Return a new path consisting of the segments between the
<code>beginIndex</code> index (inclusive) and the <code>endIndex
+ * </code> index (exclusive).
*
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the specified subpath
- * @exception IndexOutOfBoundsException if the <code>beginIndex</code> is
negative, or <code>endIndex</code> is larger
- * than the length of this <code>Path</code> object, or
<code>beginIndex</code> is larger than
- * <code>endIndex</code>.
+ * @exception IndexOutOfBoundsException if the <code>beginIndex</code> is
negative, or <code>endIndex</code> is larger than
+ * the length of this <code>Path</code> object, or
<code>beginIndex</code> is larger than <code>endIndex</code>.
*/
public Path subpath( int beginIndex,
int endIndex );
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathFactory.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathFactory.java 2008-07-23
17:17:39 UTC (rev 368)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathFactory.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -60,8 +60,8 @@
Path createAbsolutePath( Path.Segment... segments );
/**
- * Create an empty relative path (i.e., equivalent to {@link
#createRelativePath(Path.Segment...) createRelativePath}({@link Path#SELF_SEGMENT})).
- * Subsequent calls will always return the same instance.
+ * Create an empty relative path (i.e., equivalent to {@link
#createRelativePath(Path.Segment...) createRelativePath}(
+ * {@link Path#SELF_SEGMENT})). Subsequent calls will always return the same
instance.
*
* @return the new path
*/
@@ -136,12 +136,23 @@
Path.Segment... segments );
/**
+ * Create a path by appending the supplied names to the parent path.
+ *
+ * @param parentPath the path that is to provide the basis for the new path
+ * @param subpath the subpath to be appended to the parent path, which must be in the
form of a relative path
+ * @return the new path
+ * @throws IllegalArgumentException if the parent path reference or the segment name
is null, or if the index is invalid
+ */
+ Path create( Path parentPath,
+ String subpath );
+
+ /**
* Create a path segment given the supplied segment name. The resulting segment will
have no index.
*
* @param segmentName the name of the segment
* @return the segment
- * @throws IllegalArgumentException if the segment name reference is
<code>null</code> or the value could not be created
- * from the supplied string
+ * @throws IllegalArgumentException if the segment name reference is
<code>null</code> or the value could not be created from
+ * the supplied string
*/
Path.Segment createSegment( String segmentName );
@@ -151,8 +162,8 @@
* @param segmentName the name of the segment
* @param decoder the decoder that should be used to decode the qualified name
* @return the segment
- * @throws IllegalArgumentException if the segment name reference is
<code>null</code> or the value could not be created
- * from the supplied string
+ * @throws IllegalArgumentException if the segment name reference is
<code>null</code> or the value could not be created from
+ * the supplied string
*/
Path.Segment createSegment( String segmentName,
TextDecoder decoder );
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/AbstractCommandExecutor.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/AbstractCommandExecutor.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/AbstractCommandExecutor.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -21,6 +21,7 @@
*/
package org.jboss.dna.spi.graph.commands.executor;
+import org.jboss.dna.spi.graph.DateTime;
import org.jboss.dna.spi.graph.commands.CompositeCommand;
import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
@@ -58,13 +59,21 @@
private final ExecutionEnvironment env;
private final String sourceName;
+ private final DateTime nowInUtc;
protected AbstractCommandExecutor( ExecutionEnvironment env,
String sourceName ) {
+ this(env, sourceName, null);
+ }
+
+ protected AbstractCommandExecutor( ExecutionEnvironment env,
+ String sourceName,
+ DateTime now ) {
assert env != null;
assert sourceName != null && sourceName.trim().length() != 0;
this.env = env;
this.sourceName = sourceName;
+ this.nowInUtc = now != null ? now.toUtcTimeZone() :
env.getValueFactories().getDateFactory().createUtc();
}
/**
@@ -86,6 +95,15 @@
}
/**
+ * Get the current time associated with this executor. All calls to this method will
result in the same time.
+ *
+ * @return the current time expressed in UTC
+ */
+ public DateTime getCurrentTimeInUtc() {
+ return nowInUtc;
+ }
+
+ /**
* {@inheritDoc}
* <p>
* This implementation examines the instance to see which {@link GraphCommand command
interfaces} are implemented by the
@@ -101,6 +119,9 @@
return;
}
// The command could implement multiple "get" behaviors
+ if (command instanceof GetNodeCommand) {
+ execute((GetNodeCommand)command);
+ }
if (command instanceof GetPropertiesCommand) {
execute((GetPropertiesCommand)command);
}
@@ -145,7 +166,22 @@
/**
* {@inheritDoc}
+ * <p>
+ * This method implementation simply delegates to both the {@link
#execute(GetPropertiesCommand)} and
+ * {@link #execute(GetChildrenCommand)} methods, and should be overridden by
subclasses that can process
+ * {@link GetNodeCommand} more efficiently as a single command.
+ * </p>
*
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetNodeCommand)
+ */
+ public void execute( GetNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ execute((GetPropertiesCommand)command);
+ execute((GetChildrenCommand)command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetPropertiesCommand)
*/
@SuppressWarnings( "unused" )
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/CommandExecutor.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/CommandExecutor.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/CommandExecutor.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -27,6 +27,7 @@
import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
import org.jboss.dna.spi.graph.commands.DeleteBranchCommand;
import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetNodeCommand;
import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
import org.jboss.dna.spi.graph.commands.GraphCommand;
import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
@@ -60,6 +61,17 @@
void execute( CompositeCommand command ) throws RepositorySourceException,
InterruptedException;
/**
+ * Execute a command to get the properties and children of a node. {@link
GetNodeCommand} is a subtype of both
+ * {@link GetPropertiesCommand} and {@link GetChildrenCommand}, so this method will
be called in place of the
+ * {@link #execute(GetPropertiesCommand)} and {@link #execute(GetChildrenCommand)}
methods.
+ *
+ * @param command the command to be executed; may not be null
+ * @throws RepositorySourceException if there is an error executing the command
+ * @throws InterruptedException if the thread is interrupted during execution
+ */
+ void execute( GetNodeCommand command ) throws RepositorySourceException,
InterruptedException;
+
+ /**
* Execute a command to get the properties of a node.
*
* @param command the command to be executed; may not be null
Added:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/DelegatingCommandExecutor.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/DelegatingCommandExecutor.java
(rev 0)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/DelegatingCommandExecutor.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,167 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.commands.executor;
+
+import org.jboss.dna.spi.graph.commands.CompositeCommand;
+import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
+import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
+import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
+import org.jboss.dna.spi.graph.commands.DeleteBranchCommand;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetNodeCommand;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
+import org.jboss.dna.spi.graph.commands.RecordBranchCommand;
+import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+public class DelegatingCommandExecutor implements CommandExecutor {
+
+ private final CommandExecutor delegate;
+
+ public DelegatingCommandExecutor( CommandExecutor delegate ) {
+ assert delegate != null;
+ this.delegate = delegate;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.executor.CommandExecutor#close()
+ */
+ public void close() throws InterruptedException {
+ delegate.close();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.GraphCommand)
+ */
+ public void execute( GraphCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.CompositeCommand)
+ */
+ public void execute( CompositeCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetNodeCommand)
+ */
+ public void execute( GetNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetPropertiesCommand)
+ */
+ public void execute( GetPropertiesCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetChildrenCommand)
+ */
+ public void execute( GetChildrenCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.CreateNodeCommand)
+ */
+ public void execute( CreateNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.SetPropertiesCommand)
+ */
+ public void execute( SetPropertiesCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.CopyNodeCommand)
+ */
+ public void execute( CopyNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.CopyBranchCommand)
+ */
+ public void execute( CopyBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.RecordBranchCommand)
+ */
+ public void execute( RecordBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.DeleteBranchCommand)
+ */
+ public void execute( DeleteBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.CommandExecutor#execute(org.jboss.dna.spi.graph.commands.MoveBranchCommand)
+ */
+ public void execute( MoveBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ delegate.execute(command);
+ }
+
+}
Added:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/LoggingCommandExecutor.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/LoggingCommandExecutor.java
(rev 0)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/LoggingCommandExecutor.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,233 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.commands.executor;
+
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.spi.SpiI18n;
+import org.jboss.dna.spi.graph.commands.CompositeCommand;
+import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
+import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
+import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
+import org.jboss.dna.spi.graph.commands.DeleteBranchCommand;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetNodeCommand;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
+import org.jboss.dna.spi.graph.commands.RecordBranchCommand;
+import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+public class LoggingCommandExecutor extends DelegatingCommandExecutor {
+
+ private final Logger logger;
+ private final Logger.Level level;
+
+ /**
+ * Create a command executor that logs before and after each method call, logging
messages at the {@link Logger.Level#TRACE
+ * trace} level.
+ *
+ * @param delegate the delegate executor
+ * @param logger the logger
+ */
+ public LoggingCommandExecutor( CommandExecutor delegate,
+ Logger logger ) {
+ this(delegate, logger, Logger.Level.TRACE);
+ }
+
+ /**
+ * Create a command executor that logs before and after each method call, logging
messages at the supplied
+ * {@link Logger.Level level}.
+ *
+ * @param delegate the delegate executor
+ * @param logger the logger
+ * @param level the logging level, or null if {@link Logger.Level#TRACE trace-level}
logging should be used.
+ */
+ public LoggingCommandExecutor( CommandExecutor delegate,
+ Logger logger,
+ Logger.Level level ) {
+ super(delegate);
+ assert logger != null;
+ this.logger = logger;
+ this.level = level != null ? level : Logger.Level.TRACE;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#close()
+ */
+ @Override
+ public void close() throws InterruptedException {
+ this.logger.log(level, SpiI18n.closingCommandExecutor);
+ super.close();
+ this.logger.log(level, SpiI18n.closedCommandExecutor);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CompositeCommand)
+ */
+ @Override
+ public void execute( CompositeCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CopyBranchCommand)
+ */
+ @Override
+ public void execute( CopyBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CopyNodeCommand)
+ */
+ @Override
+ public void execute( CopyNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CreateNodeCommand)
+ */
+ @Override
+ public void execute( CreateNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.DeleteBranchCommand)
+ */
+ @Override
+ public void execute( DeleteBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetChildrenCommand)
+ */
+ @Override
+ public void execute( GetChildrenCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetNodeCommand)
+ */
+ @Override
+ public void execute( GetNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetPropertiesCommand)
+ */
+ @Override
+ public void execute( GetPropertiesCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GraphCommand)
+ */
+ @Override
+ public void execute( GraphCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.MoveBranchCommand)
+ */
+ @Override
+ public void execute( MoveBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.RecordBranchCommand)
+ */
+ @Override
+ public void execute( RecordBranchCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.DelegatingCommandExecutor#execute(org.jboss.dna.spi.graph.commands.SetPropertiesCommand)
+ */
+ @Override
+ public void execute( SetPropertiesCommand command ) throws RepositorySourceException,
InterruptedException {
+ this.logger.log(level, SpiI18n.executingGraphCommand, command);
+ super.execute(command);
+ this.logger.log(level, SpiI18n.executedGraphCommand, command);
+ }
+
+}
Added:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/NoOpCommandExecutor.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/NoOpCommandExecutor.java
(rev 0)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/executor/NoOpCommandExecutor.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,189 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.commands.executor;
+
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.commands.CompositeCommand;
+import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
+import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
+import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
+import org.jboss.dna.spi.graph.commands.DeleteBranchCommand;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetNodeCommand;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
+import org.jboss.dna.spi.graph.commands.RecordBranchCommand;
+import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+public class NoOpCommandExecutor extends AbstractCommandExecutor {
+
+ /**
+ * Create a command executor that does nothing.
+ *
+ * @param env the execution environment in which the executor will be run; may not be
null
+ * @param sourceName the name of the {@link RepositorySource} that is making use of
this executor; may not be null or empty
+ */
+ public NoOpCommandExecutor( ExecutionEnvironment env,
+ String sourceName ) {
+ super(env, sourceName);
+ }
+
+ /**
+ * Create a command executor that does nothing.
+ *
+ * @param env the execution environment in which the executor will be run; may not be
null
+ * @param sourceName the name of the {@link RepositorySource} that is making use of
this executor; may not be null or empty
+ * @param now the current time; may be null if the system time is to be used
+ */
+ public NoOpCommandExecutor( ExecutionEnvironment env,
+ String sourceName,
+ DateTime now ) {
+ super(env, sourceName, now);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GraphCommand)
+ */
+ @Override
+ public void execute( GraphCommand command ) throws RepositorySourceException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CompositeCommand)
+ */
+ @Override
+ public void execute( CompositeCommand command ) throws RepositorySourceException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetNodeCommand)
+ */
+ @Override
+ public void execute( GetNodeCommand command ) throws RepositorySourceException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CopyBranchCommand)
+ */
+ @Override
+ public void execute( CopyBranchCommand command ) throws RepositorySourceException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CopyNodeCommand)
+ */
+ @Override
+ public void execute( CopyNodeCommand command ) throws RepositorySourceException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.CreateNodeCommand)
+ */
+ @Override
+ public void execute( CreateNodeCommand command ) throws RepositorySourceException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.DeleteBranchCommand)
+ */
+ @Override
+ public void execute( DeleteBranchCommand command ) throws RepositorySourceException
{
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetChildrenCommand)
+ */
+ @Override
+ public void execute( GetChildrenCommand command ) throws RepositorySourceException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.GetPropertiesCommand)
+ */
+ @Override
+ public void execute( GetPropertiesCommand command ) throws RepositorySourceException
{
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.MoveBranchCommand)
+ */
+ @Override
+ public void execute( MoveBranchCommand command ) throws RepositorySourceException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.RecordBranchCommand)
+ */
+ @Override
+ public void execute( RecordBranchCommand command ) throws RepositorySourceException
{
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.spi.graph.commands.SetPropertiesCommand)
+ */
+ @Override
+ public void execute( SetPropertiesCommand command ) throws RepositorySourceException
{
+ // do nothing
+ }
+}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCompositeCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCompositeCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCompositeCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -68,4 +68,14 @@
return this;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + " (containing " +
commands.size() + " commands)";
+ }
+
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCopyNodeCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCopyNodeCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCopyNodeCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -38,7 +38,8 @@
* @param oldPath the path to the original; may not be null
* @param newPath the path to the copy; may not be null
*/
- public BasicCopyNodeCommand( Path oldPath, Path newPath ) {
+ public BasicCopyNodeCommand( Path oldPath,
+ Path newPath ) {
super();
assert oldPath != null;
assert newPath != null;
@@ -60,4 +61,14 @@
return newPath;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + " from " + this.getPath() +
" to " + this.getNewPath();
+ }
+
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCreateNodeCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCreateNodeCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCreateNodeCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -23,6 +23,7 @@
import java.util.List;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.spi.graph.Path;
import org.jboss.dna.spi.graph.Property;
import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
@@ -84,7 +85,7 @@
*/
public int compareTo( CreateNodeCommand that ) {
if (this == that) return 0;
- return this.path.compareTo(that.getPath());
+ return this.getPath().compareTo(that.getPath());
}
/**
@@ -107,4 +108,38 @@
}
return false;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getSimpleName());
+ sb.append(" at ");
+ sb.append(this.getPath());
+ boolean firstProperty = true;
+ for (Property property : this.getProperties()) {
+ if (property.isEmpty()) continue;
+ if (firstProperty) {
+ sb.append(" { ");
+ firstProperty = false;
+ } else {
+ sb.append("; ");
+ }
+ sb.append(property.getName());
+ sb.append("=");
+ if (property.isSingle()) {
+ sb.append(StringUtil.readableString(property.getValues().next()));
+ } else {
+ sb.append(StringUtil.readableString(property.getValuesAsArray()));
+ }
+ }
+ if (!firstProperty) {
+ sb.append(" }");
+ }
+ return sb.toString();
+ }
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicDeleteBranchCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicDeleteBranchCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicDeleteBranchCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -49,4 +49,13 @@
return path;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + " at " + this.getPath();
+ }
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetChildrenCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetChildrenCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetChildrenCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -25,6 +25,7 @@
import java.util.Iterator;
import java.util.List;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.spi.cache.CachePolicy;
import org.jboss.dna.spi.graph.Name;
import org.jboss.dna.spi.graph.Path;
@@ -131,4 +132,22 @@
this.cachePolicy = cachePolicy;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getSimpleName());
+ sb.append(" at ");
+ sb.append(this.getPath());
+ List<Path.Segment> children = this.getChildren();
+ if (children != null && children.size() > 0) {
+ sb.append(" with ").append(children.size()).append(" children:
");
+ sb.append(StringUtil.readableString(children));
+ }
+ return sb.toString();
+ }
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetNodeCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetNodeCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetNodeCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -26,8 +26,10 @@
import java.util.Iterator;
import java.util.List;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.spi.graph.Name;
import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
import org.jboss.dna.spi.graph.Path.Segment;
import org.jboss.dna.spi.graph.commands.GetNodeCommand;
import org.jboss.dna.spi.graph.impl.BasicPathSegment;
@@ -52,6 +54,13 @@
}
/**
+ * @return children
+ */
+ public List<Segment> getChildren() {
+ return children;
+ }
+
+ /**
* {@inheritDoc}
*/
public void setChild( Name nameOfChild ) {
@@ -111,4 +120,43 @@
children = Collections.emptyList();
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getSimpleName());
+ sb.append(" at ");
+ sb.append(this.getPath());
+ boolean firstProperty = true;
+ for (Property property : this.getPropertyIterator()) {
+ if (property.isEmpty()) continue;
+ if (firstProperty) {
+ sb.append(" { ");
+ firstProperty = false;
+ } else {
+ sb.append("; ");
+ }
+ sb.append(property.getName());
+ sb.append("=");
+ if (property.isSingle()) {
+ sb.append(StringUtil.readableString(property.getValues().next()));
+ } else {
+ sb.append(StringUtil.readableString(property.getValuesAsArray()));
+ }
+ }
+ if (!firstProperty) {
+ sb.append(" }");
+ }
+ List<Path.Segment> children = this.getChildren();
+ if (children != null && children.size() > 0) {
+ sb.append(" with ").append(children.size()).append(" children:
");
+ sb.append(StringUtil.readableString(children));
+ }
+ return sb.toString();
+ }
+
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetPropertiesCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetPropertiesCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetPropertiesCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -24,6 +24,7 @@
import java.util.HashMap;
import java.util.Map;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.spi.cache.CachePolicy;
import org.jboss.dna.spi.graph.Name;
import org.jboss.dna.spi.graph.Path;
@@ -110,4 +111,37 @@
this.cachePolicy = cachePolicy;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getSimpleName());
+ sb.append(" at ");
+ sb.append(this.getPath());
+ boolean firstProperty = true;
+ for (Property property : this.getPropertyIterator()) {
+ if (property.isEmpty()) continue;
+ if (firstProperty) {
+ sb.append(" { ");
+ firstProperty = false;
+ } else {
+ sb.append("; ");
+ }
+ sb.append(property.getName());
+ sb.append("=");
+ if (property.isSingle()) {
+ sb.append(StringUtil.readableString(property.getValues().next()));
+ } else {
+ sb.append(StringUtil.readableString(property.getValuesAsArray()));
+ }
+ }
+ if (!firstProperty) {
+ sb.append(" }");
+ }
+ return sb.toString();
+ }
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicMoveBranchCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicMoveBranchCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicMoveBranchCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -74,4 +74,14 @@
return conflictBehavior;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + " from " + this.getPath() +
" to " + this.getNewPath();
+ }
+
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicRecordBranchCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicRecordBranchCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicRecordBranchCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -167,8 +167,8 @@
* Method that is called whenver a node is recorded by the recipient of this command.
This implementation simply records it,
* but subclasses can override this method to respond immediately.
*
- * @param command the command containing the node information; never null and always
above the
- * {@link #getMaxDepth() maximum depth}.
+ * @param command the command containing the node information; never null and always
above the {@link #getMaxDepth() maximum
+ * depth}.
*/
protected void record( CreateNodeCommand command ) {
commands.add(command);
@@ -182,4 +182,15 @@
public List<CreateNodeCommand> getCreateNodeCommands() {
return this.commands;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + " at " + this.getPath();
+ }
+
}
Modified:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicSetPropertiesCommand.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicSetPropertiesCommand.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicSetPropertiesCommand.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -23,6 +23,7 @@
import java.util.List;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.spi.graph.Path;
import org.jboss.dna.spi.graph.Property;
import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
@@ -65,4 +66,38 @@
public Iterable<Property> getProperties() {
return properties;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getSimpleName());
+ sb.append(" at ");
+ sb.append(this.getPath());
+ boolean firstProperty = true;
+ for (Property property : this.getProperties()) {
+ if (property.isEmpty()) continue;
+ if (firstProperty) {
+ sb.append(" { ");
+ firstProperty = false;
+ } else {
+ sb.append("; ");
+ }
+ sb.append(property.getName());
+ sb.append("=");
+ if (property.isSingle()) {
+ sb.append(StringUtil.readableString(property.getValues().next()));
+ } else {
+ sb.append(StringUtil.readableString(property.getValuesAsArray()));
+ }
+ }
+ if (!firstProperty) {
+ sb.append(" }");
+ }
+ return sb.toString();
+ }
}
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/BasicPath.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/BasicPath.java 2008-07-23
17:17:39 UTC (rev 368)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/BasicPath.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -307,7 +307,41 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.Path#isAtOrBelow(org.jboss.dna.spi.graph.Path)
*/
+ public boolean isAtOrBelow( Path other ) {
+ if (other == null) return false;
+ if (this == other) return true;
+ Iterator<Segment> thisIter = this.segments.iterator();
+ Iterator<Segment> thatIter = other.iterator();
+ while (thisIter.hasNext() && thatIter.hasNext()) {
+ if (!thisIter.next().equals(thatIter.next())) return false;
+ }
+ if (thatIter.hasNext()) return false; // The other still has segments, but this
doesn't
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.Path#isAtOrAbove(org.jboss.dna.spi.graph.Path)
+ */
+ public boolean isAtOrAbove( Path other ) {
+ if (other == null) return false;
+ if (this == other) return true;
+ Iterator<Segment> thisIter = this.segments.iterator();
+ Iterator<Segment> thatIter = other.iterator();
+ while (thisIter.hasNext() && thatIter.hasNext()) {
+ if (!thisIter.next().equals(thatIter.next())) return false;
+ }
+ if (thisIter.hasNext()) return false; // This still has segments, but other
doesn't
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public boolean isDecendantOf( Path ancestor ) {
if (ancestor == null) return false;
return ancestor.isAncestorOf(this);
@@ -330,8 +364,8 @@
/**
* {@inheritDoc}
*/
- public boolean isSame( Path other ) {
- return this.compareTo(other) == 0;
+ public boolean isSameAs( Path other ) {
+ return other != null && this.compareTo(other) == 0;
}
/**
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/PathValueFactory.java
===================================================================
---
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/PathValueFactory.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/PathValueFactory.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -395,7 +395,19 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.PathFactory#create(org.jboss.dna.spi.graph.Path,
java.lang.String)
*/
+ public Path create( Path parentPath,
+ String subpath ) {
+ // Create a relative path for the subpath ...
+ Path relativeSubpath = create(subpath);
+ return create(parentPath, relativeSubpath);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public Segment createSegment( Name segmentName ) {
ArgCheck.isNotNull(segmentName, "segment name");
if (Path.SELF_NAME.equals(segmentName)) return Path.SELF_SEGMENT;
Modified: trunk/dna-spi/src/main/resources/org/jboss/dna/spi/SpiI18n.properties
===================================================================
--- trunk/dna-spi/src/main/resources/org/jboss/dna/spi/SpiI18n.properties 2008-07-23
17:17:39 UTC (rev 368)
+++ trunk/dna-spi/src/main/resources/org/jboss/dna/spi/SpiI18n.properties 2008-07-24
19:52:13 UTC (rev 369)
@@ -45,3 +45,8 @@
pathExpressionIsInvalid = The path expression {0} is not valid
pathExpressionHasInvalidSelect = Invalid select expression "{0}" in the path
expression "{1}"
pathExpressionHasInvalidMatch = Invalid match expression "{0}" in the path
expression "{1}"
+
+executingGraphCommand = Executing {0}
+executedGraphCommand = Executed {0}
+closingCommandExecutor = Closing command executor
+closedCommandExecutor = Closed command executor
Modified:
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/commands/executor/AbstractCommandExecutorTest.java
===================================================================
---
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/commands/executor/AbstractCommandExecutorTest.java 2008-07-23
17:17:39 UTC (rev 368)
+++
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/commands/executor/AbstractCommandExecutorTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -44,6 +44,7 @@
import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
import org.jboss.dna.spi.graph.commands.RecordBranchCommand;
import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
+import org.jboss.dna.spi.graph.connection.BasicExecutionEnvironment;
import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
import org.jboss.dna.spi.graph.connection.RepositorySourceException;
import org.junit.Before;
@@ -61,7 +62,6 @@
private AbstractCommandExecutor executor;
private GraphCommand command;
- @Mock
private ExecutionEnvironment env;
@Mock
protected CommandExecutor validator;
@@ -69,6 +69,7 @@
@Before
public void beforeEach() throws Exception {
MockitoAnnotations.initMocks(this);
+ env = new BasicExecutionEnvironment();
executor = new ExecutorImpl(env, "Source X", validator);
}
@@ -123,6 +124,7 @@
verify(validator, times(2)).execute((GetPropertiesCommand)getNodeCommand);
verify(validator, times(2)).execute((GetChildrenCommand)getNodeCommand);
verify(validator, times(1)).execute(createNodeCommand);
+ verify(validator, times(2)).execute(getNodeCommand);
verifyNoMoreInteractions(validator);
}
@@ -139,6 +141,7 @@
verify(validator, times(2)).execute((GetPropertiesCommand)getNodeCommand);
verify(validator, times(2)).execute((GetChildrenCommand)getNodeCommand);
verify(validator, times(1)).execute(createNodeCommand);
+ verify(validator, times(2)).execute(getNodeCommand);
verifyNoMoreInteractions(validator);
}
@@ -149,6 +152,7 @@
verify(validator, times(1)).execute((GraphCommand)getNodeCommand);
verify(validator, times(1)).execute((GetPropertiesCommand)getNodeCommand);
verify(validator, times(1)).execute((GetChildrenCommand)getNodeCommand);
+ verify(validator, times(1)).execute(getNodeCommand);
verifyNoMoreInteractions(validator);
}
@@ -265,6 +269,11 @@
}
@Override
+ public void execute( GetNodeCommand command ) throws RepositorySourceException,
InterruptedException {
+ validator.execute(command);
+ }
+
+ @Override
public void execute( RecordBranchCommand command ) throws
RepositorySourceException, InterruptedException {
validator.execute(command);
}
Copied:
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepository.java (from
rev 337,
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/SimpleRepository.java)
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepository.java
(rev 0)
+++
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepository.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,178 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.connection;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+
+/**
+ * A very simple repository that maintains properties for nodes identified by a path, and
computes the children based upon the set
+ * of paths registered in the {@link #getData() data}.
+ * <p>
+ * Note that the repository does not automatically rename same-name siblings when nodes
are
+ * {@link #delete(ExecutionEnvironment, String) deleted} or {@link
#create(ExecutionEnvironment, String) explicitly} or
+ * {@link #setProperty(ExecutionEnvironment, String, String, Object...) implicitly}
created.
+ * </p>
+ *
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class SimpleRepository {
+
+ private static final ConcurrentMap<String, SimpleRepository> repositoriesByName
= new ConcurrentHashMap<String, SimpleRepository>();
+
+ public static SimpleRepository get( String name ) {
+ return repositoriesByName.get(name);
+ }
+
+ public static void shutdownAll() {
+ for (SimpleRepository repository : repositoriesByName.values()) {
+ repository.shutdown();
+ }
+ }
+
+ private ConcurrentMap<Path, Map<Name, Property>> data = new
ConcurrentHashMap<Path, Map<Name, Property>>();
+ private final String repositoryName;
+ private boolean shutdown = false;
+
+ public SimpleRepository( String repositoryName ) {
+ this.repositoryName = repositoryName;
+ if (repositoriesByName.putIfAbsent(repositoryName, this) != null) {
+ throw new IllegalArgumentException("Repository \"" +
repositoryName + "\" already exists and may not be recreated");
+ }
+ }
+
+ /**
+ * @return repositoryName
+ */
+ public String getRepositoryName() {
+ return repositoryName;
+ }
+
+ /**
+ * Get the current modifiable map of property data
+ *
+ * @return data
+ */
+ public ConcurrentMap<Path, Map<Name, Property>> getData() {
+ return data;
+ }
+
+ /**
+ * Utility method to help set the property on the node given by the supplied path. If
the node does not exist, it will be
+ * created.
+ *
+ * @param env the environment; may not be null
+ * @param path the path to the node; may not be null
+ * @param propertyName the property name; may not be null
+ * @param values the values of the property
+ * @return this repository, for method chaining
+ */
+ public SimpleRepository setProperty( ExecutionEnvironment env,
+ String path,
+ String propertyName,
+ Object... values ) {
+ PathFactory pathFactory = env.getValueFactories().getPathFactory();
+ NameFactory nameFactory = env.getValueFactories().getNameFactory();
+ PropertyFactory propertyFactory = env.getPropertyFactory();
+ Path pathObj = pathFactory.create(path);
+ create(env, pathObj.getAncestor().getString(env.getNamespaceRegistry()));
+ Property property = propertyFactory.create(nameFactory.create(propertyName),
values);
+ Map<Name, Property> properties = new HashMap<Name, Property>();
+ Map<Name, Property> existingProperties = data.putIfAbsent(pathObj,
properties);
+ if (existingProperties == null) existingProperties = properties;
+ existingProperties.put(property.getName(), property);
+ return this;
+ }
+
+ /**
+ * Create the node if it does not exist.
+ *
+ * @param env the environment; may not be null
+ * @param path the path to the node; may not be null
+ * @return this repository, for method chaining
+ */
+ public SimpleRepository create( ExecutionEnvironment env,
+ String path ) {
+ PathFactory pathFactory = env.getValueFactories().getPathFactory();
+ Path pathObj = pathFactory.create(path);
+ Path ancestorPath = pathObj.getAncestor();
+ while (!ancestorPath.isRoot()) {
+ data.putIfAbsent(ancestorPath, new HashMap<Name, Property>());
+ ancestorPath = ancestorPath.getAncestor();
+ }
+ data.putIfAbsent(pathObj, new HashMap<Name, Property>());
+ return this;
+ }
+
+ /**
+ * Delete the branch rooted at the supplied path, if it exists.
+ *
+ * @param env the environment; may not be null
+ * @param path the path to the branch's top node; may not be null
+ * @return this repository, for method chaining
+ */
+ public SimpleRepository delete( ExecutionEnvironment env,
+ String path ) {
+ PathFactory pathFactory = env.getValueFactories().getPathFactory();
+ Path pathObj = pathFactory.create(path);
+ List<Path> pathsToRemove = new LinkedList<Path>();
+ for (Path nodePath : data.keySet()) {
+ if (nodePath.equals(pathObj) || nodePath.isDecendantOf(pathObj)) {
+ pathsToRemove.add(nodePath);
+ }
+ }
+ for (Path pathToRemove : pathsToRemove) {
+ data.remove(pathToRemove);
+ }
+ return this;
+ }
+
+ /**
+ * @param data new new map of property data
+ */
+ public void setData( ConcurrentMap<Path, Map<Name, Property>> data ) {
+ this.data = data;
+ }
+
+ public boolean isShutdown() {
+ return shutdown;
+ }
+
+ public void shutdown() {
+ shutdown = true;
+ repositoriesByName.remove(this.repositoryName);
+ }
+
+}
Property changes on:
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepository.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Copied:
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepositorySource.java
(from rev 337,
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/SimpleRepositorySource.java)
===================================================================
---
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepositorySource.java
(rev 0)
+++
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepositorySource.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -0,0 +1,294 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.connection;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import javax.naming.Reference;
+import javax.transaction.xa.XAResource;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.InvalidPathException;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.commands.CompositeCommand;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * A {@link RepositorySource} for a {@link SimpleRepository simple repository}.
+ *
+ * @author Randall Hauch
+ */
+public class SimpleRepositorySource implements RepositorySource {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final int DEFAULT_RETRY_LIMIT = 5;
+
+ private String repositoryName;
+ private String name;
+ private int retryLimit = DEFAULT_RETRY_LIMIT;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositorySource#getRetryLimit()
+ */
+ public int getRetryLimit() {
+ return retryLimit;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositorySource#setRetryLimit(int)
+ */
+ public void setRetryLimit( int limit ) {
+ retryLimit = limit;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory#getName()
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name Sets name to the specified value.
+ */
+ public void setName( String name ) {
+ this.name = name;
+ }
+
+ /**
+ * @return repositoryName
+ */
+ public String getRepositoryName() {
+ return repositoryName;
+ }
+
+ /**
+ * @param repositoryName Sets repositoryName to the specified value.
+ */
+ public void setRepositoryName( String repositoryName ) {
+ this.repositoryName = repositoryName;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see javax.naming.Referenceable#getReference()
+ */
+ public Reference getReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory#getConnection()
+ */
+ public RepositoryConnection getConnection() throws RepositorySourceException {
+ String reposName = this.repositoryName;
+ SimpleRepository repository = SimpleRepository.get(reposName);
+ if (repository == null) {
+ throw new RepositorySourceException(this.getName(), "Unable to find
repository \"" + reposName + "\"");
+ }
+ return new Connection(repository);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof SimpleRepositorySource) {
+ SimpleRepositorySource that = (SimpleRepositorySource)obj;
+ if (!this.getName().equals(that.getName())) return false;
+ if (!this.getRepositoryName().equals(that.getRepositoryName())) return
false;
+ return true;
+ }
+ return false;
+ }
+
+ protected class Connection implements RepositoryConnection {
+
+ private RepositorySourceListener listener;
+ private final SimpleRepository repository;
+
+ protected Connection( SimpleRepository repository ) {
+ assert repository != null;
+ this.repository = repository;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnection#close()
+ */
+ public void close() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.connection.RepositoryConnection#execute(org.jboss.dna.spi.graph.connection.ExecutionEnvironment,
+ * org.jboss.dna.spi.graph.commands.GraphCommand[])
+ */
+ public void execute( ExecutionEnvironment env,
+ GraphCommand... commands ) throws RepositorySourceException
{
+ assert env != null;
+ if (repository.isShutdown()) {
+ throw new RepositorySourceException(getName(), "The repository
\"" + repository.getRepositoryName()
+ + "\" is no
longer available");
+ }
+ for (GraphCommand command : commands) {
+ executeCommand(env, command);
+ }
+ }
+
+ protected void executeCommand( ExecutionEnvironment env,
+ GraphCommand command ) {
+ if (command == null) return;
+ if (command instanceof CompositeCommand) {
+ CompositeCommand composite = (CompositeCommand)command;
+ for (GraphCommand nestedCommand : composite) {
+ executeCommand(env, nestedCommand);
+ }
+ }
+ Map<Path, Map<Name, Property>> data = repository.getData();
+ // Only commands we recognize are the following; everything else is ignored
...
+ if (command instanceof GetPropertiesCommand) { // super of GetNodeCommand
+ GetPropertiesCommand getProperties = (GetPropertiesCommand)command;
+ Path targetPath = getProperties.getPath();
+ Map<Name, Property> properties = data.get(targetPath);
+ if (properties == null) {
+ getProperties.setError(new InvalidPathException("Non-existant
node: " + targetPath));
+ return;
+ }
+ for (Property property : properties.values()) {
+ getProperties.setProperty(property);
+ }
+ }
+ if (command instanceof GetChildrenCommand) { // super of GetNodeCommand
+ GetChildrenCommand getChildren = (GetChildrenCommand)command;
+ Path targetPath = getChildren.getPath();
+ if (data.get(targetPath) == null) {
+ getChildren.setError(new InvalidPathException("Non-existant
node: " + targetPath));
+ return;
+ }
+ // Iterate through all of the properties, looking for any paths that are
children of the path ...
+ List<Path.Segment> childSegments = new
LinkedList<Path.Segment>();
+ for (Path path : data.keySet()) {
+ if (path.getAncestor().equals(targetPath)) {
+ childSegments.add(path.getLastSegment());
+ }
+ }
+ // This does not store children order, so sort ...
+ Collections.sort(childSegments);
+ getChildren.setChildren(childSegments);
+ }
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.connection.RepositoryConnection#getDefaultCachePolicy()
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnection#getSourceName()
+ */
+ public String getSourceName() {
+ return SimpleRepositorySource.this.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnection#getXAResource()
+ */
+ public XAResource getXAResource() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnection#ping(long,
java.util.concurrent.TimeUnit)
+ */
+ public boolean ping( long time,
+ TimeUnit unit ) {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.spi.graph.connection.RepositoryConnection#setListener(org.jboss.dna.spi.graph.connection.RepositorySourceListener)
+ */
+ public void setListener( RepositorySourceListener listener ) {
+ this.listener = listener;
+ }
+
+ /**
+ * @return listener
+ */
+ public RepositorySourceListener getListener() {
+ return listener;
+ }
+
+ }
+
+}
Property changes on:
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/SimpleRepositorySource.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/BasicPathTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/BasicPathTest.java 2008-07-23
17:17:39 UTC (rev 368)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/BasicPathTest.java 2008-07-24
19:52:13 UTC (rev 369)
@@ -409,6 +409,96 @@
}
@Test
+ public void shouldConsiderNodeToBeAtOrAboveItself() {
+ assertThat(path.isAtOrAbove(path), is(true));
+ }
+
+ @Test
+ public void shouldConsiderNodeToBeAtOrBelowItself() {
+ assertThat(path.isAtOrBelow(path), is(true));
+ }
+
+ @Test
+ public void shouldConsiderAncestorToBeAtOrAboveTheDecendant() {
+ Path path1 = pathFactory.create("/a/y/z");
+ Path path2 = pathFactory.create("/a/b/c");
+ Path path3 = pathFactory.create("/x/b/c");
+ Path path4 =
pathFactory.create("/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z");
+ for (int i = 1; i < path1.size(); ++i) {
+ assertThat(path1.getAncestor(i).isAtOrAbove(path1), is(true));
+ }
+ for (int i = 1; i < path2.size(); ++i) {
+ assertThat(path2.getAncestor(i).isAtOrAbove(path2), is(true));
+ }
+ for (int i = 1; i < path3.size(); ++i) {
+ assertThat(path3.getAncestor(i).isAtOrAbove(path3), is(true));
+ }
+ for (int i = 1; i < path4.size(); ++i) {
+ assertThat(path4.getAncestor(i).isAtOrAbove(path4), is(true));
+ }
+ }
+
+ @Test
+ public void shouldConsiderDecendantToBeAtOrBelowTheAncestor() {
+ Path path1 = pathFactory.create("/a/y/z");
+ Path path2 = pathFactory.create("/a/b/c");
+ Path path3 = pathFactory.create("/x/b/c");
+ Path path4 =
pathFactory.create("/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z");
+ for (int i = 1; i < path1.size(); ++i) {
+ assertThat(path1.isAtOrBelow(path1.getAncestor(i)), is(true));
+ }
+ for (int i = 1; i < path2.size(); ++i) {
+ assertThat(path2.isAtOrBelow(path2.getAncestor(i)), is(true));
+ }
+ for (int i = 1; i < path3.size(); ++i) {
+ assertThat(path3.isAtOrBelow(path3.getAncestor(i)), is(true));
+ }
+ for (int i = 1; i < path4.size(); ++i) {
+ assertThat(path4.isAtOrBelow(path4.getAncestor(i)), is(true));
+ }
+ }
+
+ @Test
+ public void shouldNotConsiderAncestorToBeAtOrBelowTheDecendant() {
+ Path path1 = pathFactory.create("/a/y/z");
+ Path path2 = pathFactory.create("/a/b/c");
+ Path path3 = pathFactory.create("/x/b/c");
+ Path path4 =
pathFactory.create("/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z");
+ for (int i = 1; i < path1.size(); ++i) {
+ assertThat(path1.getAncestor(i).isAtOrBelow(path1), is(false));
+ }
+ for (int i = 1; i < path2.size(); ++i) {
+ assertThat(path2.getAncestor(i).isAtOrBelow(path2), is(false));
+ }
+ for (int i = 1; i < path3.size(); ++i) {
+ assertThat(path3.getAncestor(i).isAtOrBelow(path3), is(false));
+ }
+ for (int i = 1; i < path4.size(); ++i) {
+ assertThat(path4.getAncestor(i).isAtOrBelow(path4), is(false));
+ }
+ }
+
+ @Test
+ public void shouldNotConsiderDecendantToBeAtOrAboveTheAncestor() {
+ Path path1 = pathFactory.create("/a/y/z");
+ Path path2 = pathFactory.create("/a/b/c");
+ Path path3 = pathFactory.create("/x/b/c");
+ Path path4 =
pathFactory.create("/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z");
+ for (int i = 1; i < path1.size(); ++i) {
+ assertThat(path1.isAtOrAbove(path1.getAncestor(i)), is(false));
+ }
+ for (int i = 1; i < path2.size(); ++i) {
+ assertThat(path2.isAtOrAbove(path2.getAncestor(i)), is(false));
+ }
+ for (int i = 1; i < path3.size(); ++i) {
+ assertThat(path3.isAtOrAbove(path3.getAncestor(i)), is(false));
+ }
+ for (int i = 1; i < path4.size(); ++i) {
+ assertThat(path4.isAtOrAbove(path4.getAncestor(i)), is(false));
+ }
+ }
+
+ @Test
public void shouldReturnNullForLastSegmentOfRoot() {
assertThat(ROOT.getLastSegment(), is(nullValue()));
}
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2008-07-23 17:17:39 UTC (rev 368)
+++ trunk/pom.xml 2008-07-24 19:52:13 UTC (rev 369)
@@ -104,6 +104,7 @@
<module>sequencers/dna-sequencer-cnd</module>
<module>sequencers/dna-sequencer-java</module>
<module>sequencers/dna-sequencer-msoffice</module>
+ <module>connectors/dna-connector-federation</module>
<module>connectors/dna-connector-inmemory</module>
<module>connectors/dna-connector-jbosscache</module>
<module>extensions/dna-mimetype-detector-aperture</module>
@@ -341,6 +342,21 @@
<artifactId>dna-repository</artifactId>
<version>${dna-version}</version>
</dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-federation</artifactId>
+ <version>${dna-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-jbosscache</artifactId>
+ <version>${dna-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-inmemory</artifactId>
+ <version>${dna-version}</version>
+ </dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
<artifactId>dna-mimetype-detector-aperture</artifactId>