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.repository.sequencer;
25
26 import java.io.ByteArrayInputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.util.Collections;
30 import java.util.HashSet;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import org.modeshape.common.collection.Problems;
36 import org.modeshape.common.util.Logger;
37 import org.modeshape.common.util.Reflection;
38 import org.modeshape.graph.JcrLexicon;
39 import org.modeshape.graph.JcrNtLexicon;
40 import org.modeshape.graph.Node;
41 import org.modeshape.graph.observe.NetChangeObserver.NetChange;
42 import org.modeshape.graph.property.Binary;
43 import org.modeshape.graph.property.Path;
44 import org.modeshape.graph.property.PathFactory;
45 import org.modeshape.graph.property.PathNotFoundException;
46 import org.modeshape.graph.property.Property;
47 import org.modeshape.graph.property.PropertyFactory;
48 import org.modeshape.graph.property.ValueFactories;
49 import org.modeshape.graph.sequencer.StreamSequencer;
50 import org.modeshape.graph.sequencer.StreamSequencerContext;
51 import org.modeshape.repository.RepositoryI18n;
52 import org.modeshape.repository.util.RepositoryNodePath;
53
54
55
56
57 public class StreamSequencerAdapter implements Sequencer {
58
59 private static final Logger LOGGER = Logger.getLogger(StreamSequencerAdapter.class);
60
61 private SequencerConfig configuration;
62 private final StreamSequencer streamSequencer;
63
64 public StreamSequencerAdapter( StreamSequencer streamSequencer ) {
65 this.streamSequencer = streamSequencer;
66 }
67
68
69
70
71 public SequencerConfig getConfiguration() {
72 return this.configuration;
73 }
74
75
76
77
78 public void setConfiguration( SequencerConfig configuration ) {
79 this.configuration = configuration;
80
81
82
83
84 if (configuration.getProperties() != null) {
85 final Class<?> streamSequencerClass = streamSequencer.getClass();
86 Reflection reflection = new Reflection(streamSequencerClass);
87
88 try {
89 reflection.invokeSetterMethodOnTarget("classpath", streamSequencer, configuration.getComponentClasspathArray());
90 } catch (Exception e) {
91
92 try {
93 reflection.invokeSetterMethodOnTarget("classpath", streamSequencer, configuration.getComponentClasspath());
94 } catch (Exception e2) {
95
96 }
97 }
98
99 for (Map.Entry<String, Object> entry : configuration.getProperties().entrySet()) {
100
101 final String propertyName = entry.getKey();
102 try {
103 reflection.invokeSetterMethodOnTarget(propertyName, streamSequencer, entry.getValue());
104 LOGGER.trace("Set '{0}' property from sequencer configuration on '{1}' stream sequencer implementation to {2}",
105 propertyName,
106 streamSequencerClass.getName(),
107 entry.getValue());
108 } catch (NoSuchMethodException e) {
109
110 } catch (Exception ignore) {
111 LOGGER.debug("Unable to set '{0}' property from sequencer configuration on '{1}' stream sequencer implementation",
112 propertyName,
113 streamSequencerClass.getName());
114
115 }
116 }
117 }
118 }
119
120
121
122
123 public void execute( Node input,
124 String sequencedPropertyName,
125 NetChange changes,
126 Set<RepositoryNodePath> outputPaths,
127 SequencerContext context,
128 Problems problems ) throws SequencerException {
129
130
131
132
133
134
135 Property sequencedProperty = input.getProperty(sequencedPropertyName);
136
137 if (sequencedProperty == null || sequencedProperty.isEmpty()) {
138 String msg = RepositoryI18n.unableToFindPropertyForSequencing.text(sequencedPropertyName, input.getLocation());
139 throw new SequencerException(msg);
140 }
141
142
143 ValueFactories factories = context.getExecutionContext().getValueFactories();
144 SequencerOutputMap output = new SequencerOutputMap(factories);
145 InputStream stream = null;
146 Throwable firstError = null;
147 Binary binary = factories.getBinaryFactory().create(sequencedProperty.getFirstValue());
148 binary.acquire();
149 try {
150
151 stream = binary.getStream();
152 StreamSequencerContext StreamSequencerContext = createStreamSequencerContext(input,
153 sequencedProperty,
154 context,
155 problems);
156 this.streamSequencer.sequence(stream, output, StreamSequencerContext);
157 } catch (Throwable t) {
158
159 firstError = t;
160 } finally {
161 try {
162 if (stream != null) {
163
164 try {
165 stream.close();
166 } catch (Throwable t) {
167 if (firstError == null) firstError = t;
168 } finally {
169 stream = null;
170 }
171 }
172 if (firstError != null) {
173
174 throw new SequencerException(firstError);
175 }
176 } finally {
177 binary.release();
178 }
179 }
180
181
182 Set<Path> builtPaths = new HashSet<Path>();
183
184
185 for (RepositoryNodePath outputPath : outputPaths) {
186
187 final String repositoryWorkspaceName = outputPath.getWorkspaceName();
188 final String nodePath = outputPath.getNodePath();
189
190
191 context.graph().useWorkspace(repositoryWorkspaceName);
192
193 buildPathTo(nodePath, context, builtPaths);
194
195
196
197 saveOutput(nodePath, output, context, builtPaths);
198 }
199
200 context.getDestination().submit();
201 }
202
203
204
205
206
207
208
209
210 private void buildPathTo( String nodePath,
211 SequencerContext context,
212 Set<Path> builtPaths ) {
213 PathFactory pathFactory = context.getExecutionContext().getValueFactories().getPathFactory();
214 Path targetPath = pathFactory.create(nodePath);
215
216 buildPathTo(targetPath, context, builtPaths);
217 }
218
219
220
221
222
223
224
225
226 private void buildPathTo( Path targetPath,
227 SequencerContext context,
228 Set<Path> builtPaths ) {
229 PathFactory pathFactory = context.getExecutionContext().getValueFactories().getPathFactory();
230 PropertyFactory propFactory = context.getExecutionContext().getPropertyFactory();
231
232 if (targetPath.isRoot()) return;
233 Path workingPath = pathFactory.createRootPath();
234 Path.Segment[] segments = targetPath.getSegmentsArray();
235 int i = 0;
236 Property primaryType = propFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.UNSTRUCTURED);
237 for (int max = segments.length; i < max; i++) {
238 workingPath = pathFactory.create(workingPath, segments[i]);
239
240 if (!builtPaths.contains(workingPath)) {
241 try {
242 context.graph().getNodeAt(workingPath);
243 } catch (PathNotFoundException pnfe) {
244 context.getDestination().create(workingPath, primaryType);
245 builtPaths.add(workingPath);
246 }
247 }
248 }
249 }
250
251
252
253
254
255
256
257
258
259
260 protected void saveOutput( String nodePath,
261 SequencerOutputMap output,
262 SequencerContext context,
263 Set<Path> builtPaths ) {
264 if (output.isEmpty()) return;
265 final PathFactory pathFactory = context.getExecutionContext().getValueFactories().getPathFactory();
266 final PropertyFactory propertyFactory = context.getExecutionContext().getPropertyFactory();
267 final Path outputNodePath = pathFactory.create(nodePath);
268
269
270
271 for (SequencerOutputMap.Entry entry : output) {
272 Path targetNodePath = entry.getPath();
273
274
275 Path absolutePath = targetNodePath.isAbsolute() ? targetNodePath : outputNodePath.resolve(targetNodePath);
276
277 List<Property> properties = new LinkedList<Property>();
278
279 for (SequencerOutputMap.PropertyValue property : entry.getPropertyValues()) {
280 if (property.getValue() instanceof Object[]) {
281
282 properties.add(propertyFactory.create(property.getName(), (Object[])property.getValue()));
283 } else {
284 properties.add(propertyFactory.create(property.getName(), property.getValue()));
285 }
286
287 }
288
289 if (absolutePath.getParent() != null) {
290 buildPathTo(absolutePath.getParent(), context, builtPaths);
291 }
292 context.getDestination().create(absolutePath, properties);
293 builtPaths.add(absolutePath);
294 }
295 }
296
297 protected String[] extractMixinTypes( Object value ) {
298 if (value instanceof String[]) return (String[])value;
299 if (value instanceof String) return new String[] {(String)value};
300 return null;
301 }
302
303 protected StreamSequencerContext createStreamSequencerContext( Node input,
304 Property sequencedProperty,
305 SequencerContext context,
306 Problems problems ) {
307 assert input != null;
308 assert sequencedProperty != null;
309 assert context != null;
310 assert problems != null;
311 ValueFactories factories = context.getExecutionContext().getValueFactories();
312 Path path = factories.getPathFactory().create(input.getLocation().getPath());
313
314 Set<org.modeshape.graph.property.Property> props = new HashSet<org.modeshape.graph.property.Property>(
315 input.getPropertiesByName()
316 .values());
317 props = Collections.unmodifiableSet(props);
318 String mimeType = getMimeType(context, sequencedProperty, path.getLastSegment().getName().getLocalName());
319 return new StreamSequencerContext(context.getExecutionContext(), path, props, mimeType, problems);
320 }
321
322 protected String getMimeType( SequencerContext context,
323 Property sequencedProperty,
324 String name ) {
325 SequencerException err = null;
326 String mimeType = null;
327 InputStream stream = null;
328 try {
329
330 stream = new ByteArrayInputStream(sequencedProperty.toString().getBytes());
331 mimeType = context.getExecutionContext().getMimeTypeDetector().mimeTypeOf(name, stream);
332 return mimeType;
333 } catch (Exception error) {
334 err = new SequencerException(error);
335 } finally {
336 if (stream != null) {
337 try {
338 stream.close();
339 } catch (IOException error) {
340
341 if (err == null) err = new SequencerException(error);
342 }
343 }
344 }
345 throw err;
346 }
347 }