1 package net.sf.openrocket.preset.xml;
3 import java.io.BufferedWriter;
4 import java.io.IOException;
5 import java.io.OutputStream;
6 import java.io.OutputStreamWriter;
8 import java.io.StringWriter;
9 import java.util.Collections;
10 import java.util.Comparator;
11 import java.util.List;
13 import javax.xml.bind.JAXBContext;
14 import javax.xml.bind.JAXBException;
15 import javax.xml.bind.Marshaller;
16 import javax.xml.bind.Unmarshaller;
18 import net.sf.openrocket.material.Material;
19 import net.sf.openrocket.preset.ComponentPreset;
20 import net.sf.openrocket.preset.InvalidComponentPresetException;
21 import net.sf.openrocket.startup.Application;
24 * The active manager class that is the entry point for reading and writing *.orc files.
26 public class OpenRocketComponentSaver {
29 * The JAXBContext. JAXBContext is thread-safe.
31 private static JAXBContext context = null;
35 context = JAXBContext.newInstance(OpenRocketComponentDTO.class);
37 catch (JAXBException jaxb) {
38 Application.getLogger().error("Unable to create JAXBContext for loading of *.orc files.", jaxb);
43 * This method marshals a list of materials and ComponentPresets into an .orc formatted XML string.
45 * @param theMaterialList the list of materials to be included
46 * @param thePresetList the list of presets to be included
48 * @return ORC-compliant XML
50 * @throws JAXBException
52 public String marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
54 /** The context is thread-safe, but marshallers are not. Create a local one. */
55 Marshaller marshaller = context.createMarshaller();
56 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
57 StringWriter sw = new StringWriter();
59 // We're going to sort the initial data since that makes the output much easier on the eyes.
61 Collections.sort(theMaterialList, new Comparator<Material>() {
64 public int compare(Material o1, Material o2) {
65 return o1.getName().compareTo( o2.getName() );
70 Collections.sort(thePresetList, new Comparator<ComponentPreset>() {
73 public int compare(ComponentPreset o1, ComponentPreset o2) {
74 int manucmp = o1.getManufacturer().getSimpleName().compareTo( o2.getManufacturer().getSimpleName() );
80 return o1.getPartNo().compareTo( o2.getPartNo());
85 marshaller.marshal(toOpenRocketComponentDTO(theMaterialList, thePresetList), sw);
91 * This method unmarshals from a Reader that is presumed to be open on an XML file in .orc format.
93 * @param is an open reader; StringBufferInputStream could not be used because it's deprecated and does not handle UTF
94 * characters correctly
96 * @return a list of ComponentPresets
98 * @throws InvalidComponentPresetException
101 public List<ComponentPreset> unmarshalFromOpenRocketComponent(Reader is) throws JAXBException,
102 InvalidComponentPresetException {
103 return fromOpenRocketComponent(is).asComponentPresets();
107 * Write an XML representation of a list of presets.
109 * @param dest the stream to write the data to
110 * @param theMaterialList the list of materials to be included
111 * @param thePresetList the list of presets to be included
113 * @throws JAXBException
114 * @throws IOException thrown if the stream could not be written
116 public void save(OutputStream dest, List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
119 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, "UTF-8"));
120 writer.write(marshalToOpenRocketComponent(theMaterialList, thePresetList));
126 * Read from an open Reader instance XML in .orc format and reconstruct an OpenRocketComponentDTO instance.
128 * @param is an open Reader; assumed to be opened on a file of XML in .orc format
130 * @return the OpenRocketComponentDTO that is a POJO representation of the XML; null if the data could not be read or
131 * was in an invalid format
133 private OpenRocketComponentDTO fromOpenRocketComponent(Reader is) throws JAXBException {
134 /** The context is thread-safe, but unmarshallers are not. Create a local one. */
135 Unmarshaller unmarshaller = context.createUnmarshaller();
136 return (OpenRocketComponentDTO) unmarshaller.unmarshal(is);
140 * Root conversion method. It iterates over all subcomponents.
142 * @return a corresponding ORC representation
144 private OpenRocketComponentDTO toOpenRocketComponentDTO(List<Material> theMaterialList, List<ComponentPreset> thePresetList) {
145 OpenRocketComponentDTO rsd = new OpenRocketComponentDTO();
147 if (theMaterialList != null) {
148 for (Material material : theMaterialList) {
149 rsd.addMaterial(new MaterialDTO(material));
153 if (thePresetList != null) {
154 for (ComponentPreset componentPreset : thePresetList) {
155 rsd.addComponent(toComponentDTO(componentPreset));
162 * Factory method that maps a preset to the corresponding DTO handler.
164 * @param thePreset the preset for which a handler will be found
166 * @return a subclass of BaseComponentDTO that can be used for marshalling/unmarshalling a preset; null if not found
167 * for the preset type
169 private static BaseComponentDTO toComponentDTO(ComponentPreset thePreset) {
170 switch (thePreset.getType()) {
172 return new BodyTubeDTO(thePreset);
174 return new TubeCouplerDTO(thePreset);
176 return new NoseConeDTO(thePreset);
178 return new TransitionDTO(thePreset);
180 return new BulkHeadDTO(thePreset);
182 return new CenteringRingDTO(thePreset);
184 return new EngineBlockDTO(thePreset);
186 return new LaunchLugDTO(thePreset);
188 return new StreamerDTO(thePreset);
190 return new ParachuteDTO(thePreset);