[dna-commits] DNA SVN: r377 - in trunk: connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution and 8 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Mon Aug 4 15:59:20 EDT 2008


Author: rhauch
Date: 2008-08-04 15:59:20 -0400 (Mon, 04 Aug 2008)
New Revision: 377

Added:
   trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ContributionStatistics.java
   trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ContributionStatisticsTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/EmptyContributionTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java
   trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java
Modified:
   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/FederatedRepositorySource.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/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/MultiChildContribution.java
   trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContribution.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/NonEmptyContribution.java
   trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OneChildContribution.java
   trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OnePropertyContribution.java
   trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContribution.java
   trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContribution.java
   trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
   trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/BasicCachePolicy.java
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/CachePolicy.java
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/ImmutableCachePolicy.java
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/DateTimeFactory.java
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/JodaDateTime.java
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/JodaDateTimeValueFactory.java
Log:
DNA-115 - Create federation service 
http://jira.jboss.com/jira/browse/DNA-115

Added some methods to the DateTimeFactory to create DateTime by offsetting.  Removed some excess I18n messages.  Added more Contribution subclasses and tests for all the Contribution classes.

Modified: 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	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -231,8 +231,8 @@
     protected CommandExecutor getExecutor( ExecutionContext context,
                                            String sourceName ) {
         FederatedRepositoryConfig config = this.getConfiguration();
-        return new FederatingCommandExecutor(context, sourceName, config.getCacheProjection(), config.getSourceProjections(),
-                                             getConnectionFactories());
+        return new FederatingCommandExecutor(context, sourceName, config.getCacheProjection(), config.getDefaultCachePolicy(),
+                                             config.getSourceProjections(), getConnectionFactories());
     }
 
     /**

Modified: 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	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -98,8 +98,7 @@
     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";
+    protected static final String CACHE_POLICY_TIME_TO_LIVE_CONFIG_PROPERTY_NAME = "dna:timeToLive";
 
     private String repositoryName;
     private String sourceName;
@@ -698,7 +697,7 @@
             executor = new NoOpCommandExecutor(context, configurationSourceName);
         } else {
             // The configuration repository has more than one projection, so we need to merge the results
-            executor = new FederatingCommandExecutor(context, configurationSourceName, null, projections, factories);
+            executor = new FederatingCommandExecutor(context, configurationSourceName, projections, factories);
         }
         // Wrap the executor with a logging executor ...
         executor = new LoggingCommandExecutor(executor, Logger.getLogger(getClass()), Logger.Level.INFO);
@@ -767,14 +766,10 @@
 
             // 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()));
+            Property timeToLiveProperty = getRepository.getProperties().get(nameFactory.create(CACHE_POLICY_TIME_TO_LIVE_CONFIG_PROPERTY_NAME));
+            if (timeToLiveProperty != null && !timeToLiveProperty.isEmpty()) {
+                cachePolicy.setTimeToLive(longFactory.create(timeToLiveProperty.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) {

Modified: 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	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -40,12 +40,8 @@
     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 {

Modified: 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	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -47,10 +47,13 @@
      * Create an empty contribution from the named source.
      * 
      * @param sourceName the name of the source, which may not be null or blank
+     * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @return the contribution
      */
-    public static Contribution create( String sourceName ) {
-        return new EmptyContribution(sourceName);
+    public static Contribution create( String sourceName,
+                                       DateTime expirationTime ) {
+        return new EmptyContribution(sourceName, expirationTime);
     }
 
     /**
@@ -58,16 +61,19 @@
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param property the property from the source; may not be null
      * @return the contribution
      */
     public static Contribution create( String sourceName,
                                        Path pathInSource,
+                                       DateTime expirationTime,
                                        Property property ) {
         if (property == null) {
-            return new EmptyContribution(sourceName);
+            return new EmptyContribution(sourceName, expirationTime);
         }
-        return new OnePropertyContribution(sourceName, pathInSource, property);
+        return new OnePropertyContribution(sourceName, pathInSource, expirationTime, property);
     }
 
     /**
@@ -75,58 +81,98 @@
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param child the child from the source; may not be null or empty
      * @return the contribution
      */
     public static Contribution create( String sourceName,
                                        Path pathInSource,
+                                       DateTime expirationTime,
                                        Segment child ) {
         if (child == null) {
-            return new EmptyContribution(sourceName);
+            return new EmptyContribution(sourceName, expirationTime);
         }
-        return new OneChildContribution(sourceName, pathInSource, child);
+        return new OneChildContribution(sourceName, pathInSource, expirationTime, child);
     }
 
     /**
+     * Create a contribution of a single child from the named source.
+     * 
+     * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
+     * @param child1 the first child from the source; may not be null or empty
+     * @param child2 the second child from the source; may not be null or empty
+     * @return the contribution
+     */
+    public static Contribution create( String sourceName,
+                                       Path pathInSource,
+                                       DateTime expirationTime,
+                                       Segment child1,
+                                       Segment child2 ) {
+        if (child1 != null) {
+            if (child2 != null) {
+                return new TwoChildContribution(sourceName, pathInSource, expirationTime, child1, child2);
+            }
+            return new OneChildContribution(sourceName, pathInSource, expirationTime, child1);
+        }
+        if (child2 != null) {
+            return new OneChildContribution(sourceName, pathInSource, expirationTime, child2);
+        }
+        return new EmptyContribution(sourceName, expirationTime);
+    }
+
+    /**
      * Create a contribution of the supplied properties and children from the named source.
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param properties the properties from the source; may not be null
      * @param children the children from the source; may not be null or empty
      * @return the contribution
      */
     public static Contribution create( String sourceName,
                                        Path pathInSource,
+                                       DateTime expirationTime,
                                        Collection<Property> properties,
                                        Collection<Segment> children ) {
         if (properties == null || properties.isEmpty()) {
             // There are no properties ...
             if (children == null || children.isEmpty()) {
-                return new EmptyContribution(sourceName);
+                return new EmptyContribution(sourceName, expirationTime);
             }
             if (children.size() == 1) {
-                return new OneChildContribution(sourceName, pathInSource, children.iterator().next());
+                return new OneChildContribution(sourceName, pathInSource, expirationTime, children.iterator().next());
             }
-            return new MultiChildContribution(sourceName, pathInSource, children);
+            if (children.size() == 2) {
+                Iterator<Segment> iter = children.iterator();
+                return new TwoChildContribution(sourceName, pathInSource, expirationTime, iter.next(), iter.next());
+            }
+            return new MultiChildContribution(sourceName, pathInSource, expirationTime, children);
         }
         // There are some properties ...
         if (children == null || children.isEmpty()) {
             // There are no children ...
-            switch (properties.size()) {
-                case 1:
-                    return new OnePropertyContribution(sourceName, pathInSource, properties.iterator().next());
-                case 2:
-                    Iterator<Property> iter = properties.iterator();
-                    return new TwoPropertyContribution(sourceName, pathInSource, iter.next(), iter.next());
-                case 3:
-                    Iterator<Property> iter3 = properties.iterator();
-                    return new ThreePropertyContribution(sourceName, pathInSource, iter3.next(), iter3.next(), iter3.next());
+            if (properties.size() == 1) {
+                return new OnePropertyContribution(sourceName, pathInSource, expirationTime, properties.iterator().next());
             }
-            return new MultiPropertyContribution(sourceName, pathInSource, properties);
+            if (properties.size() == 2) {
+                Iterator<Property> iter = properties.iterator();
+                return new TwoPropertyContribution(sourceName, pathInSource, expirationTime, iter.next(), iter.next());
+            }
+            if (properties.size() == 3) {
+                Iterator<Property> iter = properties.iterator();
+                return new ThreePropertyContribution(sourceName, pathInSource, expirationTime, iter.next(), iter.next(),
+                                                     iter.next());
+            }
+            return new MultiPropertyContribution(sourceName, pathInSource, expirationTime, properties);
         }
         // There are some properties AND some children ...
-        return new NodeContribution(sourceName, pathInSource, properties, children);
+        return new NodeContribution(sourceName, pathInSource, expirationTime, properties, children);
     }
 
     /**
@@ -144,10 +190,15 @@
      * Create a contribution for the source with the supplied name and path.
      * 
      * @param sourceName the name of the source, which may not be null or blank
+     * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      */
-    protected Contribution( String sourceName ) {
+    protected Contribution( String sourceName,
+                            DateTime expirationTime ) {
         assert sourceName != null && sourceName.trim().length() != 0;
+        assert expirationTime == null || expirationTime.equals(expirationTime.toUtcTimeZone());
         this.sourceName = sourceName;
+        this.expirationTimeInUtc = expirationTime;
     }
 
     /**
@@ -336,6 +387,7 @@
         private boolean next = true;
 
         protected OneValueIterator( T value ) {
+            assert value != null;
             this.value = value;
         }
 
@@ -354,7 +406,7 @@
          * @see java.util.Iterator#next()
          */
         public T next() {
-            if (!next) {
+            if (next) {
                 next = false;
                 return value;
             }

Added: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ContributionStatistics.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ContributionStatistics.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ContributionStatistics.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,234 @@
+/*
+ * 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.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.HashCode;
+
+/**
+ * Simple utility class to record the distribution of contributions.
+ * 
+ * @author Randall Hauch
+ */
+public class ContributionStatistics {
+
+    /**
+     * This should only be enabled when attempting to accumulate the distribution, and should <i>never</i> be enabled in a
+     * release.
+     */
+    /*package*/static final boolean RECORD = false;
+
+    private static final ConcurrentMap<Stats, AtomicLong> DATA = new ConcurrentHashMap<Stats, AtomicLong>();
+
+    /**
+     * Record a {@link Contribution} was created for the supplied number of properties and children. {@link #RECORD} should be
+     * checked <i>before</i> this method is called.
+     * 
+     * @param propertyCount the number of properties
+     * @param childrenCount the number of children
+     */
+    /*package*/static void record( int propertyCount,
+                                    int childrenCount ) {
+        Stats key = new Stats(propertyCount, childrenCount);
+        AtomicLong existing = DATA.putIfAbsent(key, new AtomicLong(1l));
+        if (existing != null) existing.incrementAndGet();
+    }
+
+    public boolean isRecording() {
+        return RECORD;
+    }
+
+    /**
+     * Get a copy of the raw statistics data.
+     * 
+     * @return a copy of the data; never null
+     */
+    public static Map<Stats, AtomicLong> getData() {
+        return new HashMap<Stats, AtomicLong>(DATA);
+    }
+
+    /**
+     * Get the N most populous combinations of properties and children counts.
+     * 
+     * @param n the maximum number of data objects to find and return in the raw data; must be positive
+     * @return the list of N (or fewer)
+     */
+    public static List<Data> getTop( int n ) {
+        ArgCheck.isPositive(n, "n");
+        LinkedList<Data> results = new LinkedList<Data>();
+        for (Map.Entry<Stats, AtomicLong> entry : DATA.entrySet()) {
+            long value = entry.getValue().get();
+            if (results.size() >= n) {
+                Data last = results.getLast();
+                if (value <= last.getInstanceCount()) continue;
+                // The new count is larger than the smallest, so pop the smallest and add the newest ...
+                results.removeLast();
+            }
+            results.add(new Data(entry.getKey(), value));
+            Collections.sort(results);
+        }
+        return results;
+    }
+
+    public static final class Data implements Comparable<Data> {
+        private final int propertyCount;
+        private final int childrenCount;
+        private final long instanceCount;
+
+        protected Data( Stats stats,
+                        long instanceCount ) {
+            this.propertyCount = stats.getPropertyCount();
+            this.childrenCount = stats.getChildrenCount();
+            this.instanceCount = instanceCount;
+        }
+
+        /**
+         * @return childrenCount
+         */
+        public int getChildrenCount() {
+            return childrenCount;
+        }
+
+        /**
+         * @return propertyCount
+         */
+        public int getPropertyCount() {
+            return propertyCount;
+        }
+
+        /**
+         * @return instanceCount
+         */
+        public long getInstanceCount() {
+            return instanceCount;
+        }
+
+        /**
+         * {@inheritDoc} This orders the values in the opposite order, so that those with larger numbers of instances appear
+         * first.
+         * 
+         * @see java.lang.Comparable#compareTo(java.lang.Object)
+         */
+        public int compareTo( Data that ) {
+            long diff = that.getInstanceCount() - this.getInstanceCount(); // backwards
+            return diff < 0l ? -1 : diff > 0 ? 1 : 0;
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            return HashCode.compute(this.propertyCount, this.childrenCount, this.instanceCount);
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals( Object obj ) {
+            if (obj instanceof Data) {
+                Data that = (Data)obj;
+                if (this.propertyCount != that.propertyCount) return false;
+                if (this.childrenCount != that.childrenCount) return false;
+                if (this.instanceCount != that.instanceCount) return false;
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Object#toString()
+         */
+        @Override
+        public String toString() {
+            return "(# props=" + this.getPropertyCount() + ", # children=" + this.getChildrenCount() + ") => "
+                   + this.getInstanceCount();
+        }
+    }
+
+    public static final class Stats {
+        private final int propertyCount;
+        private final int childrenCount;
+
+        protected Stats( int propertyCount,
+                         int childrenCount ) {
+            this.propertyCount = propertyCount;
+            this.childrenCount = childrenCount;
+        }
+
+        /**
+         * @return childrenCount
+         */
+        public int getChildrenCount() {
+            return childrenCount;
+        }
+
+        /**
+         * @return propertyCount
+         */
+        public int getPropertyCount() {
+            return propertyCount;
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            return HashCode.compute(this.propertyCount, this.childrenCount);
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals( Object obj ) {
+            if (obj instanceof Stats) {
+                Stats that = (Stats)obj;
+                if (this.propertyCount != that.propertyCount) return false;
+                if (this.childrenCount != that.childrenCount) return false;
+                return true;
+            }
+            return false;
+        }
+    }
+
+}


Property changes on: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ContributionStatistics.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: 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	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -22,6 +22,7 @@
 package org.jboss.dna.connector.federation.contribution;
 
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.spi.graph.DateTime;
 import org.jboss.dna.spi.graph.Path;
 
 /**
@@ -46,9 +47,13 @@
      * Create a contribution for the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
+     * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      */
-    public EmptyContribution( String sourceName ) {
-        super(sourceName);
+    public EmptyContribution( String sourceName,
+                              DateTime expirationTime ) {
+        super(sourceName, expirationTime);
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(0, 0);
     }
 
     /**

Modified: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiChildContribution.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiChildContribution.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiChildContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -25,6 +25,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.spi.graph.DateTime;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.Path.Segment;
 
@@ -48,16 +49,22 @@
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param children the children from the source; may not be null or empty
      */
     public MultiChildContribution( String sourceName,
                                    Path pathInSource,
+                                   DateTime expirationTime,
                                    Iterable<Segment> children ) {
-        super(sourceName, pathInSource);
+        super(sourceName, pathInSource, expirationTime);
+        assert children != null;
         this.children = new LinkedList<Segment>();
         for (Segment child : children) {
             if (child != null) this.children.add(child);
         }
+        assert this.children.isEmpty() == false;
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(0, this.children.size());
     }
 
     /**

Modified: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContribution.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContribution.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -25,6 +25,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import net.jcip.annotations.Immutable;
+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;
@@ -42,23 +43,29 @@
      */
     private static final long serialVersionUID = 1L;
 
-    private final Map<Name, Property> properties;
+    protected final Map<Name, Property> properties;
 
     /**
      * 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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param properties the properties from the source; may not be null
      */
     public MultiPropertyContribution( String sourceName,
                                       Path pathInSource,
+                                      DateTime expirationTime,
                                       Iterable<Property> properties ) {
-        super(sourceName, pathInSource);
+        super(sourceName, pathInSource, expirationTime);
+        assert properties != null;
         this.properties = new HashMap<Name, Property>();
         for (Property property : properties) {
             if (property != null) this.properties.put(property.getName(), property);
         }
+        assert this.properties.isEmpty() == false;
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(this.properties.size(), 0);
     }
 
     /**

Modified: 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	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -25,6 +25,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.spi.graph.DateTime;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.Property;
 import org.jboss.dna.spi.graph.Path.Segment;
@@ -49,18 +50,24 @@
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @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,
+                             DateTime expirationTime,
                              Iterable<Property> properties,
                              Iterable<Segment> children ) {
-        super(sourceName, pathInSource, properties);
+        super(sourceName, pathInSource, expirationTime, properties);
+        assert children != null;
         this.children = new LinkedList<Segment>();
         for (Segment child : children) {
             if (child != null) this.children.add(child);
         }
+        assert this.children.isEmpty() == false;
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(this.properties.size(), this.children.size());
     }
 
     /**

Modified: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NonEmptyContribution.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NonEmptyContribution.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NonEmptyContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -23,6 +23,7 @@
 
 import net.jcip.annotations.Immutable;
 import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.spi.graph.DateTime;
 import org.jboss.dna.spi.graph.Path;
 
 /**
@@ -45,10 +46,13 @@
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      */
     protected NonEmptyContribution( String sourceName,
-                                    Path pathInSource ) {
-        super(sourceName);
+                                    Path pathInSource,
+                                    DateTime expirationTime ) {
+        super(sourceName, expirationTime);
         assert pathInSource != null;
         this.pathInSource = pathInSource;
     }

Modified: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OneChildContribution.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OneChildContribution.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OneChildContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -23,11 +23,12 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.spi.graph.DateTime;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.Path.Segment;
 
 /**
- * The record of a source contributing only properties to a node.
+ * The record of a source contributing only a single child to a node.
  * 
  * @author Randall Hauch
  */
@@ -42,18 +43,22 @@
     private final Segment child;
 
     /**
-     * Create a contribution of node properties from the source with the supplied name.
+     * Create a contribution of a single child 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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param child the child contributed from the source; may not be null
      */
     public OneChildContribution( String sourceName,
                                  Path pathInSource,
+                                 DateTime expirationTime,
                                  Segment child ) {
-        super(sourceName, pathInSource);
+        super(sourceName, pathInSource, expirationTime);
         assert child != null;
         this.child = child;
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(0, 1);
     }
 
     /**

Modified: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OnePropertyContribution.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OnePropertyContribution.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OnePropertyContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -23,6 +23,7 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+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;
@@ -47,15 +48,19 @@
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param property the property from the source; may not be null
      */
     public OnePropertyContribution( String sourceName,
                                     Path pathInSource,
+                                    DateTime expirationTime,
                                     Property property ) {
-        super(sourceName, pathInSource);
+        super(sourceName, pathInSource, expirationTime);
         assert property != null;
         assert property.isEmpty() == false;
         this.property = property;
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(1, 0);
     }
 
     /**

Modified: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContribution.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContribution.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -23,6 +23,7 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+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;
@@ -49,16 +50,19 @@
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param property1 the first property from the source; may not be null
      * @param property2 the second property from the source; may not be null
      * @param property3 the third property from the source; may not be null
      */
     public ThreePropertyContribution( String sourceName,
                                       Path pathInSource,
+                                      DateTime expirationTime,
                                       Property property1,
                                       Property property2,
                                       Property property3 ) {
-        super(sourceName, pathInSource);
+        super(sourceName, pathInSource, expirationTime);
         assert property1 != null;
         assert property1.isEmpty() == false;
         assert property2 != null;
@@ -68,6 +72,7 @@
         this.property1 = property1;
         this.property2 = property2;
         this.property3 = property3;
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(3, 0);
     }
 
     /**

Added: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,89 @@
+/*
+ * 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.Iterator;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Path.Segment;
+
+/**
+ * The record of a source contributing only two children to a node.
+ * 
+ * @author Randall Hauch
+ */
+ at Immutable
+public class TwoChildContribution extends NonEmptyContribution {
+
+    /**
+     * This is the first version of this class. See the documentation of MergePlan.serialVersionUID.
+     */
+    private static final long serialVersionUID = 1L;
+
+    private final Segment child1;
+    private final Segment child2;
+
+    /**
+     * Create a contribution of two 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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
+     * @param child1 the first child contributed from the source; may not be null
+     * @param child2 the second child contributed from the source; may not be null
+     */
+    public TwoChildContribution( String sourceName,
+                                 Path pathInSource,
+                                 DateTime expirationTime,
+                                 Segment child1,
+                                 Segment child2 ) {
+        super(sourceName, pathInSource, expirationTime);
+        assert child1 != null;
+        assert child2 != null;
+        this.child1 = child1;
+        this.child2 = child2;
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(0, 2);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.connector.federation.contribution.Contribution#getChildren()
+     */
+    @Override
+    public Iterator<Segment> getChildren() {
+        return new TwoValueIterator<Segment>(child1, child2);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.connector.federation.contribution.Contribution#getChildrenCount()
+     */
+    @Override
+    public int getChildrenCount() {
+        return 2;
+    }
+
+}


Property changes on: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContribution.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContribution.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContribution.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -23,6 +23,7 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+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;
@@ -48,20 +49,24 @@
      * 
      * @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 expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
+     *        expiration time
      * @param property1 the first property from the source; may not be null
      * @param property2 the first property from the source; may not be null
      */
     public TwoPropertyContribution( String sourceName,
                                     Path pathInSource,
+                                    DateTime expirationTime,
                                     Property property1,
                                     Property property2 ) {
-        super(sourceName, pathInSource);
+        super(sourceName, pathInSource, expirationTime);
         assert property1 != null;
         assert property1.isEmpty() == false;
         assert property2 != null;
         assert property2.isEmpty() == false;
         this.property1 = property1;
         this.property2 = property2;
+        if (ContributionStatistics.RECORD) ContributionStatistics.record(2, 0);
     }
 
     /**

Modified: 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	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -35,7 +35,9 @@
 import org.jboss.dna.connector.federation.contribution.Contribution;
 import org.jboss.dna.connector.federation.merge.MergePlan;
 import org.jboss.dna.spi.ExecutionContext;
+import org.jboss.dna.spi.cache.CachePolicy;
 import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.DateTimeFactory;
 import org.jboss.dna.spi.graph.Name;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.PathFactory;
@@ -64,6 +66,7 @@
 public class FederatingCommandExecutor extends AbstractCommandExecutor {
 
     private final Name mergePlanPropertyName;
+    private final CachePolicy defaultCachePolicy;
     private final Projection cacheProjection;
     private final List<Projection> sourceProjections;
     private final Set<String> sourceNames;
@@ -76,7 +79,8 @@
     /**
      * 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(ExecutionContext, String, Projection, List, RepositoryConnectionFactories)
+     * desired, see
+     * {@link #FederatingCommandExecutor(ExecutionContext, String, Projection, CachePolicy, List, RepositoryConnectionFactories)
      * constructor} that takes a {@link Projection cache projection}.
      * 
      * @param context the execution context in which the executor will be run; may not be null
@@ -88,7 +92,7 @@
                                       String sourceName,
                                       List<Projection> sourceProjections,
                                       RepositoryConnectionFactories connectionFactories ) {
-        this(context, sourceName, null, sourceProjections, connectionFactories);
+        this(context, sourceName, null, null, sourceProjections, connectionFactories);
     }
 
     /**
@@ -101,18 +105,23 @@
      * @param context the execution context 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 defaultCachePolicy the default caching policy that outlines the length of time that information should be cached, or
+     *        null if there is no cache or no specific cache policy
      * @param sourceProjections the source projections; may not be null
      * @param connectionFactories the factory for connection factory instances
      */
     public FederatingCommandExecutor( ExecutionContext context,
                                       String sourceName,
                                       Projection cacheProjection,
+                                      CachePolicy defaultCachePolicy,
                                       List<Projection> sourceProjections,
                                       RepositoryConnectionFactories connectionFactories ) {
         super(context, sourceName);
         assert sourceProjections != null;
         assert connectionFactories != null;
+        assert cacheProjection != null ? defaultCachePolicy != null : defaultCachePolicy == null;
         this.cacheProjection = cacheProjection;
+        this.defaultCachePolicy = defaultCachePolicy;
         this.sourceProjections = sourceProjections;
         this.connectionFactories = connectionFactories;
         this.connectionsBySourceName = new HashMap<String, RepositoryConnection>();
@@ -219,9 +228,10 @@
      */
     protected BasicGetNodeCommand getNode( Path path ) throws RepositorySourceException, InterruptedException {
         // Check the cache first ...
+        final ExecutionContext context = getEnvironment();
         RepositoryConnection cacheConnection = getConnectionToCache();
         BasicGetNodeCommand fromCache = new BasicGetNodeCommand(path);
-        cacheConnection.execute(getEnvironment(), fromCache);
+        cacheConnection.execute(context, fromCache);
         if (fromCache.hasError()) {
             if (fromCache.getError() instanceof PathNotFoundException) {
                 // Start at the root and populate the cache down to this node ...
@@ -259,46 +269,70 @@
             // What about other (new) regions?
         } else {
             // At this point, there is no merge plan, so read information from the sources ...
-            PathFactory pathFactory = getEnvironment().getValueFactories().getPathFactory();
+            PathFactory pathFactory = context.getValueFactories().getPathFactory();
+            DateTimeFactory timeFactory = context.getValueFactories().getDateFactory();
             List<Contribution> contributions = new LinkedList<Contribution>();
             for (Projection projection : this.sourceProjections) {
                 final String source = projection.getSourceName();
-                // Get the paths-in-source where we should fetch node contributions ...
-                Set<Path> pathsInSource = projection.getPathsInSource(path, pathFactory);
-                if (pathsInSource.isEmpty()) {
-                    // The source has no contributions ...
-                    contributions.add(Contribution.create(source));
-                } else {
-                    // There is at least one contribution ...
-                    RepositoryConnection sourceConnection = getConnection(projection);
+                final RepositoryConnection sourceConnection = getConnection(projection);
+                try {
+                    // Get the cached information ...
+                    CachePolicy cachePolicy = sourceConnection.getDefaultCachePolicy();
+                    if (cachePolicy == null) cachePolicy = this.defaultCachePolicy;
+                    DateTime expirationTime = null;
+                    if (cachePolicy != null) {
+                        expirationTime = timeFactory.create(getCurrentTimeInUtc(), cachePolicy.getTimeToLive());
+                    }
+                    // Get the paths-in-source where we should fetch node contributions ...
+                    Set<Path> pathsInSource = projection.getPathsInSource(path, pathFactory);
+                    if (pathsInSource.isEmpty()) {
+                        // The source has no contributions ...
+                        contributions.add(Contribution.create(source, expirationTime));
+                    } else {
+                        // There is at least one contribution ...
 
-                    // Get the contributions ...
-                    final int numPaths = pathsInSource.size();
-                    if (numPaths == 1) {
-                        Path pathInSource = pathsInSource.iterator().next();
-                        BasicGetNodeCommand fromSource = new BasicGetNodeCommand(pathInSource);
-                        sourceConnection.execute(getEnvironment(), fromSource);
-                        if (!fromSource.hasError()) {
-                            Collection<Property> properties = fromSource.getProperties().values();
-                            Collection<Segment> children = fromSource.getChildren();
-                            Contribution contribution = Contribution.create(source, pathInSource, properties, children);
-                            contributions.add(contribution);
+                        // Get the contributions ...
+                        final int numPaths = pathsInSource.size();
+                        if (numPaths == 1) {
+                            Path pathInSource = pathsInSource.iterator().next();
+                            BasicGetNodeCommand fromSource = new BasicGetNodeCommand(pathInSource);
+                            sourceConnection.execute(getEnvironment(), fromSource);
+                            if (!fromSource.hasError()) {
+                                Collection<Property> properties = fromSource.getProperties().values();
+                                Collection<Segment> children = fromSource.getChildren();
+                                DateTime expTime = fromSource.getCachePolicy() == null ? expirationTime : timeFactory.create(getCurrentTimeInUtc(),
+                                                                                                                             fromSource.getCachePolicy().getTimeToLive());
+                                Contribution contribution = Contribution.create(source,
+                                                                                pathInSource,
+                                                                                expTime,
+                                                                                properties,
+                                                                                children);
+                                contributions.add(contribution);
+                            }
+                        } else {
+                            BasicGetNodeCommand[] fromSourceCommands = new BasicGetNodeCommand[numPaths];
+                            int i = 0;
+                            for (Path pathInSource : pathsInSource) {
+                                fromSourceCommands[i++] = new BasicGetNodeCommand(pathInSource);
+                            }
+                            sourceConnection.execute(getEnvironment(), fromSourceCommands);
+                            for (BasicGetNodeCommand fromSource : fromSourceCommands) {
+                                if (fromSource.hasError()) continue;
+                                Collection<Property> properties = fromSource.getProperties().values();
+                                Collection<Segment> children = fromSource.getChildren();
+                                DateTime expTime = fromSource.getCachePolicy() == null ? expirationTime : timeFactory.create(getCurrentTimeInUtc(),
+                                                                                                                             fromSource.getCachePolicy().getTimeToLive());
+                                Contribution contribution = Contribution.create(source,
+                                                                                fromSource.getPath(),
+                                                                                expTime,
+                                                                                properties,
+                                                                                children);
+                                contributions.add(contribution);
+                            }
                         }
-                    } else {
-                        BasicGetNodeCommand[] fromSourceCommands = new BasicGetNodeCommand[numPaths];
-                        int i = 0;
-                        for (Path pathInSource : pathsInSource) {
-                            fromSourceCommands[i++] = new BasicGetNodeCommand(pathInSource);
-                        }
-                        sourceConnection.execute(getEnvironment(), fromSourceCommands);
-                        for (BasicGetNodeCommand fromSource : fromSourceCommands) {
-                            if (fromSource.hasError()) continue;
-                            Collection<Property> properties = fromSource.getProperties().values();
-                            Collection<Segment> children = fromSource.getChildren();
-                            Contribution contribution = Contribution.create(source, fromSource.getPath(), properties, children);
-                            contributions.add(contribution);
-                        }
                     }
+                } finally {
+                    sourceConnection.close();
                 }
             }
             // Merge the results into a single set of results ...
@@ -326,19 +360,6 @@
         return null;
     }
 
-    protected Contribution getContribution( RepositoryConnection connection,
-                                            String sourceName,
-                                            Path path ) throws RepositorySourceException, InterruptedException {
-        BasicGetNodeCommand fromSource = new BasicGetNodeCommand(path);
-        connection.execute(getEnvironment(), fromSource);
-        if (fromSource.hasError()) return null;
-
-        Collection<Property> properties = fromSource.getProperties().values();
-        Collection<Segment> children = fromSource.getChildren();
-        Contribution contribution = Contribution.create(sourceName, path, properties, children);
-        return contribution;
-    }
-
     protected MergePlan getMergePlan( BasicGetPropertiesCommand command ) {
         Property mergePlanProperty = command.getProperties().get(mergePlanPropertyName);
         if (mergePlanProperty == null || mergePlanProperty.isEmpty()) {

Modified: 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	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/connectors/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties	2008-08-04 19:59:20 UTC (rev 377)
@@ -29,10 +29,6 @@
 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/contribution/ContributionStatisticsTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ContributionStatisticsTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ContributionStatisticsTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,63 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import java.util.List;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class ContributionStatisticsTest {
+
+    /**
+     * Statistics should be recorded ONLY during testing within an IDE, and should <i>never</i> be committed to SVN with the
+     * {@link ContributionStatistics#RECORD} set to <code>true</code>. This test verifies this, and thus will fail only during IDE
+     * testing.
+     */
+    @Test
+    public void shouldNotRecordStatisticsUnlessMeasuringStatisticsInLocalTests() {
+        assertThat(ContributionStatistics.RECORD, is(false));
+    }
+
+    @Test
+    public void shouldRecordTopFiveStatistics() {
+        if (!ContributionStatistics.RECORD) return;
+        for (int j = 0; j != 10; ++j) {
+            for (int i = 0; i != j; ++i)
+                ContributionStatistics.record(i, 1);
+        }
+        List<ContributionStatistics.Data> topData = ContributionStatistics.getTop(5);
+        for (ContributionStatistics.Data data : topData) {
+            System.out.println(data);
+        }
+        assertThat(topData.size(), is(5));
+        assertThat(topData.get(0).getInstanceCount(), is(9l));
+        assertThat(topData.get(1).getInstanceCount(), is(8l));
+        assertThat(topData.get(2).getInstanceCount(), is(7l));
+        assertThat(topData.get(3).getInstanceCount(), is(6l));
+        assertThat(topData.get(4).getInstanceCount(), is(5l));
+    }
+
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ContributionStatisticsTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/EmptyContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/EmptyContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/EmptyContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,98 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class EmptyContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private EmptyContribution contribution;
+    private DateTime expiration;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        expiration = TOMORROW;
+        contribution = new EmptyContribution(sourceName, expiration);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new EmptyContribution(sourceName, expiration);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        new EmptyContribution(sourceName, new JodaDateTime(System.currentTimeMillis(), "CST"));
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new EmptyContribution(sourceName, NOW);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveNoChildren() {
+        assertThat(contribution.getChildrenCount(), is(0));
+        assertThat(contribution.getChildren().hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveNoProperties() {
+        assertThat(contribution.getPropertyCount(), is(0));
+        assertThat(contribution.getProperties().hasNext(), is(false));
+        Name propertyName = mock(Name.class); // doesn't matter what the name instance is
+        assertThat(contribution.getProperty(propertyName), is(nullValue()));
+    }
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/EmptyContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,135 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+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.Path.Segment;
+import org.jboss.dna.spi.graph.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.BasicPath;
+import org.jboss.dna.spi.graph.impl.BasicPathSegment;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class MultiChildContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private Path pathInSource;
+    private MultiChildContribution contribution;
+    private DateTime expiration;
+    private List<Segment> children;
+    private Segment child1;
+    private Segment child2;
+    private Segment child3;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        pathInSource = BasicPath.ROOT;
+        expiration = TOMORROW;
+        String nsUri = "http://www.jboss.org/default";
+        child1 = new BasicPathSegment(new BasicName(nsUri, "child1"));
+        child2 = new BasicPathSegment(new BasicName(nsUri, "child2"));
+        child3 = new BasicPathSegment(new BasicName(nsUri, "child3"));
+        children = Arrays.asList(child1, child2, child3);
+        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
+        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullChildren() {
+        children = null;
+        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowEmptyChildren() {
+        children = Collections.emptyList();
+        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new MultiChildContribution(sourceName, pathInSource, NOW, children);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveChildren() {
+        assertThat(contribution.getChildrenCount(), is(3));
+        Iterator<Segment> iter = contribution.getChildren();
+        assertThat(iter.next(), is(child1));
+        assertThat(iter.next(), is(child2));
+        assertThat(iter.next(), is(child3));
+        assertThat(iter.hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveNoProperties() {
+        assertThat(contribution.getPropertyCount(), is(0));
+        assertThat(contribution.getProperties().hasNext(), is(false));
+        Name propertyName = mock(Name.class); // doesn't matter what the name instance is
+        assertThat(contribution.getProperty(propertyName), is(nullValue()));
+    }
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,138 @@
+/*
+ * 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 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.BasicPath;
+import org.jboss.dna.spi.graph.impl.BasicSingleValueProperty;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class MultiPropertyContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private Path pathInSource;
+    private MultiPropertyContribution contribution;
+    private DateTime expiration;
+    private List<Property> properties;
+    private Property property1;
+    private Property property2;
+    private Property property3;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        pathInSource = BasicPath.ROOT;
+        expiration = TOMORROW;
+        String nsUri = "http://www.jboss.org/default";
+        property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
+        property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
+        property3 = new BasicSingleValueProperty(new BasicName(nsUri, "property3"), "value3");
+        properties = Arrays.asList(property1, property2, property3);
+        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
+        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullProperties() {
+        properties = null;
+        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowEmptyProperties() {
+        properties = Collections.emptyList();
+        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new MultiPropertyContribution(sourceName, pathInSource, NOW, properties);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveNoChildren() {
+        assertThat(contribution.getChildrenCount(), is(0));
+        assertThat(contribution.getChildren().hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveProperties() {
+        assertThat(contribution.getPropertyCount(), is(3));
+        assertThat(contribution.getProperty(property1.getName()), is(sameInstance(property1)));
+        assertThat(contribution.getProperty(property2.getName()), is(sameInstance(property2)));
+        assertThat(contribution.getProperty(property3.getName()), is(sameInstance(property3)));
+        assertThat(contribution.getProperty(new BasicName("http://www.jboss.org/x", "propertyX")), is(nullValue()));
+        List<Property> properties = new ArrayList<Property>();
+        for (Iterator<Property> iter = contribution.getProperties(); iter.hasNext();) {
+            properties.add(iter.next());
+        }
+        assertThat(properties, hasItems(property1, property2, property3));
+    }
+
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,164 @@
+/*
+ * 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 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.jboss.dna.spi.graph.DateTime;
+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.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.BasicPath;
+import org.jboss.dna.spi.graph.impl.BasicPathSegment;
+import org.jboss.dna.spi.graph.impl.BasicSingleValueProperty;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class NodeContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private Path pathInSource;
+    private NodeContribution contribution;
+    private DateTime expiration;
+    private List<Property> properties;
+    private Property property1;
+    private Property property2;
+    private Property property3;
+    private List<Segment> children;
+    private Segment child1;
+    private Segment child2;
+    private Segment child3;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        pathInSource = BasicPath.ROOT;
+        expiration = TOMORROW;
+        String nsUri = "http://www.jboss.org/default";
+        property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
+        property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
+        property3 = new BasicSingleValueProperty(new BasicName(nsUri, "property3"), "value3");
+        properties = Arrays.asList(property1, property2, property3);
+        child1 = new BasicPathSegment(new BasicName(nsUri, "child1"));
+        child2 = new BasicPathSegment(new BasicName(nsUri, "child2"));
+        child3 = new BasicPathSegment(new BasicName(nsUri, "child3"));
+        children = Arrays.asList(child1, child2, child3);
+        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
+        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullProperties() {
+        properties = null;
+        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowEmptyProperties() {
+        properties = Collections.emptyList();
+        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullChildren() {
+        children = null;
+        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowEmptyChildren() {
+        children = Collections.emptyList();
+        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new NodeContribution(sourceName, pathInSource, NOW, properties, children);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveChildren() {
+        assertThat(contribution.getChildrenCount(), is(3));
+        Iterator<Segment> iter = contribution.getChildren();
+        assertThat(iter.next(), is(child1));
+        assertThat(iter.next(), is(child2));
+        assertThat(iter.next(), is(child3));
+        assertThat(iter.hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveProperties() {
+        assertThat(contribution.getPropertyCount(), is(3));
+        assertThat(contribution.getProperty(property1.getName()), is(sameInstance(property1)));
+        assertThat(contribution.getProperty(property2.getName()), is(sameInstance(property2)));
+        assertThat(contribution.getProperty(property3.getName()), is(sameInstance(property3)));
+        assertThat(contribution.getProperty(new BasicName("http://www.jboss.org/x", "propertyX")), is(nullValue()));
+        List<Property> properties = new ArrayList<Property>();
+        for (Iterator<Property> iter = contribution.getProperties(); iter.hasNext();) {
+            properties.add(iter.next());
+        }
+        assertThat(properties, hasItems(property1, property2, property3));
+    }
+
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,118 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import java.util.Iterator;
+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.Path.Segment;
+import org.jboss.dna.spi.graph.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.BasicPath;
+import org.jboss.dna.spi.graph.impl.BasicPathSegment;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class OneChildContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private Path pathInSource;
+    private OneChildContribution contribution;
+    private DateTime expiration;
+    private Segment child1;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        pathInSource = BasicPath.ROOT;
+        expiration = TOMORROW;
+        String nsUri = "http://www.jboss.org/default";
+        child1 = new BasicPathSegment(new BasicName(nsUri, "child1"));
+        contribution = new OneChildContribution(sourceName, pathInSource, expiration, child1);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new OneChildContribution(sourceName, pathInSource, expiration, child1);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
+        contribution = new OneChildContribution(sourceName, pathInSource, expiration, child1);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullChildren() {
+        child1 = null;
+        contribution = new OneChildContribution(sourceName, pathInSource, expiration, child1);
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new OneChildContribution(sourceName, pathInSource, NOW, child1);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveChildren() {
+        assertThat(contribution.getChildrenCount(), is(1));
+        Iterator<Segment> iter = contribution.getChildren();
+        assertThat(iter.next(), is(child1));
+        assertThat(iter.hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveNoProperties() {
+        assertThat(contribution.getPropertyCount(), is(0));
+        assertThat(contribution.getProperties().hasNext(), is(false));
+        Name propertyName = mock(Name.class); // doesn't matter what the name instance is
+        assertThat(contribution.getProperty(propertyName), is(nullValue()));
+    }
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,122 @@
+/*
+ * 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 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 java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.BasicPath;
+import org.jboss.dna.spi.graph.impl.BasicSingleValueProperty;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class OnePropertyContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private Path pathInSource;
+    private OnePropertyContribution contribution;
+    private DateTime expiration;
+    private Property property1;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        pathInSource = BasicPath.ROOT;
+        expiration = TOMORROW;
+        String nsUri = "http://www.jboss.org/default";
+        property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
+        contribution = new OnePropertyContribution(sourceName, pathInSource, expiration, property1);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new OnePropertyContribution(sourceName, pathInSource, expiration, property1);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
+        contribution = new OnePropertyContribution(sourceName, pathInSource, expiration, property1);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullFirstProperty() {
+        property1 = null;
+        contribution = new OnePropertyContribution(sourceName, pathInSource, expiration, property1);
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new OnePropertyContribution(sourceName, pathInSource, NOW, property1);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveNoChildren() {
+        assertThat(contribution.getChildrenCount(), is(0));
+        assertThat(contribution.getChildren().hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveProperties() {
+        assertThat(contribution.getPropertyCount(), is(1));
+        assertThat(contribution.getProperty(property1.getName()), is(sameInstance(property1)));
+        assertThat(contribution.getProperty(new BasicName("http://www.jboss.org/x", "propertyX")), is(nullValue()));
+        List<Property> properties = new ArrayList<Property>();
+        for (Iterator<Property> iter = contribution.getProperties(); iter.hasNext();) {
+            properties.add(iter.next());
+        }
+        assertThat(properties, hasItems(property1));
+    }
+
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -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.contribution;
+
+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 java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.BasicPath;
+import org.jboss.dna.spi.graph.impl.BasicSingleValueProperty;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class ThreePropertyContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private Path pathInSource;
+    private ThreePropertyContribution contribution;
+    private DateTime expiration;
+    private Property property1;
+    private Property property2;
+    private Property property3;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        pathInSource = BasicPath.ROOT;
+        expiration = TOMORROW;
+        String nsUri = "http://www.jboss.org/default";
+        property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
+        property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
+        property3 = new BasicSingleValueProperty(new BasicName(nsUri, "property3"), "value3");
+        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
+        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullFirstProperty() {
+        property1 = null;
+        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullSecondProperty() {
+        property2 = null;
+        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullThirdProperty() {
+        property3 = null;
+        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new ThreePropertyContribution(sourceName, pathInSource, NOW, property1, property2, property3);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveNoChildren() {
+        assertThat(contribution.getChildrenCount(), is(0));
+        assertThat(contribution.getChildren().hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveProperties() {
+        assertThat(contribution.getPropertyCount(), is(3));
+        assertThat(contribution.getProperty(property1.getName()), is(sameInstance(property1)));
+        assertThat(contribution.getProperty(property2.getName()), is(sameInstance(property2)));
+        assertThat(contribution.getProperty(property3.getName()), is(sameInstance(property3)));
+        assertThat(contribution.getProperty(new BasicName("http://www.jboss.org/x", "propertyX")), is(nullValue()));
+        List<Property> properties = new ArrayList<Property>();
+        for (Iterator<Property> iter = contribution.getProperties(); iter.hasNext();) {
+            properties.add(iter.next());
+        }
+        assertThat(properties, hasItems(property1, property2, property3));
+    }
+
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,127 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import java.util.Iterator;
+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.Path.Segment;
+import org.jboss.dna.spi.graph.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.BasicPath;
+import org.jboss.dna.spi.graph.impl.BasicPathSegment;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class TwoChildContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private Path pathInSource;
+    private TwoChildContribution contribution;
+    private DateTime expiration;
+    private Segment child1;
+    private Segment child2;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        pathInSource = BasicPath.ROOT;
+        expiration = TOMORROW;
+        String nsUri = "http://www.jboss.org/default";
+        child1 = new BasicPathSegment(new BasicName(nsUri, "child1"));
+        child2 = new BasicPathSegment(new BasicName(nsUri, "child1"));
+        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
+        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullFirstChild() {
+        child1 = null;
+        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullSecondChild() {
+        child2 = null;
+        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new TwoChildContribution(sourceName, pathInSource, NOW, child1, child2);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveChildren() {
+        assertThat(contribution.getChildrenCount(), is(2));
+        Iterator<Segment> iter = contribution.getChildren();
+        assertThat(iter.next(), is(child1));
+        assertThat(iter.next(), is(child2));
+        assertThat(iter.hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveNoProperties() {
+        assertThat(contribution.getPropertyCount(), is(0));
+        assertThat(contribution.getProperties().hasNext(), is(false));
+        Name propertyName = mock(Name.class); // doesn't matter what the name instance is
+        assertThat(contribution.getProperty(propertyName), is(nullValue()));
+    }
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java
===================================================================
--- trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java	                        (rev 0)
+++ trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -0,0 +1,131 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors. 
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.contribution;
+
+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 java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.BasicPath;
+import org.jboss.dna.spi.graph.impl.BasicSingleValueProperty;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class TwoPropertyContributionTest {
+
+    private static final long TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
+    public static final DateTime NOW = new JodaDateTime(System.currentTimeMillis()).toUtcTimeZone();
+    public static final DateTime YESTERDAY = new JodaDateTime(NOW.getMilliseconds() - TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+    public static final DateTime TOMORROW = new JodaDateTime(NOW.getMilliseconds() + TWENTY_FOUR_HOURS_IN_MILLISECONDS).toUtcTimeZone();
+
+    private String sourceName;
+    private Path pathInSource;
+    private TwoPropertyContribution contribution;
+    private DateTime expiration;
+    private Property property1;
+    private Property property2;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "some source";
+        pathInSource = BasicPath.ROOT;
+        expiration = TOMORROW;
+        String nsUri = "http://www.jboss.org/default";
+        property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
+        property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
+        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+    }
+
+    @Test
+    public void shouldAllowNullExpiration() {
+        expiration = null;
+        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+        assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
+        expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
+        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullFirstProperty() {
+        property1 = null;
+        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullSecondProperty() {
+        property2 = null;
+        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+    }
+
+    @Test
+    public void shouldHaveSameExpirationTimeSetInConstructor() {
+        assertThat(contribution.getExpirationTimeInUtc(), is(sameInstance(expiration)));
+    }
+
+    @Test
+    public void shouldHaveSameSourceNameSetInConstructor() {
+        assertThat(contribution.getSourceName(), is(sourceName));
+    }
+
+    @Test
+    public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
+        contribution = new TwoPropertyContribution(sourceName, pathInSource, NOW, property1, property2);
+        assertThat(contribution.isExpired(YESTERDAY), is(false));
+        assertThat(contribution.isExpired(TOMORROW), is(true));
+    }
+
+    @Test
+    public void shouldHaveNoChildren() {
+        assertThat(contribution.getChildrenCount(), is(0));
+        assertThat(contribution.getChildren().hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldHaveProperties() {
+        assertThat(contribution.getPropertyCount(), is(2));
+        assertThat(contribution.getProperty(property1.getName()), is(sameInstance(property1)));
+        assertThat(contribution.getProperty(property2.getName()), is(sameInstance(property2)));
+        assertThat(contribution.getProperty(new BasicName("http://www.jboss.org/x", "propertyX")), is(nullValue()));
+        List<Property> properties = new ArrayList<Property>();
+        for (Iterator<Property> iter = contribution.getProperties(); iter.hasNext();) {
+            properties.add(iter.next());
+        }
+        assertThat(properties, hasItems(property1, property2));
+    }
+
+}


Property changes on: trunk/connectors/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -215,7 +215,7 @@
                 executor = new NoOpCommandExecutor(context, configurationSourceName);
             } else {
                 // The configuration repository has more than one projection, so we need to merge the results
-                executor = new FederatingCommandExecutor(context, configurationSourceName, null, projections, sources);
+                executor = new FederatingCommandExecutor(context, configurationSourceName, projections, sources);
             }
 
             // Read the configuration and the repository sources, located as child nodes/branches under "/dna:sources",

Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/BasicCachePolicy.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/BasicCachePolicy.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/BasicCachePolicy.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -27,56 +27,37 @@
 public class BasicCachePolicy implements CachePolicy {
 
     private static final long serialVersionUID = 1L;
-    private long timeToCache;
-    private long timeToExpire;
+    private long timeToLive;
 
     public BasicCachePolicy() {
     }
 
-    public BasicCachePolicy( long timeToCache,
-                             long timeToExpire ) {
-        this.timeToCache = timeToCache;
-        this.timeToExpire = timeToExpire;
+    public BasicCachePolicy( long timeToCache ) {
+        this.timeToLive = timeToCache;
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.spi.cache.CachePolicy#getTimeToCache()
+     * @see org.jboss.dna.spi.cache.CachePolicy#getTimeToLive()
      */
-    public long getTimeToCache() {
-        return this.timeToCache;
+    public long getTimeToLive() {
+        return this.timeToLive;
     }
 
     /**
-     * @param timeToCache Sets timeToCache to the specified value.
+     * @param timeToLive Sets timeToLive to the specified value.
      */
-    public void setTimeToCache( long timeToCache ) {
-        this.timeToCache = timeToCache;
+    public void setTimeToLive( long timeToLive ) {
+        this.timeToLive = timeToLive;
     }
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.spi.cache.CachePolicy#getTimeToExpire()
-     */
-    public long getTimeToExpire() {
-        return this.timeToExpire;
-    }
-
-    /**
-     * @param timeToExpire Sets timeToExpire to the specified value.
-     */
-    public void setTimeToExpire( long timeToExpire ) {
-        this.timeToExpire = timeToExpire;
-    }
-
     public boolean isEmpty() {
-        return this.timeToCache == 0 && this.timeToExpire == 0;
+        return this.timeToLive == 0;
     }
 
     public CachePolicy getUnmodifiable() {
-        return new ImmutableCachePolicy(this.getTimeToCache(), this.getTimeToExpire());
+        return new ImmutableCachePolicy(this.getTimeToLive());
     }
 
 }

Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/CachePolicy.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/CachePolicy.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/CachePolicy.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -27,6 +27,7 @@
 /**
  * The specification of how node data is to be cached. The time values provided are relative, allowing the same cache policy
  * instance to be shared among multiple {@link Cacheable} objects.
+ * 
  * @author Randall Hauch
  */
 @Immutable
@@ -34,14 +35,9 @@
 
     /**
      * Get the system time in milliseconds before which the node data remains valid.
+     * 
      * @return the number of milliseconds that the cached data should be used before consulting the original source.
      */
-    public long getTimeToCache();
+    public long getTimeToLive();
 
-    /**
-     * Get the relative time after which the cached data should expire and no longer be used.
-     * @return the number of milliseconds until the cached data expires
-     */
-    public long getTimeToExpire();
-
 }

Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/ImmutableCachePolicy.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/ImmutableCachePolicy.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/ImmutableCachePolicy.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -28,32 +28,20 @@
 
     private static final long serialVersionUID = 1L;
     private final long timeToCache;
-    private final long timeToExpire;
 
-    public ImmutableCachePolicy( long timeToCache,
-                                 long timeToExpire ) {
+    public ImmutableCachePolicy( long timeToCache ) {
         this.timeToCache = timeToCache;
-        this.timeToExpire = timeToExpire;
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.spi.cache.CachePolicy#getTimeToCache()
+     * @see org.jboss.dna.spi.cache.CachePolicy#getTimeToLive()
      */
-    public long getTimeToCache() {
+    public long getTimeToLive() {
         return this.timeToCache;
     }
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.spi.cache.CachePolicy#getTimeToExpire()
-     */
-    public long getTimeToExpire() {
-        return this.timeToExpire;
-    }
-
     public CachePolicy getUnmodifiable() {
         return this;
     }

Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/DateTimeFactory.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/DateTimeFactory.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/DateTimeFactory.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -21,6 +21,7 @@
  */
 package org.jboss.dna.spi.graph;
 
+
 /**
  * A factory for creating {@link DateTime date-time instants}. This interface extends the {@link ValueFactory} generic interface
  * and adds specific methods for creating instants for the current time (and time zone) as well as various combinations of
@@ -117,6 +118,16 @@
     DateTime createUtc();
 
     /**
+     * Create a date-time instance that is offset from the original by the specified amount.
+     * 
+     * @param original
+     * @param offsetInMillis the offset in milliseconds (positive or negative)
+     * @return the offset date-time instance
+     */
+    DateTime create( DateTime original,
+                     long offsetInMillis );
+
+    /**
      * Create a date-time instance given the individual values for the fields
      * 
      * @param year the year of the era

Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/JodaDateTime.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/JodaDateTime.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/JodaDateTime.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -70,6 +70,11 @@
         this.instance = new DateTime(milliseconds, chronology);
     }
 
+    public JodaDateTime( long milliseconds,
+                         String timeZoneId ) {
+        this.instance = new DateTime(milliseconds, DateTimeZone.forID(timeZoneId));
+    }
+
     public JodaDateTime( DateTimeZone dateTimeZone ) {
         this.instance = new DateTime(dateTimeZone);
     }

Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/JodaDateTimeValueFactory.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/JodaDateTimeValueFactory.java	2008-07-29 21:15:51 UTC (rev 376)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/JodaDateTimeValueFactory.java	2008-08-04 19:59:20 UTC (rev 377)
@@ -260,7 +260,20 @@
 
     /**
      * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.spi.graph.DateTimeFactory#create(org.jboss.dna.spi.graph.DateTime, long)
      */
+    public DateTime create( DateTime original,
+                            long offsetInMillis ) {
+        assert original != null;
+        if (offsetInMillis == 0l) return original;
+        long newMillis = original.getMilliseconds() + offsetInMillis;
+        return new JodaDateTime(newMillis, original.getTimeZoneId());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     @Override
     protected DateTime[] createEmptyArray( int length ) {
         return new DateTime[length];




More information about the dna-commits mailing list