View Javadoc
1   package ejava.projects.esales.xml;
2   
3   import java.io.InputStream;
4   import java.util.HashMap;
5   import java.util.concurrent.Callable;
6   
7   
8   import javax.xml.XMLConstants;
9   import javax.xml.bind.JAXBContext;
10  import javax.xml.bind.JAXBElement;
11  import javax.xml.bind.JAXBException;
12  import javax.xml.bind.Unmarshaller;
13  import javax.xml.stream.XMLInputFactory;
14  import javax.xml.stream.XMLStreamException;
15  import javax.xml.stream.XMLStreamReader;
16  import javax.xml.transform.stream.StreamSource;
17  import javax.xml.validation.Schema;
18  import javax.xml.validation.SchemaFactory;
19  
20  import org.slf4j.Logger;
21  import org.slf4j.LoggerFactory;
22  import org.xml.sax.SAXException;
23  
24  import com.sun.xml.bind.IDResolver;
25  
26  /**
27   * This class will read in Java objects from a specified XML file. These 
28   * objects can be used to create ingest data for projects.
29   *
30   */
31  public class ESalesParser {
32      @SuppressWarnings("unused")
33      private static final Logger log = LoggerFactory.getLogger(ESalesParser.class);
34      protected XMLInputFactory xmlif = XMLInputFactory.newInstance();
35      protected Unmarshaller um;
36      protected XMLStreamReader xmlr;
37      public static final String SAMPLE_FILE = "xml/eSales-10.xml";
38     
39      /**
40       * Pass in the JAXB class that represents the root node of the document
41       * and an InputStream for the document to parse.
42       * 
43       * @param rootType - the class of the root type
44       * @param is - am input stream with document to parse
45       * @throws JAXBException
46       * @throws XMLStreamException
47       */
48      public ESalesParser(Class<?> rootType, InputStream is) 
49      
50          throws JAXBException, XMLStreamException {
51          JAXBContext jaxbContext = JAXBContext.newInstance(rootType);
52          um = jaxbContext.createUnmarshaller();
53          xmlif = XMLInputFactory.newInstance();
54          xmlr = xmlif.createXMLStreamReader(is);
55  
56          //This (anonymous) class is a near replicate of sun's DefaultIDResolver
57          //except that they added a clear() of the idmap within startDocument()
58          //that prevents the unmarshaller from being called multiple times.
59          IDResolver idResolver = new IDResolver() {
60              private HashMap<String,Object> idmap = null;
61  
62  			@SuppressWarnings("rawtypes")
63  			@Override
64  			public Callable<?> resolve(final String id, Class targetType) throws SAXException {
65                  return new Callable() {
66                      public Object call() throws Exception {
67                          if(idmap==null)     return null;
68                          return idmap.get(id);
69                      }
70                  };
71  			}
72  			
73  			@Override
74  			public void bind(String id, Object obj) throws SAXException {
75                  if(idmap==null)     idmap = new HashMap<String,Object>();
76                  idmap.put(id,obj);
77  			};
78  		};
79          um.setProperty(IDResolver.class.getName(), idResolver);    
80      }
81      
82      public void setSchema(InputStream schema) throws SAXException {
83          SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
84          Schema schemaObject = sf.newSchema(new StreamSource(schema));
85          um.setSchema(schemaObject);
86      }
87      
88      private boolean contains(String elements[], String localName) {
89          for(String element: elements) {
90              if (element.equalsIgnoreCase(localName)) {
91                  return true;
92              }
93          }
94          return false;
95      }
96      
97      /**
98       * This method will return either the object or null if we hit the end
99       * of stream before getting another instance. Note that only the local-name
100      * is being used. That won't work to great when two namespaces declare 
101      * a common local-name. Should be easily fixable when needed.
102      * 
103      * @param element
104      * @return
105      * @throws XMLStreamException
106      * @throws JAXBException
107      */
108     public Object getObject(String...elements) 
109         throws XMLStreamException, JAXBException {
110         xmlr.next();
111         while (xmlr.hasNext()) {
112             if (xmlr.isStartElement() && 
113                     contains(elements, xmlr.getName().getLocalPart())) {
114                 Object object = um.unmarshal(xmlr);
115                 return (object instanceof JAXBElement) ?
116                     ((JAXBElement<?>)object).getValue() : object;
117             }
118             xmlr.next();
119         }
120         return null;        
121     }
122     
123     public static InputStream getSampleData() {
124         return Thread.currentThread()
125            .getContextClassLoader()
126            .getResourceAsStream(SAMPLE_FILE);
127     }
128 }