1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.graph.connector.federation;
25
26 import java.util.Iterator;
27 import java.util.List;
28 import net.jcip.annotations.Immutable;
29 import org.modeshape.graph.ExecutionContext;
30 import org.modeshape.graph.Location;
31 import org.modeshape.graph.connector.federation.Projection.Rule;
32 import org.modeshape.graph.property.Path;
33 import org.modeshape.graph.property.PathFactory;
34 import org.modeshape.graph.property.Path.Segment;
35
36
37
38
39
40
41
42
43
44
45 @Immutable
46 final class BranchedMirrorProjector extends ProjectorWithPlaceholders {
47
48
49
50
51
52
53
54
55
56 static BranchedMirrorProjector with( ExecutionContext context,
57 List<Projection> projections ) {
58 assert projections != null;
59 assert context != null;
60 if (projections.size() != 2) return null;
61 Projection first = projections.get(0);
62 Projection second = projections.get(1);
63 if (first.getRules().size() != 1) return null;
64 if (second.getRules().size() != 1) return null;
65 Rule firstRule = first.getRules().get(0);
66 Rule secondRule = second.getRules().get(0);
67 assert firstRule != null;
68 assert secondRule != null;
69 PathFactory pathFactory = context.getValueFactories().getPathFactory();
70 List<Path> firstTopLevelPaths = first.getRules().get(0).getTopLevelPathsInRepository(pathFactory);
71 if (firstTopLevelPaths.size() != 1) return null;
72 List<Path> secondTopLevelPaths = second.getRules().get(0).getTopLevelPathsInRepository(pathFactory);
73 if (secondTopLevelPaths.size() != 1) return null;
74 Path firstTopLevelPath = firstTopLevelPaths.get(0);
75 Path secondTopLevelPath = secondTopLevelPaths.get(0);
76 if (firstTopLevelPath.isRoot()) {
77
78 return new BranchedMirrorProjector(context, projections, first, second, secondTopLevelPath,
79 secondRule.getPathInSource(secondTopLevelPath, pathFactory));
80 }
81
82 if (!secondTopLevelPath.isRoot()) return null;
83
84 return new BranchedMirrorProjector(context, projections, second, first, firstTopLevelPath,
85 firstRule.getPathInSource(firstTopLevelPath, pathFactory));
86 }
87
88 private final Projection mirrorProjection;
89 private final Projection branchProjection;
90 private final Path branchFederatedPath;
91 private final Path branchSourcePath;
92 private final boolean branchSourceUsesSamePath;
93
94 BranchedMirrorProjector( ExecutionContext context,
95 List<Projection> projections,
96 Projection mirrorProjection,
97 Projection branchProjection,
98 Path branchFederatedPath,
99 Path branchSourcePath ) {
100 super(context, projections);
101 assert mirrorProjection != null;
102 assert branchProjection != null;
103 assert branchFederatedPath != null;
104 assert branchSourcePath != null;
105 this.mirrorProjection = mirrorProjection;
106 this.branchProjection = branchProjection;
107 this.branchFederatedPath = branchFederatedPath;
108 this.branchSourcePath = branchSourcePath;
109 this.branchSourceUsesSamePath = branchSourcePath.equals(branchFederatedPath);
110 }
111
112
113
114
115
116
117
118
119
120 public ProjectedNode project( ExecutionContext context,
121 Location location,
122 boolean requiresUpdate ) {
123 assert location != null;
124 if (location.hasPath()) {
125 Path path = location.getPath();
126 if (path.isRoot()) {
127
128 if (requiresUpdate && mirrorProjection.isReadOnly()) return null;
129 ProxyNode result = new ProxyNode(mirrorProjection, location, location.with(branchSourcePath),
130 branchSourceUsesSamePath);
131 result.add(isPlaceholder(location));
132 return result;
133 }
134 ProjectedNode onBranch = isOnBranch(path, location, context);
135 if (onBranch != null) {
136 if (requiresUpdate && branchProjection.isReadOnly()) return null;
137 return onBranch;
138 }
139
140 if (requiresUpdate && mirrorProjection.isReadOnly()) return null;
141 return new ProxyNode(mirrorProjection, location, location, true);
142 }
143
144
145 if (requiresUpdate) {
146 if (branchProjection.isReadOnly()) {
147
148 if (mirrorProjection.isReadOnly()) return null;
149 return new ProxyNode(mirrorProjection, location, location, true);
150 }
151 if (mirrorProjection.isReadOnly()) {
152
153 return new ProxyNode(branchProjection, location, location, branchSourceUsesSamePath);
154 }
155 }
156
157
158 ProjectedNode result = new ProxyNode(mirrorProjection, location, location, true);
159 result.add(new ProxyNode(branchProjection, location, location, branchSourceUsesSamePath));
160 return result;
161 }
162
163 protected final ProjectedNode isOnBranch( Path federatedPath,
164 Location location,
165 ExecutionContext context ) {
166 Iterator<Segment> branchIter = branchFederatedPath.iterator();
167 Iterator<Segment> federIter = federatedPath.iterator();
168
169 if (branchIter.hasNext() && federIter.hasNext()) {
170 if (!branchIter.next().equals(federIter.next())) return null;
171 }
172
173 while (branchIter.hasNext() && federIter.hasNext()) {
174 if (!branchIter.next().equals(federIter.next())) {
175
176 return null;
177 }
178 }
179 if (branchIter.hasNext()) {
180
181 return isPlaceholder(location);
182 }
183
184 Location locationInSource = location;
185 if (!branchSourceUsesSamePath) {
186
187 if (federIter.hasNext()) {
188 Path subpath = federatedPath.subpath(branchFederatedPath.size());
189 Path sourcePath = context.getValueFactories().getPathFactory().create(branchSourcePath, subpath);
190 locationInSource = location.with(sourcePath);
191 } else {
192 locationInSource = location.with(branchSourcePath);
193 }
194 }
195 return new ProxyNode(branchProjection, locationInSource, location, branchSourceUsesSamePath);
196 }
197 }