Added persistence of ComponentPresets in the ORK file. Bumped ORK file version number to 1.5 when saving designs containing ComponentPresets. Added a digest string to ComponentPreset which is used during reading and writing ORK files to verify the correct ComponentPreset is used.

This commit is contained in:
Kevin Ruland 2012-04-11 17:36:50 +00:00
parent 68eaf21ef0
commit edcd0008b1
7 changed files with 559 additions and 365 deletions

View File

@ -38,3 +38,5 @@ The following file format versions exist:
deploymentvelocity attributes to <flightdata> element. The motor
digesting algorithm was changed. Adds <separationevent> and
<separationdelay> elements to stage components (except sustainer).
1.5: Introduced with OpenRocket 12.xx. Added ComponentPresets.

View File

@ -26,4 +26,6 @@ public interface ComponentPresetDao {
public void setFavorite( ComponentPreset preset, boolean favorite );
public List<ComponentPreset> find( String manufacturer, String partNo );
}

View File

@ -129,6 +129,17 @@ public class ComponentPresetDatabase extends Database<ComponentPreset> implement
return result;
}
@Override
public List<ComponentPreset> find(String manufacturer, String partNo) {
List<ComponentPreset> presets = new ArrayList<ComponentPreset>();
for( ComponentPreset preset : list ) {
if ( preset.getManufacturer().getSimpleName().equals(manufacturer) && preset.getPartNo().equals(partNo) ) {
presets.add(preset);
}
}
return presets;
}
@Override
public void setFavorite( ComponentPreset preset, boolean favorite ) {
preset.setFavorite(favorite);

View File

@ -184,6 +184,9 @@ public class OpenRocketSaver extends RocketSaver {
*/
private int calculateNecessaryFileVersion(OpenRocketDocument document, StorageOptions opts) {
/*
* File version 1.5 is requires for:
* - saving designs using ComponentPrests
*
* File version 1.4 is required for:
* - saving simulation data
* - saving motor data
@ -195,6 +198,22 @@ public class OpenRocketSaver extends RocketSaver {
* Otherwise use version 1.0.
*/
// Search the rocket for any ComponentPrests
{
Rocket r = document.getRocket();
Iterator<RocketComponent> componentIterator = r.iterator();
boolean usesComponentPreset = false;
while ( !usesComponentPreset && componentIterator.hasNext() ) {
RocketComponent c = componentIterator.next();
if ( c.getPresetComponent() != null ) {
usesComponentPreset = true;
}
}
if ( usesComponentPreset ) {
return FILE_VERSION_DIVISOR + 5;
}
}
// Check if design has simulations defined (version 1.4)
if (document.getSimulationCount() > 0) {
return FILE_VERSION_DIVISOR + 4;

View File

@ -28,6 +28,7 @@ import net.sf.openrocket.file.simplesax.SimpleSAX;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.rocketcomponent.BodyComponent;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.Bulkhead;
@ -101,7 +102,7 @@ public class OpenRocketLoader extends AbstractRocketLoader {
@Override
public OpenRocketDocument loadFromStream(InputStream source, MotorFinder motorFinder) throws RocketLoadException,
IOException {
IOException {
log.info("Loading .ork file");
DocumentLoadingContext context = new DocumentLoadingContext();
context.setMotorFinder(motorFinder);
@ -164,7 +165,7 @@ public class OpenRocketLoader extends AbstractRocketLoader {
class DocumentConfig {
/* Remember to update OpenRocketSaver as well! */
public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4" };
public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4", "1.5" };
/**
* Divisor used in converting an integer version to the point-represented version.
@ -236,6 +237,8 @@ class DocumentConfig {
Reflection.findMethod(RocketComponent.class, "setOverrideSubcomponents", boolean.class)));
setters.put("RocketComponent:comment", new StringSetter(
Reflection.findMethod(RocketComponent.class, "setComment", String.class)));
setters.put("RocketComponent:preset", new ComponentPresetSetter(
Reflection.findMethod(RocketComponent.class, "loadPreset", ComponentPreset.class)));
// ExternalComponent
setters.put("ExternalComponent:finish", new EnumSetter<Finish>(
@ -1934,8 +1937,72 @@ class ColorSetter implements Setter {
}
}
////ComponentPresetSetter - sets a ComponentPreset value
class ComponentPresetSetter implements Setter {
private final Reflection.Method setMethod;
public ComponentPresetSetter(Reflection.Method set) {
this.setMethod = set;
}
@Override
public void set(RocketComponent c, String name, HashMap<String, String> attributes,
WarningSet warnings) {
// FIXME - probably need more data in the warning messages - like what component preset...
String manufacturerName = attributes.get("manufacturer");
if ( manufacturerName == null ) {
warnings.add(Warning.fromString("Invalid ComponentPreset, no manufacturer specified. Ignored"));
return;
}
String productNo = attributes.get("partno");
if ( productNo == null ) {
warnings.add(Warning.fromString("Invalid ComponentPreset, no partno specified. Ignored"));
return;
}
String digest = attributes.get("digest");
if ( digest == null ) {
warnings.add(Warning.fromString("Invalid ComponentPreset, no digest specified."));
}
String type = attributes.get("type");
if ( type == null ) {
warnings.add(Warning.fromString("Invalid ComponentPreset, no type specified."));
}
List<ComponentPreset> presets = Application.getComponentPresetDao().find( manufacturerName, productNo );
ComponentPreset matchingPreset = null;
for( ComponentPreset preset: presets ) {
if ( digest != null && preset.getDigest().equals(digest) ) {
// Found one with matching digest. Take it.
matchingPreset = preset;
break;
}
if ( type != null && preset.getType().name().equals(type) && matchingPreset != null) {
// Found the first one with matching type.
matchingPreset = preset;
}
}
// Was any found?
if ( matchingPreset == null ) {
warnings.add(Warning.fromString("No matching ComponentPreset found"));
return;
}
if ( digest != null && !matchingPreset.getDigest().equals(digest) ) {
warnings.add(Warning.fromString("ComponentPreset has wrong digest"));
}
setMethod.invoke(c, matchingPreset);
}
}
////MaterialSetter - sets a Material value
class MaterialSetter implements Setter {
private final Reflection.Method setMethod;
private final Material.Type type;

View File

@ -9,6 +9,7 @@ import net.sf.openrocket.file.RocketSaver;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.ThrustCurveMotor;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.Rocket;
@ -27,6 +28,13 @@ public class RocketComponentSaver {
protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
elements.add("<name>" + RocketSaver.escapeXML(c.getName()) + "</name>");
ComponentPreset preset = c.getPresetComponent();
if ( preset != null ) {
elements.add("<preset type=\"" + preset.getType() +
"\" manufacturer=\"" + preset.getManufacturer().getSimpleName() +
"\" partno=\"" + preset.getPartNo() + "\" digest=\"" + preset.getDigest() +"\"/>");
}
// Save color and line style if significant
if (!(c instanceof Rocket || c instanceof ComponentAssembly)) {

View File

@ -1,6 +1,13 @@
package net.sf.openrocket.preset;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.openrocket.material.Material;
@ -9,6 +16,7 @@ import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.TextUtil;
/**
@ -25,6 +33,7 @@ public class ComponentPreset implements Comparable<ComponentPreset> {
private final TypedPropertyMap properties = new TypedPropertyMap();
private boolean favorite = false;
private String digest = "";
public enum Type {
BODY_TUBE,
@ -158,23 +167,45 @@ public class ComponentPreset implements Comparable<ComponentPreset> {
}
}
preset.computeDigest();
return preset;
}
// Private constructor to encourage use of factory.
private ComponentPreset() {
}
/**
* Convenience method to retrieve the Type of this ComponentPreset.
*
* @return
*/
public Type getType() {
return properties.get(TYPE);
}
/**
* Convenience method to retrieve the Manufacturer of this ComponentPreset.
* @return
*/
public Manufacturer getManufacturer() {
return properties.get(MANUFACTURER);
}
/**
* Convenience method to retrieve the PartNo of this ComponentPreset.
* @return
*/
public String getPartNo() {
return properties.get(PARTNO);
}
public String getDigest() {
return digest;
}
public boolean has(Object key) {
return properties.containsKey(key);
}
@ -214,4 +245,58 @@ public class ComponentPreset implements Comparable<ComponentPreset> {
return get(MANUFACTURER).toString() + "|" + get(PARTNO);
}
private void computeDigest() {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream os = new DataOutputStream(bos);
List<TypedKey<?>> keys = new ArrayList<TypedKey<?>>( properties.keySet());
Collections.sort(keys, new Comparator<TypedKey<?>>() {
@Override
public int compare( TypedKey<?> a, TypedKey<?> b ) {
return a.getName().compareTo(b.getName());
}
});
for ( TypedKey<?> key : keys ) {
Object value = properties.get(key);
os.writeBytes(key.getName());
if ( key.getType() == Double.class ) {
Double d = (Double) value;
os.writeDouble(d);
} else if (key.getType() == String.class ) {
String s = (String) value;
os.writeBytes(s);
} else if (key.getType() == Manufacturer.class ) {
String s = ((Manufacturer)value).getSimpleName();
os.writeBytes(s);
} else if ( key.getType() == Finish.class ) {
String s = ((Finish)value).name();
os.writeBytes(s);
} else if ( key.getType() == Type.class ) {
String s = ((Type)value).name();
os.writeBytes(s);
} else if ( key.getType() == Boolean.class ) {
Boolean b = (Boolean) value;
os.writeBoolean(b);
} else if ( key.getType() == Material.class ) {
double d = ((Material)value).getDensity();
os.writeDouble(d);
}
}
MessageDigest md5 = MessageDigest.getInstance("MD5");
digest = TextUtil.hexString(md5.digest( bos.toByteArray() ));
}
catch ( Exception e ) {
throw new BugException(e);
}
}
}