add220a692e6059b52c9d4a9de25f7027e9b477e
[debian/openrocket] / core / src / net / sf / openrocket / preset / xml / OpenRocketComponentSaver.java
1 package net.sf.openrocket.preset.xml;
2
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;
7
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;
13 import java.io.IOException;
14 import java.io.OutputStream;
15 import java.io.OutputStreamWriter;
16 import java.io.Reader;
17 import java.io.StringWriter;
18 import java.util.List;
19
20 /**
21  * The active manager class that is the entry point for reading and writing *.orc files.
22  */
23 public class OpenRocketComponentSaver {
24
25     /**
26      * The JAXBContext.  JAXBContext is thread-safe.
27      */
28     private static JAXBContext context = null;
29
30     static {
31         try {
32             context = JAXBContext.newInstance(OpenRocketComponentDTO.class);
33         }
34         catch (JAXBException jaxb) {
35             Application.getLogger().error("Unable to create JAXBContext for loading of *.orc files.", jaxb);
36         }
37     }
38
39     /**
40      * This method marshals a list of materials and ComponentPresets into an .orc formatted XML string.
41      *
42      * @param theMaterialList the list of materials to be included
43      * @param thePresetList   the list of presets to be included
44      *
45      * @return ORC-compliant XML
46      *
47      * @throws JAXBException
48      */
49     public String marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
50                                                                                                                     JAXBException {
51         /** The context is thread-safe, but marshallers are not.  Create a local one. */
52         Marshaller marshaller = context.createMarshaller();
53         marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
54         StringWriter sw = new StringWriter();
55
56         marshaller.marshal(toOpenRocketComponentDTO(theMaterialList, thePresetList), sw);
57         return sw.toString();
58
59     }
60
61     /**
62      * This method unmarshals from a Reader that is presumed to be open on an XML file in .orc format.
63      *
64      * @param is an open reader; StringBufferInputStream could not be used because it's deprecated and does not handle UTF
65      *           characters correctly
66      *
67      * @return a list of ComponentPresets
68      *
69      * @throws InvalidComponentPresetException
70      *
71      */
72     public List<ComponentPreset> unmarshalFromOpenRocketComponent(Reader is) throws JAXBException,
73                                                                                     InvalidComponentPresetException {
74         return fromOpenRocketComponent(is).asComponentPresets();
75     }
76
77     /**
78      * Write an XML representation of a list of presets.
79      *
80      * @param dest            the stream to write the data to
81      * @param theMaterialList the list of materials to be included
82      * @param thePresetList   the list of presets to be included
83      *
84      * @throws JAXBException
85      * @throws IOException   thrown if the stream could not be written
86      */
87     public void save(OutputStream dest, List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
88                                                                                                              IOException,
89                                                                                                              JAXBException {
90         BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, "UTF-8"));
91         writer.write(marshalToOpenRocketComponent(theMaterialList, thePresetList));
92         writer.flush();
93         writer.close();
94     }
95
96     /**
97      * Read from an open Reader instance XML in .orc format and reconstruct an OpenRocketComponentDTO instance.
98      *
99      * @param is an open Reader; assumed to be opened on a file of XML in .orc format
100      *
101      * @return the OpenRocketComponentDTO that is a POJO representation of the XML; null if the data could not be read or
102      *         was in an invalid format
103      */
104     private OpenRocketComponentDTO fromOpenRocketComponent(Reader is) throws JAXBException {
105         /** The context is thread-safe, but unmarshallers are not.  Create a local one. */
106         Unmarshaller unmarshaller = context.createUnmarshaller();
107         return (OpenRocketComponentDTO) unmarshaller.unmarshal(is);
108     }
109
110     /**
111      * Root conversion method.  It iterates over all subcomponents.
112      *
113      * @return a corresponding ORC representation
114      */
115     private OpenRocketComponentDTO toOpenRocketComponentDTO(List<Material> theMaterialList, List<ComponentPreset> thePresetList) {
116         OpenRocketComponentDTO rsd = new OpenRocketComponentDTO();
117
118         if (theMaterialList != null) {
119             for (Material material : theMaterialList) {
120                 rsd.addMaterial(new MaterialDTO(material));
121             }
122         }
123
124         if (thePresetList != null) {
125             for (ComponentPreset componentPreset : thePresetList) {
126                 rsd.addComponent(toComponentDTO(componentPreset));
127             }
128         }
129         return rsd;
130     }
131
132     /**
133      * Factory method that maps a preset to the corresponding DTO handler.
134      *
135      * @param thePreset the preset for which a handler will be found
136      *
137      * @return a subclass of BaseComponentDTO that can be used for marshalling/unmarshalling a preset; null if not found
138      *         for the preset type
139      */
140     private static BaseComponentDTO toComponentDTO(ComponentPreset thePreset) {
141         switch (thePreset.getType()) {
142             case BODY_TUBE:
143                 return new BodyTubeDTO(thePreset);
144             case TUBE_COUPLER:
145                 return new TubeCouplerDTO(thePreset);
146             case NOSE_CONE:
147                 return new NoseConeDTO(thePreset);
148             case TRANSITION:
149                 return new TransitionDTO(thePreset);
150             case BULK_HEAD:
151                 return new BulkHeadDTO(thePreset);
152             case CENTERING_RING:
153                 return new CenteringRingDTO(thePreset);
154             case ENGINE_BLOCK:
155                 return new EngineBlockDTO(thePreset);
156         }
157
158         return null;
159     }
160 }