Support for base64 images in .orc; performance improvement to the JAXBContext

This commit is contained in:
Doug Pedrick 2012-04-28 03:16:42 +00:00
parent df7ab36b5a
commit 45dae98850
4 changed files with 270 additions and 21 deletions

View File

@ -1,14 +1,6 @@
package net.sf.openrocket.preset.xml;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlValue;
import net.sf.openrocket.database.Databases;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.motor.Manufacturer;
@ -17,6 +9,22 @@ import net.sf.openrocket.preset.InvalidComponentPresetException;
import net.sf.openrocket.preset.TypedPropertyMap;
import net.sf.openrocket.unit.UnitGroup;
import javax.imageio.ImageIO;
import javax.xml.bind.DatatypeConverter;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlInlineBinaryData;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
/**
* Base class for the external representation of all component presets.
*/
@ -35,6 +43,10 @@ public abstract class BaseComponentDTO {
private AnnotatedMassDTO mass;
@XmlElement(name="Filled")
private Boolean filled;
@XmlInlineBinaryData
@XmlJavaTypeAdapter(Base64Adapter.class)
@XmlElement(name = "Thumbnail")
private byte[] image;
/**
* Default constructor.
@ -118,7 +130,30 @@ public abstract class BaseComponentDTO {
this.filled = filled;
}
public abstract ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException;
public byte[] getImageData() {
return image;
}
public void setImageData(final byte[] theImage) {
image = theImage;
}
public BufferedImage getImage() throws IOException {
if (image != null) {
return ImageIO.read(new ByteArrayInputStream(image));
}
return null;
}
public void setImage(BufferedImage theImage) throws IOException {
if (theImage != null) {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(theImage, "png", byteArrayOutputStream);
image = byteArrayOutputStream.toByteArray();
}
}
public abstract ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException;
void addProps(TypedPropertyMap props, List<MaterialDTO> materialList) {
props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(manufacturer));
@ -162,15 +197,15 @@ public abstract class BaseComponentDTO {
material = theMaterial.getName();
}
}
static class AnnotatedLengthDTO {
@XmlAttribute(name="Unit", required=false)
private String unitName = "m";
@XmlValue
private double length;
AnnotatedLengthDTO() {}
AnnotatedLengthDTO( double length ) {
this.length = length;
}
@ -179,21 +214,37 @@ public abstract class BaseComponentDTO {
return UnitGroup.UNITS_LENGTH.getUnit(unitName).fromUnit(length);
}
}
static class AnnotatedMassDTO {
@XmlAttribute(name="Unit", required=false)
private String unitName = "kg";
@XmlValue
private double mass;
AnnotatedMassDTO() {}
AnnotatedMassDTO( double mass ) {
this.mass = mass;
}
public double getValue() {
return UnitGroup.UNITS_MASS.getUnit(unitName).fromUnit(mass);
}
}
static class Base64Adapter extends XmlAdapter<String, byte[]> {
public byte[] unmarshal(String s) {
if (s == null) {
return null;
}
return DatatypeConverter.parseBase64Binary(s);
}
public String marshal(byte[] bytes) {
if (bytes == null) {
return null;
}
return DatatypeConverter.printBase64Binary(bytes);
}
}
}

View File

@ -3,6 +3,7 @@ package net.sf.openrocket.preset.xml;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.InvalidComponentPresetException;
import net.sf.openrocket.startup.Application;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
@ -21,6 +22,20 @@ import java.util.List;
*/
public class OpenRocketComponentSaver {
/**
* The JAXBContext. JAXBContext is thread-safe.
*/
private static JAXBContext context = null;
static {
try {
context = JAXBContext.newInstance(OpenRocketComponentDTO.class);
}
catch (JAXBException jaxb) {
Application.getLogger().error("Unable to create JAXBContext for loading of *.orc files.", jaxb);
}
}
/**
* This method marshals a list of materials and ComponentPresets into an .orc formatted XML string.
*
@ -33,9 +48,8 @@ public class OpenRocketComponentSaver {
*/
public String marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
JAXBException {
JAXBContext binder = JAXBContext.newInstance(OpenRocketComponentDTO.class);
Marshaller marshaller = binder.createMarshaller();
/** The context is thread-safe, but marshallers are not. Create a local one. */
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter sw = new StringWriter();
@ -88,8 +102,8 @@ public class OpenRocketComponentSaver {
* was in an invalid format
*/
private OpenRocketComponentDTO fromOpenRocketComponent(Reader is) throws JAXBException {
JAXBContext bind = JAXBContext.newInstance(OpenRocketComponentDTO.class);
Unmarshaller unmarshaller = bind.createUnmarshaller();
/** The context is thread-safe, but unmarshallers are not. Create a local one. */
Unmarshaller unmarshaller = context.createUnmarshaller();
return (OpenRocketComponentDTO) unmarshaller.unmarshal(is);
}

View File

@ -0,0 +1,72 @@
package net.sf.openrocket.preset.xml;
import net.sf.openrocket.motor.Manufacturer;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPresetFactory;
import net.sf.openrocket.preset.TypedPropertyMap;
import org.junit.Assert;
import org.junit.Test;
import javax.imageio.ImageIO;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.StringReader;
import java.io.StringWriter;
/**
*/
public class BaseComponentDTOTest {
@Test
public void testImage() throws Exception {
TypedPropertyMap presetspec = new TypedPropertyMap();
presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
presetspec.put(ComponentPreset.PARTNO, "partno");
presetspec.put(ComponentPreset.LENGTH, 2.0);
presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
presetspec.put(ComponentPreset.MASS, 100.0);
ComponentPreset preset = ComponentPresetFactory.create(presetspec);
//Convert the presets to a BodyTubeDTO
BodyTubeDTO dto = new BodyTubeDTO(preset);
//Add an image to the DTO.
BufferedImage image = ImageIO.read(this.getClass().getResourceAsStream("or_launcher.png"));
dto.setImage(image);
JAXBContext binder = JAXBContext.newInstance(OpenRocketComponentDTO.class);
Marshaller marshaller = binder.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter sw = new StringWriter();
//Serialize the dto to XML
marshaller.marshal(dto, sw);
String xml = sw.toString();
//Read the XML back to create the dto again
Unmarshaller unmarshaller = binder.createUnmarshaller();
BodyTubeDTO redone = (BodyTubeDTO) unmarshaller.unmarshal(new StringReader(xml));
//Compare the image.
Assert.assertArrayEquals(((DataBufferByte) image.getData().getDataBuffer()).getData(),
((DataBufferByte) redone.getImage().getData().getDataBuffer()).getData());
//Assert the rest of the attributes.
Assert.assertEquals(dto.getInsideDiameter(), redone.getInsideDiameter(), 0.00001);
Assert.assertEquals(dto.getLength(), redone.getLength(), 0.00001);
Assert.assertEquals(dto.getOutsideDiameter(), redone.getOutsideDiameter(), 0.00001);
Assert.assertEquals(dto.getDescription(), redone.getDescription());
Assert.assertEquals(dto.getManufacturer(), redone.getManufacturer());
Assert.assertEquals(dto.getMass(), redone.getMass(), 0.00001);
Assert.assertEquals(dto.getPartNo(), redone.getPartNo());
//Uncomment if you want to write the image to a file to view it.
// ImageIO.write(redone.getImage(), "png", new FileOutputStream("redone.png"));
}
}

View File

@ -0,0 +1,112 @@
package net.sf.openrocket.preset.xml;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* OpenRocketComponentSaver Tester.
*
*/
public class OpenRocketComponentSaverTest {
@Before
public void before() throws Exception {
}
@After
public void after() throws Exception {
}
/**
*
* Method: marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList)
*
*/
@Test
public void testMarshalToOpenRocketComponent() throws Exception {
//TODO: Test goes here...
}
/**
*
* Method: unmarshalFromOpenRocketComponent(Reader is)
*
*/
@Test
public void testUnmarshalFromOpenRocketComponent() throws Exception {
//TODO: Test goes here...
}
/**
*
* Method: save(OutputStream dest, List<Material> theMaterialList, List<ComponentPreset> thePresetList)
*
*/
@Test
public void testSave() throws Exception {
//TODO: Test goes here...
}
/**
*
* Method: fromOpenRocketComponent(Reader is)
*
*/
@Test
public void testFromOpenRocketComponent() throws Exception {
//TODO: Test goes here...
/*
try {
Method method = OpenRocketComponentSaver.getClass().getMethod("fromOpenRocketComponent", Reader.class);
method.setAccessible(true);
method.invoke(<Object>, <Parameters>);
} catch(NoSuchMethodException e) {
} catch(IllegalAccessException e) {
} catch(InvocationTargetException e) {
}
*/
}
/**
*
* Method: toOpenRocketComponentDTO(List<Material> theMaterialList, List<ComponentPreset> thePresetList)
*
*/
@Test
public void testToOpenRocketComponentDTO() throws Exception {
//TODO: Test goes here...
/*
try {
Method method = OpenRocketComponentSaver.getClass().getMethod("toOpenRocketComponentDTO", List<Material>.class, List<ComponentPreset>.class);
method.setAccessible(true);
method.invoke(<Object>, <Parameters>);
} catch(NoSuchMethodException e) {
} catch(IllegalAccessException e) {
} catch(InvocationTargetException e) {
}
*/
}
/**
*
* Method: toComponentDTO(ComponentPreset thePreset)
*
*/
@Test
public void testToComponentDTO() throws Exception {
//TODO: Test goes here...
/*
try {
Method method = OpenRocketComponentSaver.getClass().getMethod("toComponentDTO", ComponentPreset.class);
method.setAccessible(true);
method.invoke(<Object>, <Parameters>);
} catch(NoSuchMethodException e) {
} catch(IllegalAccessException e) {
} catch(InvocationTargetException e) {
}
*/
}
}