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