package org.openlca.ilcd.io; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.util.HashMap; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.transform.stream.StreamSource; import org.openlca.ilcd.contacts.Contact; import org.openlca.ilcd.descriptors.DescriptorList; import org.openlca.ilcd.flowproperties.FlowProperty; import org.openlca.ilcd.flows.Flow; import org.openlca.ilcd.methods.LCIAMethod; import org.openlca.ilcd.processes.ObjectFactory; import org.openlca.ilcd.processes.Process; import org.openlca.ilcd.productmodel.ProductModel; import org.openlca.ilcd.sources.Source; import org.openlca.ilcd.units.UnitGroup; /** * A helper class for reading and writing ILCD types from / to XML. Uses the * standard JAXB mechanisms but in combination with some ILCD specific things. * The binder can be used for multiple IO-operations, the marshalers and * un-marshalers for the class types are cached. */ public class XmlBinder { private HashMap<Class<?>, Marshaller> marshallers = new HashMap<>(); private HashMap<Class<?>, Unmarshaller> unmarshallers = new HashMap<>(); /** Writes the given ILCD object to a file. */ public void toFile(Object ilcdObject, File file) throws JAXBException { getMarshaller(ilcdObject).marshal(toElement(ilcdObject), file); } /** * Writes the given ILCD object to a output stream. The stream is flushed * and closed within this method. */ public void toStream(Object ilcdObject, OutputStream stream) throws JAXBException, IOException { getMarshaller(ilcdObject).marshal(toElement(ilcdObject), stream); stream.flush(); stream.close(); } /** * Writes the given ILCD object to a writer. The writer is flushed and * closed within this method. */ public void toWriter(Object ilcdObject, Writer writer) throws JAXBException, IOException { getMarshaller(ilcdObject).marshal(toElement(ilcdObject), writer); writer.flush(); writer.close(); } public byte[] toByteArray(Object ilcdObject) throws JAXBException, IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); toStream(ilcdObject, os); return os.toByteArray(); } private Marshaller getMarshaller(Object ilcdObject) throws JAXBException { Class<?> clazz = ilcdObject.getClass(); Marshaller marshaller = marshallers.get(clazz); if (marshaller != null) return marshaller; marshaller = createMarshaller(ilcdObject); marshallers.put(clazz, marshaller); return marshaller; } private Marshaller createMarshaller(Object ilcdObject) throws JAXBException { JAXBContext context = null; if (ilcdObject instanceof Process) context = JAXBContext .newInstance(Process.class, ProductModel.class); else context = JAXBContext.newInstance(ilcdObject.getClass()); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); return marshaller; } /** Reads an ILCD object of the given type from the given file. */ public <T> T fromFile(Class<T> clazz, File file) throws JAXBException { StreamSource source = new StreamSource(file); return unmarshal(clazz, source); } /** * Reads an ILCD object of the given type from the given stream. The stream * is closed within this method. */ public <T> T fromStream(Class<T> clazz, InputStream stream) throws JAXBException, IOException { StreamSource source = new StreamSource(stream); T obj = unmarshal(clazz, source); stream.close(); return obj; } /** * Reads an ILCD object of the given type from the given reader. The reader * is closed within this method. */ public <T> T fromReader(Class<T> clazz, Reader reader) throws JAXBException, IOException { StreamSource source = new StreamSource(reader); T obj = unmarshal(clazz, source); reader.close(); return obj; } private <T> T unmarshal(Class<T> clazz, StreamSource source) throws JAXBException { Unmarshaller unmarshaller = getUnmarshaller(clazz); JAXBElement<T> elem = unmarshaller.unmarshal(source, clazz); return elem.getValue(); } private Unmarshaller getUnmarshaller(Class<?> clazz) throws JAXBException { Unmarshaller unmarshaller = unmarshallers.get(clazz); if (unmarshaller != null) return unmarshaller; unmarshaller = createUnmarshaller(clazz); unmarshallers.put(clazz, unmarshaller); return unmarshaller; } private Unmarshaller createUnmarshaller(Class<?> clazz) throws JAXBException { JAXBContext context = null; if (clazz.equals(Process.class)) context = JAXBContext .newInstance(Process.class, ProductModel.class); else context = JAXBContext.newInstance(clazz); Unmarshaller unmarshaller = context.createUnmarshaller(); return unmarshaller; } /** * Wraps the given ILCD object into a JAXB element using the respective * object factory method for the given type. */ public static JAXBElement<?> toElement(Object value) { if (value instanceof Process) { ObjectFactory factory = new ObjectFactory(); return factory.createProcessDataSet((Process) value); } else if (value instanceof Flow) { org.openlca.ilcd.flows.ObjectFactory fac = new org.openlca.ilcd.flows.ObjectFactory(); return fac.createFlowDataSet((Flow) value); } else if (value instanceof FlowProperty) { org.openlca.ilcd.flowproperties.ObjectFactory fac = new org.openlca.ilcd.flowproperties.ObjectFactory(); return fac.createFlowPropertyDataSet((FlowProperty) value); } else if (value instanceof UnitGroup) { org.openlca.ilcd.units.ObjectFactory fac = new org.openlca.ilcd.units.ObjectFactory(); return fac.createUnitGroupDataSet((UnitGroup) value); } else if (value instanceof Contact) { org.openlca.ilcd.contacts.ObjectFactory fac = new org.openlca.ilcd.contacts.ObjectFactory(); return fac.createContactDataSet((Contact) value); } else if (value instanceof Source) { org.openlca.ilcd.sources.ObjectFactory fac = new org.openlca.ilcd.sources.ObjectFactory(); return fac.createSourceDataSet((Source) value); } else if (value instanceof LCIAMethod) { org.openlca.ilcd.methods.ObjectFactory fac = new org.openlca.ilcd.methods.ObjectFactory(); return fac.createLCIAMethodDataSet((LCIAMethod) value); } else if (value instanceof DescriptorList) { org.openlca.ilcd.descriptors.ObjectFactory fac = new org.openlca.ilcd.descriptors.ObjectFactory(); return fac.createDataSetList((DescriptorList) value); } else { throw new IllegalArgumentException("Unsupported type " + value); } } }