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