001    /*
002     * JBoss, Home of Professional Open Source.
003     * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004     * as indicated by the @author tags. See the copyright.txt file in the
005     * distribution for a full listing of individual contributors. 
006     *
007     * This is free software; you can redistribute it and/or modify it
008     * under the terms of the GNU Lesser General Public License as
009     * published by the Free Software Foundation; either version 2.1 of
010     * the License, or (at your option) any later version.
011     *
012     * This software is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015     * Lesser General Public License for more details.
016     *
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this software; if not, write to the Free
019     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021     */
022    package org.jboss.dna.connector.federation.merge.strategy;
023    
024    import java.util.Iterator;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.UUID;
028    import net.jcip.annotations.ThreadSafe;
029    import org.jboss.dna.connector.federation.contribution.Contribution;
030    import org.jboss.dna.connector.federation.merge.FederatedNode;
031    import org.jboss.dna.connector.federation.merge.MergePlan;
032    import org.jboss.dna.graph.DnaLexicon;
033    import org.jboss.dna.graph.ExecutionContext;
034    import org.jboss.dna.graph.properties.Name;
035    import org.jboss.dna.graph.properties.Property;
036    import org.jboss.dna.graph.properties.UuidFactory;
037    import org.jboss.dna.graph.properties.ValueFormatException;
038    import org.jboss.dna.graph.properties.Path.Segment;
039    
040    /**
041     * A merge strategy that is optimized for merging when there is a single contribution.
042     * 
043     * @author Randall Hauch
044     */
045    @ThreadSafe
046    public class OneContributionMergeStrategy implements MergeStrategy {
047    
048        public static final boolean DEFAULT_REUSE_UUID_FROM_CONTRIBUTION = true;
049    
050        private boolean useUuidFromContribution = DEFAULT_REUSE_UUID_FROM_CONTRIBUTION;
051    
052        /**
053         * @return reuseUuidFromContribution
054         */
055        public boolean isContributionUuidUsedForFederatedNode() {
056            return useUuidFromContribution;
057        }
058    
059        /**
060         * @param useUuidFromContribution Sets useUuidFromContribution to the specified value.
061         */
062        public void setContributionUuidUsedForFederatedNode( boolean useUuidFromContribution ) {
063            this.useUuidFromContribution = useUuidFromContribution;
064        }
065    
066        /**
067         * {@inheritDoc}
068         * <p>
069         * This method only uses the one and only one non-null {@link Contribution} in the <code>contributions</code>.
070         * </p>
071         * 
072         * @see org.jboss.dna.connector.federation.merge.strategy.MergeStrategy#merge(org.jboss.dna.connector.federation.merge.FederatedNode,
073         *      java.util.List, org.jboss.dna.graph.ExecutionContext)
074         */
075        public void merge( FederatedNode federatedNode,
076                           List<Contribution> contributions,
077                           ExecutionContext context ) {
078            assert federatedNode != null;
079            assert context != null;
080            assert contributions != null;
081            assert contributions.size() > 0;
082            Contribution contribution = contributions.get(0);
083            assert contribution != null;
084            final boolean findUuid = isContributionUuidUsedForFederatedNode();
085            // Copy the children ...
086            List<Segment> children = federatedNode.getChildren();
087            children.clear();
088            Iterator<Segment> childIterator = contribution.getChildren();
089            while (childIterator.hasNext()) {
090                Segment child = childIterator.next();
091                children.add(child);
092            }
093            // Copy the properties ...
094            Map<Name, Property> properties = federatedNode.getPropertiesByName();
095            properties.clear();
096            UUID uuid = null;
097            UuidFactory uuidFactory = null;
098            Iterator<Property> propertyIterator = contribution.getProperties();
099            while (propertyIterator.hasNext()) {
100                Property property = propertyIterator.next();
101                if (findUuid && uuid == null && property.getName().getLocalName().equals("uuid")) {
102                    if (property.isSingle()) {
103                        if (uuidFactory == null) uuidFactory = context.getValueFactories().getUuidFactory();
104                        try {
105                            uuid = uuidFactory.create(property.getValues().next());
106                        } catch (ValueFormatException e) {
107                            // Ignore conversion exceptions
108                        }
109                    }
110                } else {
111                    properties.put(property.getName(), property);
112                }
113            }
114            // If we found a single "uuid" property whose value is a valid UUID ..
115            if (uuid != null) {
116                // then set the UUID on the federated node ...
117                federatedNode.setUuid(uuid);
118            }
119            // Set the UUID as a property ...
120            Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, federatedNode.getUuid());
121            properties.put(uuidProperty.getName(), uuidProperty);
122    
123            // Assign the merge plan ...
124            MergePlan mergePlan = MergePlan.create(contributions);
125            federatedNode.setMergePlan(mergePlan);
126        }
127    
128    }