Support for base64 images in .orc; performance improvement to the JAXBContext
[debian/openrocket] / core / src / net / sf / openrocket / preset / xml / BaseComponentDTO.java
1
2 package net.sf.openrocket.preset.xml;
3
4 import net.sf.openrocket.database.Databases;
5 import net.sf.openrocket.material.Material;
6 import net.sf.openrocket.motor.Manufacturer;
7 import net.sf.openrocket.preset.ComponentPreset;
8 import net.sf.openrocket.preset.InvalidComponentPresetException;
9 import net.sf.openrocket.preset.TypedPropertyMap;
10 import net.sf.openrocket.unit.UnitGroup;
11
12 import javax.imageio.ImageIO;
13 import javax.xml.bind.DatatypeConverter;
14 import javax.xml.bind.annotation.XmlAccessType;
15 import javax.xml.bind.annotation.XmlAccessorType;
16 import javax.xml.bind.annotation.XmlAttribute;
17 import javax.xml.bind.annotation.XmlElement;
18 import javax.xml.bind.annotation.XmlInlineBinaryData;
19 import javax.xml.bind.annotation.XmlValue;
20 import javax.xml.bind.annotation.adapters.XmlAdapter;
21 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
22 import java.awt.image.BufferedImage;
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.util.List;
27
28 /**
29  * Base class for the external representation of all component presets.
30  */
31 @XmlAccessorType(XmlAccessType.FIELD)
32 public abstract class BaseComponentDTO {
33
34         @XmlElement(name = "Manufacturer")
35         private String manufacturer;
36         @XmlElement(name = "PartNumber")
37         private String partNo;
38         @XmlElement(name = "Description")
39         private String description;
40         @XmlElement(name = "Material")
41         private AnnotatedMaterialDTO material;
42         @XmlElement(name = "Mass")
43         private AnnotatedMassDTO mass;
44         @XmlElement(name="Filled")
45         private Boolean filled;
46     @XmlInlineBinaryData
47     @XmlJavaTypeAdapter(Base64Adapter.class)
48     @XmlElement(name = "Thumbnail")
49     private byte[] image;
50
51         /**
52          * Default constructor.
53          */
54         protected BaseComponentDTO() {
55         }
56
57         /**
58          * Constructor.
59          *
60          * @param preset  the preset to use to pull data values out of
61          *
62          * @throws net.sf.openrocket.util.BugException thrown if the expected body tube keys are not in the preset
63          */
64         protected BaseComponentDTO(final ComponentPreset preset) {
65                 setManufacturer(preset.getManufacturer().getSimpleName());
66                 setPartNo(preset.getPartNo());
67                 if ( preset.has(ComponentPreset.DESCRIPTION )) {
68                         setDescription(preset.get(ComponentPreset.DESCRIPTION));
69                 }
70                 if ( preset.has(ComponentPreset.MATERIAL)) {
71                         setMaterial(new AnnotatedMaterialDTO(preset.get(ComponentPreset.MATERIAL)));
72                 }
73                 if (preset.has(ComponentPreset.MASS)) {
74                         setMass(preset.get(ComponentPreset.MASS));
75                 }
76                 if ( preset.has(ComponentPreset.FILLED) ) {
77                         setFilled( preset.get(ComponentPreset.FILLED));
78                 }
79         }
80
81         public String getManufacturer() {
82                 return manufacturer;
83         }
84
85         public void setManufacturer(final String theManufacturer) {
86                 manufacturer = theManufacturer;
87         }
88
89         public String getPartNo() {
90                 return partNo;
91         }
92
93         public void setPartNo(final String thePartNo) {
94                 partNo = thePartNo;
95         }
96
97         public String getDescription() {
98                 return description;
99         }
100
101         public void setDescription(final String theDescription) {
102                 description = theDescription;
103         }
104
105         public AnnotatedMaterialDTO getMaterial() {
106                 return material;
107         }
108
109         public void setMaterial(final AnnotatedMaterialDTO theMaterial) {
110                 material = theMaterial;
111         }
112
113         public double getMass() {
114                 return mass.getValue();
115         }
116
117         public void setMass(final AnnotatedMassDTO theMass) {
118                 mass = theMass;
119         }
120
121         public void setMass(final double theMass) {
122                 mass = new AnnotatedMassDTO(theMass);
123         }
124
125         public Boolean getFilled() {
126                 return filled;
127         }
128
129         public void setFilled(Boolean filled) {
130                 this.filled = filled;
131         }
132
133     public byte[] getImageData() {
134         return image;
135     }
136
137     public void setImageData(final byte[] theImage) {
138         image = theImage;
139     }
140
141     public BufferedImage getImage() throws IOException {
142         if (image != null) {
143             return ImageIO.read(new ByteArrayInputStream(image));
144         }
145         return null;
146     }
147
148     public void setImage(BufferedImage theImage) throws IOException {
149         if (theImage != null) {
150             final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
151             ImageIO.write(theImage, "png", byteArrayOutputStream);
152             image = byteArrayOutputStream.toByteArray();
153         }
154     }
155
156     public abstract ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException;
157
158         void addProps(TypedPropertyMap props, List<MaterialDTO> materialList) {
159                 props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(manufacturer));
160                 props.put(ComponentPreset.PARTNO, partNo);
161                 if ( description != null ) {
162                         props.put(ComponentPreset.DESCRIPTION, description);
163                 }
164                 Material m = find(materialList, material);
165                 if ( m != null ) {
166                         props.put(ComponentPreset.MATERIAL, find(materialList, material));
167                 }
168                 if ( mass != null ) {
169                         props.put(ComponentPreset.MASS, getMass());
170                 }
171                 if ( filled != null ) {
172                         props.put(ComponentPreset.FILLED, getFilled());
173                 }
174         }
175
176         private Material find(List<MaterialDTO> materialList, AnnotatedMaterialDTO dto) {
177                 for (int i = 0; i < materialList.size(); i++) {
178                         MaterialDTO materialDTO =  materialList.get(i);
179                         if (materialDTO.getType().name().equals(dto.type) && materialDTO.getName().equals(dto.material)) {
180                                 return materialDTO.asMaterial();
181                         }
182                 }
183                 //Otherwise fallback and look at factory default materials.
184                 return Databases.findMaterial(Material.Type.valueOf(material.type), material.material);
185         }
186
187         static class AnnotatedMaterialDTO {
188                 @XmlAttribute(name = "Type")
189                 private String type;
190                 @XmlValue
191                 private String material;
192
193                 AnnotatedMaterialDTO() {}
194
195                 AnnotatedMaterialDTO(Material theMaterial) {
196                         type = theMaterial.getType().name();
197                         material = theMaterial.getName();
198                 }
199         }
200
201         static class AnnotatedLengthDTO {
202                 @XmlAttribute(name="Unit", required=false)
203                 private String unitName = "m";
204                 @XmlValue
205                 private double length;
206
207                 AnnotatedLengthDTO() {}
208
209                 AnnotatedLengthDTO( double length ) {
210                         this.length = length;
211                 }
212
213                 public double getValue() {
214                         return UnitGroup.UNITS_LENGTH.getUnit(unitName).fromUnit(length);
215                 }
216         }
217
218         static class AnnotatedMassDTO {
219                 @XmlAttribute(name="Unit", required=false)
220                 private String unitName = "kg";
221                 @XmlValue
222                 private double mass;
223
224                 AnnotatedMassDTO() {}
225
226                 AnnotatedMassDTO( double mass ) {
227                         this.mass = mass;
228                 }
229
230                 public double getValue() {
231                         return UnitGroup.UNITS_MASS.getUnit(unitName).fromUnit(mass);
232                 }
233         }
234
235     static class Base64Adapter extends XmlAdapter<String, byte[]> {
236         public byte[] unmarshal(String s) {
237             if (s == null) {
238                 return null;
239             }
240             return DatatypeConverter.parseBase64Binary(s);
241         }
242
243         public String marshal(byte[] bytes) {
244             if (bytes == null) {
245                 return null;
246             }
247             return DatatypeConverter.printBase64Binary(bytes);
248         }
249     }
250 }