View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.connector.federation;
25  
26  import java.util.List;
27  import java.util.Set;
28  import net.jcip.annotations.Immutable;
29  import org.modeshape.graph.ExecutionContext;
30  import org.modeshape.graph.Location;
31  import org.modeshape.graph.property.Path;
32  import org.modeshape.graph.property.PathFactory;
33  
34  /**
35   * A Projector for federated repository configurations that are an offset, direct one-for-one mirror against a single source
36   * repository that is projected below the federated root. In other words, the federated repository has a single projection with a
37   * single "/something/below/root => /" rule.
38   */
39  @Immutable
40  final class GeneralProjector extends ProjectorWithPlaceholders {
41  
42      /**
43       * Attempt to create an instance of the {@link GeneralProjector} with the supplied projections using the supplied context.
44       * 
45       * @param context the context; may not be null
46       * @param projections the projections in the federated repository; may not be null
47       * @return the offset mirror projector, or null if the projections didn't match the criteria for such a projector
48       */
49      static GeneralProjector with( ExecutionContext context,
50                                    List<Projection> projections ) {
51          assert projections != null;
52          assert context != null;
53          return new GeneralProjector(context, projections);
54      }
55  
56      private final List<Projection> projections;
57  
58      private GeneralProjector( ExecutionContext context,
59                                List<Projection> projections ) {
60          super(context, projections);
61          this.projections = projections;
62      }
63  
64      /**
65       * {@inheritDoc}
66       * 
67       * @see org.modeshape.graph.connector.federation.Projector#project(ExecutionContext, Location, boolean)
68       */
69      public ProjectedNode project( ExecutionContext context,
70                                    Location location,
71                                    boolean requiresUpdate ) {
72          PlaceholderNode placeholder = isPlaceholder(location);
73          if (placeholder != null) return placeholder;
74  
75          // Find the location of the desired node ...
76          Path path = location.getPath();
77          if (path == null) {
78              // There are only identification properties, so return a ProxyNode for each source/workspace ...
79              ProjectedNode result = null;
80              for (Projection projection : projections) {
81                  if (requiresUpdate && projection.isReadOnly()) continue;
82                  ProxyNode proxy = new ProxyNode(projection, location, location, false);
83                  if (result == null) {
84                      result = proxy;
85                  } else {
86                      result.add(proxy);
87                  }
88              }
89              return result;
90          }
91          // We have a path, so see if the path is one of the existing placeholder nodes ...
92          ProjectedNode result = isPlaceholder(location);
93          if (result != null) return result;
94  
95          // Otherwise this node lives below one (or more) of the projections, and we figure this out each time ...
96          final PathFactory pathFactory = context.getValueFactories().getPathFactory();
97          for (Projection projection : projections) {
98              if (requiresUpdate && projection.isReadOnly()) continue;
99              // Project the federated repository path into the paths as they would exist in the source ...
100             Set<Path> pathsInSource = projection.getPathsInSource(path, pathFactory);
101             for (Path pathInSource : pathsInSource) {
102                 // Create a ProxyNode for this projection ...
103                 Location locationInSource = Location.create(pathInSource);
104                 boolean samePath = pathInSource.equals(path);
105                 ProxyNode proxy = new ProxyNode(projection, locationInSource, location, samePath);
106                 if (result == null) {
107                     result = proxy;
108                 } else {
109                     result.add(proxy);
110                 }
111             }
112         }
113 
114         // If there is only one projection ...
115         if (result != null && !result.hasNext() && result.isProxy()) {
116             // Then we want to include the supplied location's ID properties down to the source ...
117             ProxyNode proxy = result.asProxy();
118             result = new ProxyNode(proxy.projection(), location.with(result.location().getPath()), location,
119                                    proxy.isSameLocationAsOriginal());
120         }
121         return result;
122     }
123 
124 }