1 package net.sf.openrocket.preset.xml;
3 import net.sf.openrocket.material.Material;
4 import net.sf.openrocket.preset.ComponentPreset;
5 import net.sf.openrocket.preset.InvalidComponentPresetException;
6 import net.sf.openrocket.startup.Application;
8 import javax.xml.bind.JAXBContext;
9 import javax.xml.bind.JAXBException;
10 import javax.xml.bind.Marshaller;
11 import javax.xml.bind.Unmarshaller;
12 import java.io.BufferedWriter;
14 import java.io.FileOutputStream;
15 import java.io.IOException;
16 import java.io.OutputStream;
17 import java.io.OutputStreamWriter;
18 import java.io.Reader;
19 import java.io.StringWriter;
20 import java.util.Collections;
21 import java.util.Comparator;
22 import java.util.List;
25 * The active manager class that is the entry point for reading and writing *.orc files.
27 public class OpenRocketComponentSaver {
30 * The JAXBContext. JAXBContext is thread-safe.
32 private static JAXBContext context = null;
36 context = JAXBContext.newInstance(OpenRocketComponentDTO.class);
38 catch (JAXBException jaxb) {
39 Application.getLogger().error("Unable to create JAXBContext for loading of *.orc files.", jaxb);
43 public boolean save(File file, List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
46 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
47 writer.write(marshalToOpenRocketComponent(theMaterialList, thePresetList));
54 * This method marshals a list of materials and ComponentPresets into an .orc formatted XML string.
56 * @param theMaterialList the list of materials to be included
57 * @param thePresetList the list of presets to be included
59 * @return ORC-compliant XML
61 * @throws JAXBException
63 public String marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
65 /** The context is thread-safe, but marshallers are not. Create a local one. */
66 Marshaller marshaller = context.createMarshaller();
67 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
68 StringWriter sw = new StringWriter();
70 // We're going to sort the initial data since that makes the output much easier on the eyes.
72 Collections.sort(theMaterialList, new Comparator<Material>() {
75 public int compare(Material o1, Material o2) {
76 return o1.getName().compareTo( o2.getName() );
81 Collections.sort(thePresetList, new Comparator<ComponentPreset>() {
84 public int compare(ComponentPreset o1, ComponentPreset o2) {
85 int manucmp = o1.getManufacturer().getSimpleName().compareTo( o2.getManufacturer().getSimpleName() );
91 return o1.getPartNo().compareTo( o2.getPartNo());
96 marshaller.marshal(toOpenRocketComponentDTO(theMaterialList, thePresetList), sw);
102 * This method unmarshals from a Reader that is presumed to be open on an XML file in .orc format.
104 * @param is an open reader; StringBufferInputStream could not be used because it's deprecated and does not handle
105 * UTF characters correctly
107 * @return a list of ComponentPresets
109 * @throws InvalidComponentPresetException
112 public OpenRocketComponentDTO unmarshalFromOpenRocketComponent(Reader is) throws JAXBException,
113 InvalidComponentPresetException {
114 return fromOpenRocketComponent(is);
118 * Write an XML representation of a list of presets.
120 * @param dest the stream to write the data to
121 * @param theMaterialList the list of materials to be included
122 * @param thePresetList the list of presets to be included
124 * @throws JAXBException
125 * @throws IOException thrown if the stream could not be written
127 public void save(OutputStream dest, List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
130 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, "UTF-8"));
131 writer.write(marshalToOpenRocketComponent(theMaterialList, thePresetList));
137 * Read from an open Reader instance XML in .orc format and reconstruct an OpenRocketComponentDTO instance.
139 * @param is an open Reader; assumed to be opened on a file of XML in .orc format
141 * @return the OpenRocketComponentDTO that is a POJO representation of the XML; null if the data could not be read
142 * or was in an invalid format
144 private OpenRocketComponentDTO fromOpenRocketComponent(Reader is) throws JAXBException {
145 /** The context is thread-safe, but unmarshallers are not. Create a local one. */
146 Unmarshaller unmarshaller = context.createUnmarshaller();
147 return (OpenRocketComponentDTO) unmarshaller.unmarshal(is); //new StreamSource(is));
151 * Root conversion method. It iterates over all subcomponents.
153 * @return a corresponding ORC representation
155 private OpenRocketComponentDTO toOpenRocketComponentDTO(List<Material> theMaterialList, List<ComponentPreset> thePresetList) {
156 OpenRocketComponentDTO rsd = new OpenRocketComponentDTO();
158 if (theMaterialList != null) {
159 for (Material material : theMaterialList) {
160 rsd.addMaterial(new MaterialDTO(material));
164 if (thePresetList != null) {
165 for (ComponentPreset componentPreset : thePresetList) {
166 rsd.addComponent(toComponentDTO(componentPreset));
173 * Factory method that maps a preset to the corresponding DTO handler.
175 * @param thePreset the preset for which a handler will be found
177 * @return a subclass of BaseComponentDTO that can be used for marshalling/unmarshalling a preset; null if not found
178 * for the preset type
180 private static BaseComponentDTO toComponentDTO(ComponentPreset thePreset) {
181 switch (thePreset.getType()) {
183 return new BodyTubeDTO(thePreset);
185 return new TubeCouplerDTO(thePreset);
187 return new NoseConeDTO(thePreset);
189 return new TransitionDTO(thePreset);
191 return new BulkHeadDTO(thePreset);
193 return new CenteringRingDTO(thePreset);
195 return new EngineBlockDTO(thePreset);
197 return new LaunchLugDTO(thePreset);
199 return new StreamerDTO(thePreset);
201 return new ParachuteDTO(thePreset);