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