View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.client.bindings.spi.atompub;
20  
21  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.CONTENT_SRC;
22  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.LINK_HREF;
23  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.LINK_REL;
24  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.LINK_TYPE;
25  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ACL;
26  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ALLOWABLEACTIONS;
27  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_CHILDREN;
28  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_COLLECTION;
29  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_COLLECTION_TYPE;
30  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_CONTENT;
31  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_ENTRY;
32  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_FEED;
33  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_HTML;
34  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_LINK;
35  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_NUM_ITEMS;
36  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_OBJECT;
37  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_PATH_SEGMENT;
38  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_RELATIVE_PATH_SEGMENT;
39  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_REPOSITORY_INFO;
40  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_SERVICE;
41  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_TEMPLATE_TEMPLATE;
42  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_TEMPLATE_TYPE;
43  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_TYPE;
44  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_URI_TEMPLATE;
45  import static org.apache.chemistry.opencmis.client.bindings.spi.atompub.CmisAtomPubConstants.TAG_WORKSPACE;
46  
47  import java.io.InputStream;
48  import java.math.BigInteger;
49  import java.util.HashMap;
50  import java.util.Map;
51  
52  import javax.xml.namespace.QName;
53  import javax.xml.stream.XMLStreamConstants;
54  import javax.xml.stream.XMLStreamException;
55  import javax.xml.stream.XMLStreamReader;
56  
57  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAcl;
58  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomAllowableActions;
59  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomBase;
60  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomElement;
61  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomEntry;
62  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomFeed;
63  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.AtomLink;
64  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.HtmlDoc;
65  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.RepositoryWorkspace;
66  import org.apache.chemistry.opencmis.client.bindings.spi.atompub.objects.ServiceDoc;
67  import org.apache.chemistry.opencmis.commons.data.ObjectData;
68  import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
69  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
70  import org.apache.chemistry.opencmis.commons.impl.IOUtils;
71  import org.apache.chemistry.opencmis.commons.impl.XMLConstants;
72  import org.apache.chemistry.opencmis.commons.impl.XMLConstraints;
73  import org.apache.chemistry.opencmis.commons.impl.XMLConverter;
74  import org.apache.chemistry.opencmis.commons.impl.XMLUtils;
75  
76  /**
77   * AtomPub Parser.
78   */
79  public class AtomPubParser {
80  
81      // public constants
82      public static final String LINK_REL_CONTENT = "@@content@@";
83  
84      private final InputStream stream;
85      private AtomBase parseResult;
86  
87      public AtomPubParser(InputStream stream) {
88          if (stream == null) {
89              throw new IllegalArgumentException("No stream.");
90          }
91  
92          this.stream = stream;
93      }
94  
95      /**
96       * Parses the stream.
97       */
98      public void parse() throws XMLStreamException {
99          XMLStreamReader parser = XMLUtils.createParser(stream);
100 
101         try {
102             while (true) {
103                 int event = parser.getEventType();
104                 if (event == XMLStreamConstants.START_ELEMENT) {
105                     QName name = parser.getName();
106 
107                     if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
108                         if (TAG_FEED.equals(name.getLocalPart())) {
109                             parseResult = parseFeed(parser);
110                             break;
111                         } else if (TAG_ENTRY.equals(name.getLocalPart())) {
112                             parseResult = parseEntry(parser);
113                             break;
114                         }
115                     } else if (XMLConstants.NAMESPACE_CMIS.equals(name.getNamespaceURI())) {
116                         if (TAG_ALLOWABLEACTIONS.equals(name.getLocalPart())) {
117                             parseResult = parseAllowableActions(parser);
118                             break;
119                         } else if (TAG_ACL.equals(name.getLocalPart())) {
120                             parseResult = parseACL(parser);
121                             break;
122                         }
123                     } else if (XMLConstants.NAMESPACE_APP.equals(name.getNamespaceURI())) {
124                         if (TAG_SERVICE.equals(name.getLocalPart())) {
125                             parseResult = parseServiceDoc(parser);
126                             break;
127                         }
128                     } else if (TAG_HTML.equalsIgnoreCase(name.getLocalPart())) {
129                         parseResult = new HtmlDoc();
130                         break;
131                     }
132                 }
133 
134                 if (!XMLUtils.next(parser)) {
135                     break;
136                 }
137             }
138 
139         } finally {
140             try {
141                 parser.close();
142             } catch (XMLStreamException xse) {
143                 // there is nothing we can do
144             }
145 
146             // make sure the stream is read and closed in all cases
147             IOUtils.consumeAndClose(stream);
148         }
149     }
150 
151     /**
152      * Return the parse results.
153      */
154     public AtomBase getResults() {
155         return parseResult;
156     }
157 
158     /**
159      * Parses a service document.
160      */
161     private static ServiceDoc parseServiceDoc(XMLStreamReader parser) throws XMLStreamException {
162         ServiceDoc result = new ServiceDoc();
163 
164         XMLUtils.next(parser);
165 
166         while (true) {
167             int event = parser.getEventType();
168             if (event == XMLStreamConstants.START_ELEMENT) {
169                 QName name = parser.getName();
170 
171                 if (XMLConstants.NAMESPACE_APP.equals(name.getNamespaceURI())) {
172                     if (TAG_WORKSPACE.equals(name.getLocalPart())) {
173                         result.addWorkspace(parseWorkspace(parser));
174                     } else {
175                         XMLUtils.skip(parser);
176                     }
177                 } else {
178                     XMLUtils.skip(parser);
179                 }
180             } else if (event == XMLStreamConstants.END_ELEMENT) {
181                 break;
182             } else {
183                 if (!XMLUtils.next(parser)) {
184                     break;
185                 }
186             }
187         }
188 
189         return result;
190     }
191 
192     /**
193      * Parses a workspace element in a service document.
194      */
195     private static RepositoryWorkspace parseWorkspace(XMLStreamReader parser) throws XMLStreamException {
196         RepositoryWorkspace workspace = new RepositoryWorkspace();
197 
198         XMLUtils.next(parser);
199 
200         while (true) {
201             int event = parser.getEventType();
202             if (event == XMLStreamConstants.START_ELEMENT) {
203                 AtomElement element = parseWorkspaceElement(parser);
204 
205                 // check if we can extract the workspace id
206                 if ((element != null) && (element.getObject() instanceof RepositoryInfo)) {
207                     workspace.setId(((RepositoryInfo) element.getObject()).getId());
208                 }
209 
210                 // add to workspace
211                 workspace.addElement(element);
212             } else if (event == XMLStreamConstants.END_ELEMENT) {
213                 break;
214             } else {
215                 if (!XMLUtils.next(parser)) {
216                     break;
217                 }
218             }
219         }
220 
221         XMLUtils.next(parser);
222 
223         return workspace;
224     }
225 
226     /**
227      * Parses an Atom feed.
228      */
229     private AtomFeed parseFeed(XMLStreamReader parser) throws XMLStreamException {
230         AtomFeed result = new AtomFeed();
231 
232         XMLUtils.next(parser);
233 
234         while (true) {
235             int event = parser.getEventType();
236             if (event == XMLStreamConstants.START_ELEMENT) {
237                 QName name = parser.getName();
238 
239                 if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
240                     if (TAG_LINK.equals(name.getLocalPart())) {
241                         result.addElement(parseLink(parser));
242                     } else if (TAG_ENTRY.equals(name.getLocalPart())) {
243                         result.addEntry(parseEntry(parser));
244                     } else {
245                         XMLUtils.skip(parser);
246                     }
247                 } else if (XMLConstants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) {
248                     if (TAG_NUM_ITEMS.equals(name.getLocalPart())) {
249                         result.addElement(parseBigInteger(parser));
250                     } else {
251                         XMLUtils.skip(parser);
252                     }
253                 } else if (XMLConstants.NAMESPACE_APACHE_CHEMISTRY.equals(name.getNamespaceURI())) {
254                     result.addElement(parseText(parser));
255                 } else {
256                     XMLUtils.skip(parser);
257                 }
258             } else if (event == XMLStreamConstants.END_ELEMENT) {
259                 break;
260             } else {
261                 if (!XMLUtils.next(parser)) {
262                     break;
263                 }
264             }
265         }
266 
267         XMLUtils.next(parser);
268 
269         return result;
270     }
271 
272     /**
273      * Parses an Atom entry.
274      */
275     private AtomEntry parseEntry(XMLStreamReader parser) throws XMLStreamException {
276         AtomEntry result = new AtomEntry();
277 
278         XMLUtils.next(parser);
279 
280         // walk through all tags in entry
281         while (true) {
282             int event = parser.getEventType();
283             if (event == XMLStreamConstants.START_ELEMENT) {
284                 AtomElement element = parseElement(parser);
285                 if (element != null) {
286                     // add to entry
287                     result.addElement(element);
288 
289                     // find and set object id
290                     if (element.getObject() instanceof ObjectData) {
291                         result.setId(((ObjectData) element.getObject()).getId());
292                     } else if (element.getObject() instanceof TypeDefinition) {
293                         result.setId(((TypeDefinition) element.getObject()).getId());
294                     }
295                 }
296             } else if (event == XMLStreamConstants.END_ELEMENT) {
297                 break;
298             } else {
299                 if (!XMLUtils.next(parser)) {
300                     break;
301                 }
302             }
303         }
304 
305         XMLUtils.next(parser);
306 
307         return result;
308     }
309 
310     /**
311      * Parses an Allowable Actions document.
312      */
313     private static AtomAllowableActions parseAllowableActions(XMLStreamReader parser) throws XMLStreamException {
314         return new AtomAllowableActions(XMLConverter.convertAllowableActions(parser));
315     }
316 
317     /**
318      * Parses an ACL document.
319      */
320     private static AtomAcl parseACL(XMLStreamReader parser) throws XMLStreamException {
321         return new AtomAcl(XMLConverter.convertAcl(parser));
322     }
323 
324     /**
325      * Parses an element.
326      */
327     private AtomElement parseElement(XMLStreamReader parser) throws XMLStreamException {
328         QName name = parser.getName();
329 
330         if (XMLConstants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) {
331             if (TAG_OBJECT.equals(name.getLocalPart())) {
332                 return new AtomElement(name, XMLConverter.convertObject(parser));
333             } else if (TAG_PATH_SEGMENT.equals(name.getLocalPart())
334                     || TAG_RELATIVE_PATH_SEGMENT.equals(name.getLocalPart())) {
335                 return parseText(parser);
336             } else if (TAG_TYPE.equals(name.getLocalPart())) {
337                 return new AtomElement(name, XMLConverter.convertTypeDefinition(parser));
338             } else if (TAG_CHILDREN.equals(name.getLocalPart())) {
339                 return parseChildren(parser);
340             }
341         } else if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
342             if (TAG_LINK.equals(name.getLocalPart())) {
343                 return parseLink(parser);
344             } else if (TAG_CONTENT.equals(name.getLocalPart())) {
345                 return parseAtomContentSrc(parser);
346             }
347         }
348 
349         // we don't know it - skip it
350         XMLUtils.skip(parser);
351 
352         return null;
353     }
354 
355     /**
356      * Parses a children element.
357      */
358     private AtomElement parseChildren(XMLStreamReader parser) throws XMLStreamException {
359         AtomElement result = null;
360         QName childName = parser.getName();
361 
362         XMLUtils.next(parser);
363 
364         // walk through the children tag
365         while (true) {
366             int event = parser.getEventType();
367             if (event == XMLStreamConstants.START_ELEMENT) {
368                 QName name = parser.getName();
369 
370                 if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
371                     if (TAG_FEED.equals(name.getLocalPart())) {
372                         result = new AtomElement(childName, parseFeed(parser));
373                     } else {
374                         XMLUtils.skip(parser);
375                     }
376                 } else {
377                     XMLUtils.skip(parser);
378                 }
379             } else if (event == XMLStreamConstants.END_ELEMENT) {
380                 break;
381             } else {
382                 if (!XMLUtils.next(parser)) {
383                     break;
384                 }
385             }
386         }
387 
388         XMLUtils.next(parser);
389 
390         return result;
391     }
392 
393     /**
394      * Parses a workspace element.
395      */
396     private static AtomElement parseWorkspaceElement(XMLStreamReader parser) throws XMLStreamException {
397         QName name = parser.getName();
398 
399         if (XMLConstants.NAMESPACE_RESTATOM.equals(name.getNamespaceURI())) {
400             if (TAG_REPOSITORY_INFO.equals(name.getLocalPart())) {
401                 return new AtomElement(name, XMLConverter.convertRepositoryInfo(parser));
402             } else if (TAG_URI_TEMPLATE.equals(name.getLocalPart())) {
403                 return parseTemplate(parser);
404             }
405         } else if (XMLConstants.NAMESPACE_ATOM.equals(name.getNamespaceURI())) {
406             if (TAG_LINK.equals(name.getLocalPart())) {
407                 return parseLink(parser);
408             }
409         } else if (XMLConstants.NAMESPACE_APP.equals(name.getNamespaceURI())) {
410             if (TAG_COLLECTION.equals(name.getLocalPart())) {
411                 return parseCollection(parser);
412             }
413         }
414 
415         // we don't know it - skip it
416         XMLUtils.skip(parser);
417 
418         return null;
419     }
420 
421     /**
422      * Parses a collection tag.
423      */
424     private static AtomElement parseCollection(XMLStreamReader parser) throws XMLStreamException {
425         QName name = parser.getName();
426         Map<String, String> result = new HashMap<String, String>();
427 
428         result.put("href", parser.getAttributeValue(null, "href"));
429 
430         XMLUtils.next(parser);
431 
432         while (true) {
433             int event = parser.getEventType();
434             if (event == XMLStreamConstants.START_ELEMENT) {
435                 QName tagName = parser.getName();
436                 if (XMLConstants.NAMESPACE_RESTATOM.equals(tagName.getNamespaceURI())
437                         && TAG_COLLECTION_TYPE.equals(tagName.getLocalPart())) {
438                     result.put("collectionType", XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH));
439                 } else {
440                     XMLUtils.skip(parser);
441                 }
442             } else if (event == XMLStreamConstants.END_ELEMENT) {
443                 break;
444             } else {
445                 if (!XMLUtils.next(parser)) {
446                     break;
447                 }
448             }
449         }
450 
451         XMLUtils.next(parser);
452 
453         return new AtomElement(name, result);
454     }
455 
456     /**
457      * Parses a template tag.
458      */
459     private static AtomElement parseTemplate(XMLStreamReader parser) throws XMLStreamException {
460         QName name = parser.getName();
461         Map<String, String> result = new HashMap<String, String>();
462 
463         XMLUtils.next(parser);
464 
465         while (true) {
466             int event = parser.getEventType();
467             if (event == XMLStreamConstants.START_ELEMENT) {
468                 QName tagName = parser.getName();
469                 if (XMLConstants.NAMESPACE_RESTATOM.equals(tagName.getNamespaceURI())) {
470                     if (TAG_TEMPLATE_TEMPLATE.equals(tagName.getLocalPart())) {
471                         result.put("template", XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH));
472                     } else if (TAG_TEMPLATE_TYPE.equals(tagName.getLocalPart())) {
473                         result.put("type", XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH));
474                     } else {
475                         XMLUtils.skip(parser);
476                     }
477                 } else {
478                     XMLUtils.skip(parser);
479                 }
480             } else if (event == XMLStreamConstants.END_ELEMENT) {
481                 break;
482             } else {
483                 if (!XMLUtils.next(parser)) {
484                     break;
485                 }
486             }
487         }
488 
489         XMLUtils.next(parser);
490 
491         return new AtomElement(name, result);
492     }
493 
494     /**
495      * Parses a link tag.
496      */
497     private static AtomElement parseLink(XMLStreamReader parser) throws XMLStreamException {
498         QName name = parser.getName();
499         AtomLink result = new AtomLink();
500 
501         // save attributes
502         for (int i = 0; i < parser.getAttributeCount(); i++) {
503             if (LINK_REL.equals(parser.getAttributeLocalName(i))) {
504                 result.setRel(parser.getAttributeValue(i));
505             } else if (LINK_HREF.equals(parser.getAttributeLocalName(i))) {
506                 result.setHref(parser.getAttributeValue(i));
507             } else if (LINK_TYPE.equals(parser.getAttributeLocalName(i))) {
508                 result.setType(parser.getAttributeValue(i));
509             }
510         }
511 
512         // skip enclosed tags, if any
513         XMLUtils.skip(parser);
514 
515         return new AtomElement(name, result);
516     }
517 
518     /**
519      * Parses a link tag.
520      */
521     private static AtomElement parseAtomContentSrc(XMLStreamReader parser) throws XMLStreamException {
522         QName name = parser.getName();
523         AtomLink result = new AtomLink();
524         result.setRel(LINK_REL_CONTENT);
525 
526         // save attributes
527         for (int i = 0; i < parser.getAttributeCount(); i++) {
528             if (CONTENT_SRC.equals(parser.getAttributeLocalName(i))) {
529                 result.setHref(parser.getAttributeValue(i));
530             }
531         }
532 
533         // skip enclosed tags, if any
534         XMLUtils.skip(parser);
535 
536         return new AtomElement(name, result);
537     }
538 
539     /**
540      * Parses a text tag.
541      */
542     private static AtomElement parseText(XMLStreamReader parser) throws XMLStreamException {
543         QName name = parser.getName();
544         return new AtomElement(name, XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH));
545     }
546 
547     /**
548      * Parses a text tag and convert it into an integer.
549      */
550     private static AtomElement parseBigInteger(XMLStreamReader parser) throws XMLStreamException {
551         QName name = parser.getName();
552         return new AtomElement(name, new BigInteger(XMLUtils.readText(parser, XMLConstraints.MAX_STRING_LENGTH)));
553     }
554 }