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.jcr;
25
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.OutputStream;
29 import java.util.Arrays;
30 import java.util.List;
31 import javax.jcr.Binary;
32 import javax.jcr.Node;
33 import javax.jcr.NodeIterator;
34 import javax.jcr.Property;
35 import javax.jcr.PropertyIterator;
36 import javax.jcr.PropertyType;
37 import javax.jcr.RepositoryException;
38 import javax.jcr.Value;
39 import net.jcip.annotations.NotThreadSafe;
40 import org.modeshape.common.util.Base64;
41 import org.modeshape.common.xml.XmlCharacters;
42 import org.modeshape.graph.property.Name;
43 import org.modeshape.graph.property.ValueFactory;
44 import org.xml.sax.ContentHandler;
45 import org.xml.sax.SAXException;
46 import org.xml.sax.helpers.AttributesImpl;
47
48
49
50
51
52
53
54
55 @NotThreadSafe
56 class JcrSystemViewExporter extends AbstractJcrExporter {
57
58
59
60
61 private static final int BASE_64_BUFFER_SIZE = 1024;
62
63
64
65
66
67 private static final List<Name> SPECIAL_PROPERTY_NAMES = Arrays.asList(new Name[] {JcrLexicon.PRIMARY_TYPE,
68 JcrLexicon.MIXIN_TYPES, JcrLexicon.UUID});
69
70 JcrSystemViewExporter( JcrSession session ) {
71 super(session, Arrays.asList(new String[] {"xml"}));
72 }
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 @Override
88 public void exportNode( Node node,
89 ContentHandler contentHandler,
90 boolean skipBinary,
91 boolean noRecurse ) throws RepositoryException, SAXException {
92 exportNode(node, contentHandler, skipBinary, noRecurse, node.getDepth() == 0);
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 protected void exportNode( Node node,
110 ContentHandler contentHandler,
111 boolean skipBinary,
112 boolean noRecurse,
113 boolean isRoot ) throws RepositoryException, SAXException {
114
115
116 AttributesImpl atts = new AttributesImpl();
117 String nodeName = node.getName();
118 if (isRoot && node.getDepth() == 0) {
119
120 nodeName = "jcr:root";
121 }
122 atts.addAttribute(JcrSvLexicon.NAME.getNamespaceUri(),
123 JcrSvLexicon.NAME.getLocalName(),
124 getPrefixedName(JcrSvLexicon.NAME),
125 PropertyType.nameFromValue(PropertyType.STRING),
126 nodeName);
127
128 startElement(contentHandler, JcrSvLexicon.NODE, atts);
129
130 if (node instanceof JcrSharedNode) {
131
132
133
134
135 emitProperty(JcrLexicon.PRIMARY_TYPE, PropertyType.NAME, JcrNtLexicon.SHARE, contentHandler, skipBinary);
136
137
138 emitProperty(JcrLexicon.UUID, PropertyType.STRING, node.getIdentifier(), contentHandler, skipBinary);
139 } else {
140
141
142 for (Name specialPropertyName : SPECIAL_PROPERTY_NAMES) {
143 Property specialProperty = ((AbstractJcrNode)node).getProperty(specialPropertyName);
144
145 if (specialProperty != null) {
146 emitProperty(specialProperty, contentHandler, skipBinary);
147 }
148 }
149
150 PropertyIterator properties = node.getProperties();
151 while (properties.hasNext()) {
152 exportProperty(properties.nextProperty(), contentHandler, skipBinary);
153 }
154
155 if (!noRecurse) {
156 NodeIterator nodes = node.getNodes();
157 while (nodes.hasNext()) {
158 exportNode(nodes.nextNode(), contentHandler, skipBinary, noRecurse, false);
159 }
160 }
161 }
162
163 endElement(contentHandler, JcrSvLexicon.NODE);
164 }
165
166
167
168
169
170
171
172
173 private void exportProperty( Property property,
174 ContentHandler contentHandler,
175 boolean skipBinary ) throws RepositoryException, SAXException {
176 assert property instanceof AbstractJcrProperty : "Illegal attempt to use " + getClass().getName()
177 + " on non-ModeShape property";
178
179 AbstractJcrProperty prop = (AbstractJcrProperty)property;
180
181 Name propertyName = prop.name();
182 if (SPECIAL_PROPERTY_NAMES.contains(propertyName)) {
183 return;
184 }
185
186 emitProperty(property, contentHandler, skipBinary);
187 }
188
189
190
191
192
193
194
195
196
197
198 private void emitProperty( Property property,
199 ContentHandler contentHandler,
200 boolean skipBinary ) throws RepositoryException, SAXException {
201 assert property instanceof AbstractJcrProperty : "Illegal attempt to use " + getClass().getName()
202 + " on non-ModeShape property";
203
204 AbstractJcrProperty prop = (AbstractJcrProperty)property;
205
206
207 AttributesImpl propAtts = new AttributesImpl();
208 propAtts.addAttribute(JcrSvLexicon.NAME.getNamespaceUri(),
209 JcrSvLexicon.NAME.getLocalName(),
210 getPrefixedName(JcrSvLexicon.NAME),
211 PropertyType.nameFromValue(PropertyType.STRING),
212 prop.getName());
213
214
215 propAtts.addAttribute(JcrSvLexicon.TYPE.getNamespaceUri(),
216 JcrSvLexicon.TYPE.getLocalName(),
217 getPrefixedName(JcrSvLexicon.TYPE),
218 PropertyType.nameFromValue(PropertyType.STRING),
219 PropertyType.nameFromValue(prop.getType()));
220
221
222 startElement(contentHandler, JcrSvLexicon.PROPERTY, propAtts);
223
224
225 if (prop instanceof JcrMultiValueProperty) {
226 Value[] values = prop.getValues();
227 for (int i = 0; i < values.length; i++) {
228
229 emitValue(values[i], contentHandler, property.getType(), skipBinary);
230 }
231 } else {
232 emitValue(property.getValue(), contentHandler, property.getType(), skipBinary);
233 }
234
235
236 endElement(contentHandler, JcrSvLexicon.PROPERTY);
237 }
238
239
240
241
242
243
244
245
246
247
248
249 private void emitValue( Value value,
250 ContentHandler contentHandler,
251 int propertyType,
252 boolean skipBinary ) throws RepositoryException, SAXException {
253
254 if (PropertyType.BINARY == propertyType) {
255 startElement(contentHandler, JcrSvLexicon.VALUE, null);
256
257
258
259 if (!skipBinary) {
260 byte[] bytes = new byte[BASE_64_BUFFER_SIZE];
261 int len;
262
263 Binary binary = value.getBinary();
264 try {
265 InputStream stream = new Base64.InputStream(binary.getStream(), Base64.ENCODE);
266 while (-1 != (len = stream.read(bytes))) {
267 contentHandler.characters(new String(bytes, 0, len).toCharArray(), 0, len);
268 }
269 } catch (IOException ioe) {
270 throw new RepositoryException(ioe);
271 } finally {
272 binary.dispose();
273 }
274 }
275 endElement(contentHandler, JcrSvLexicon.VALUE);
276 } else {
277 emitValue(value.getString(), contentHandler);
278 }
279 }
280
281 private void emitValue( String value,
282 ContentHandler contentHandler ) throws RepositoryException, SAXException {
283
284
285
286 char[] chars = value.toCharArray();
287
288 boolean allCharsAreValidXml = true;
289 for (int i = 0; i < chars.length; i++) {
290 if (!XmlCharacters.isValid(chars[i])) {
291 allCharsAreValidXml = false;
292 break;
293 }
294 }
295
296 if (allCharsAreValidXml) {
297
298 startElement(contentHandler, JcrSvLexicon.VALUE, null);
299 contentHandler.characters(chars, 0, chars.length);
300 endElement(contentHandler, JcrSvLexicon.VALUE);
301 } else {
302 AttributesImpl valueAtts = new AttributesImpl();
303 valueAtts.addAttribute("xsi", "type", "xsi:type", "STRING", "xsd:base64Binary");
304
305 startElement(contentHandler, JcrSvLexicon.VALUE, valueAtts);
306 try {
307 chars = Base64.encodeBytes(value.getBytes("UTF-8")).toCharArray();
308 } catch (IOException ioe) {
309 throw new RepositoryException(ioe);
310 }
311 contentHandler.characters(chars, 0, chars.length);
312 endElement(contentHandler, JcrSvLexicon.VALUE);
313 }
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327 private void emitProperty( Name propertyName,
328 int propertyType,
329 Object value,
330 ContentHandler contentHandler,
331 boolean skipBinary ) throws RepositoryException, SAXException {
332 ValueFactory<String> strings = session.getExecutionContext().getValueFactories().getStringFactory();
333
334
335 AttributesImpl propAtts = new AttributesImpl();
336 propAtts.addAttribute(JcrSvLexicon.NAME.getNamespaceUri(),
337 JcrSvLexicon.NAME.getLocalName(),
338 getPrefixedName(JcrSvLexicon.NAME),
339 PropertyType.nameFromValue(PropertyType.STRING),
340 strings.create(propertyName));
341
342
343 propAtts.addAttribute(JcrSvLexicon.TYPE.getNamespaceUri(),
344 JcrSvLexicon.TYPE.getLocalName(),
345 getPrefixedName(JcrSvLexicon.TYPE),
346 PropertyType.nameFromValue(PropertyType.STRING),
347 PropertyType.nameFromValue(propertyType));
348
349
350 startElement(contentHandler, JcrSvLexicon.PROPERTY, propAtts);
351
352
353 emitValue(strings.create(value), contentHandler);
354
355
356 endElement(contentHandler, JcrSvLexicon.PROPERTY);
357 }
358 }