diff --git a/SBOLCanvasBackend/src/utils/MxToSBML.java b/SBOLCanvasBackend/src/utils/MxToSBML.java
index 248e8277..8ca560fb 100644
--- a/SBOLCanvasBackend/src/utils/MxToSBML.java
+++ b/SBOLCanvasBackend/src/utils/MxToSBML.java
@@ -158,8 +158,6 @@ public void toSBML(InputStream graphStream, OutputStream sbmlStream)
SBMLDocument document = setupDocument(graphStream);
- // Write to SBML document stream
- // https://sbml.org/jsbml/files/doc/api/1.6.1/org/sbml/jsbml/SBMLWriter.html
org.sbml.jsbml.TidySBMLWriter.write(document, sbmlStream, "SBOLCanvas", "1.0", ' ', (short) 2);
}
@@ -228,10 +226,8 @@ private HashMap createPromoterSpecies(Model sbmlModel, mxGraphMo
}
}
- // TODO: For all IllegalArgumentExceptions, add user validation before export
- if (promoterGlyph == null) {
- throw new IllegalArgumentException("Backbone has no promoter glyph. Add a Promoter to the backbone for SBML export.");
- }
+ if (promoterGlyph == null)
+ continue;
GlyphInfo promoterInfo = (GlyphInfo) infoDict.get(promoterGlyph.getValue());
String promoterName = promoterInfo.getName();
@@ -280,6 +276,8 @@ private void createMolecularSpecies(Model sbmlModel, mxGraphModel graphModel, mx
for (mxCell glyph : speciesGlyphs) {
Species species = createSpecies(sbmlModel, glyph);
+ if (species == null)
+ continue;
glyphToSpeciesData.put((String) glyph.getValue(),
new SpeciesData(species, glyph.getGeometry()));
}
@@ -304,9 +302,8 @@ private void createProductionReactions(Model sbmlModel, mxGraphModel graphModel,
if (cell.isEdge()) {
InteractionInfo info = (InteractionInfo) interactionDict.get(cell.getValue());
- if (info == null) {
+ if (info == null)
continue;
- }
String type = info.getInteractionType();
URI typeURI = SBOLData.interactions.getValue(type);
@@ -345,13 +342,11 @@ private void createProductionReactions(Model sbmlModel, mxGraphModel graphModel,
double np = getParam(promoterInfo.getSimulationData(), SBOLData.PARAM_NP, SequenceOntology.PROMOTER, "promoter '" + promoterId + "'");
for (mxCell productionEdge : tuData.productionEdges) {
mxCell targetCell = (mxCell) productionEdge.getTarget();
- if (targetCell == null) {
- throw new IllegalArgumentException("Production edge has no target cell (disconnected edge)");
- }
+ if (targetCell == null)
+ continue;
SpeciesData productData = glyphToSpeciesData.get((String) targetCell.getValue());
- if (productData == null) {
- throw new IllegalArgumentException("Product species not found for production edge");
- }
+ if (productData == null)
+ continue;
SpeciesReference product = reaction.createProduct(productData.species);
product.setConstant(true);
product.setStoichiometry(np);
@@ -372,19 +367,17 @@ private void createProductionReactions(Model sbmlModel, mxGraphModel graphModel,
if (typeURI != null && modifierCell != null) {
if (typeURI.equals(SBOLData.interactions.getValue("Inhibition"))) {
- repressorEdge = inEdge;
SpeciesData modifierData = glyphToSpeciesData.get((String) modifierCell.getValue());
- if (modifierData == null) {
- throw new IllegalArgumentException("Repressor species not found for inhibition edge");
- }
+ if (modifierData == null)
+ continue;
+ repressorEdge = inEdge;
ModifierSpeciesReference mod = reaction.createModifier(modifierData.species);
mod.setSBOTerm(20); // SBO:0000020 Inhibitor
} else if (typeURI.equals(SBOLData.interactions.getValue("Stimulation"))) {
- activatorEdge = inEdge;
SpeciesData modifierData = glyphToSpeciesData.get((String) modifierCell.getValue());
- if (modifierData == null) {
- throw new IllegalArgumentException("Activator species not found for stimulation edge");
- }
+ if (modifierData == null)
+ continue;
+ activatorEdge = inEdge;
ModifierSpeciesReference mod = reaction.createModifier(modifierData.species);
mod.setSBOTerm(459); // SBO:0000459 Stimulator
}
@@ -393,21 +386,17 @@ private void createProductionReactions(Model sbmlModel, mxGraphModel graphModel,
}
if (repressorEdge != null && activatorEdge != null) {
- throw new IllegalArgumentException(
- "Mixed regulation (both activators and repressors) not supported for promoter: " + promoterId);
+ sbmlModel.removeReaction(reaction);
+ continue;
}
- // TODO: Unregulated promoters not supported
if (repressorEdge != null) {
- buildRepressionFormula(reaction, promoterId, promoterInfo, repressorEdge);
+ buildRepressionFormula(sbmlModel, reaction, promoterId, promoterInfo, repressorEdge);
} else if (activatorEdge != null) {
- buildActivationFormula(reaction, promoterId, promoterInfo, activatorEdge);
+ buildActivationFormula(sbmlModel, reaction, promoterId, promoterInfo, activatorEdge);
} else {
- String promoterName = promoterInfo.getName();
- if (promoterName == null || promoterName.isEmpty()) {
- promoterName = promoterInfo.getDisplayID();
- }
- throw new IllegalArgumentException("Promoter '" + promoterName + "' has no regulator.");
+ // TODO: Add constitutive (unregulated) promoter formula
+ sbmlModel.removeReaction(reaction);
}
}
}
@@ -428,9 +417,8 @@ private void createDegradationReactions(Model sbmlModel, mxGraphModel graphModel
if (cell.isEdge()) {
InteractionInfo info = (InteractionInfo) interactionDict.get(cell.getValue());
- if (info == null) {
+ if (info == null)
continue;
- }
String type = info.getInteractionType();
URI typeURI = SBOLData.interactions.getValue(type);
@@ -473,13 +461,17 @@ private void createComplexReactions(Model sbmlModel, mxGraphModel graphModel, mx
* Builds the repression-only Hill equation formula.
*
* Parameters:
- * ko, ko_f, ko_r, nr, kr_f_, kr_r_, nc_
+ * ko, ko_f, ko_r, nr, kr__f, kr__r, nc__r
*
* Formula:
* (P * ko * (ko_f/ko_r) * nr) / (1 + (ko_f/ko_r) * nr + ((kr_f/kr_r) * R)^nc)
*/
- private void buildRepressionFormula(Reaction reaction, String promoterId, GlyphInfo promoterInfo,
+ private void buildRepressionFormula(Model sbmlModel, Reaction reaction, String promoterId, GlyphInfo promoterInfo,
mxCell repressorEdge) {
+ mxCell repCell = (mxCell) repressorEdge.getSource();
+ SpeciesData repData = glyphToSpeciesData.get((String) repCell.getValue());
+ if (repData == null) return;
+
KineticLaw law = reaction.createKineticLaw();
Hashtable promoterSimData = promoterInfo.getSimulationData();
@@ -493,12 +485,6 @@ private void buildRepressionFormula(Reaction reaction, String promoterId, GlyphI
law.createLocalParameter("ko_f").setValue(Ko_f);
law.createLocalParameter("ko_r").setValue(Ko_r);
law.createLocalParameter("nr").setValue(nr);
-
- mxCell repCell = (mxCell) repressorEdge.getSource();
- SpeciesData repData = glyphToSpeciesData.get((String) repCell.getValue());
- if (repData == null) {
- throw new IllegalArgumentException("Repressor species not found for edge");
- }
String repId = repData.species.getId();
InteractionInfo repInfo = (InteractionInfo) interactionDict.get(repressorEdge.getValue());
@@ -508,9 +494,9 @@ private void buildRepressionFormula(Reaction reaction, String promoterId, GlyphI
double Kr_r = getParam(repSimData, SBOLData.PARAM_KR_R, SystemsBiologyOntology.INHIBITION, repContext);
double nc = getParam(repSimData, SBOLData.PARAM_NC, SystemsBiologyOntology.INHIBITION, repContext);
- String p_Krf = "kr_f_" + repId;
- String p_Krr = "kr_r_" + repId;
- String p_nc = "nc_" + repId;
+ String p_Krf = "kr_" + repId + "_f";
+ String p_Krr = "kr_" + repId + "_r";
+ String p_nc = "nc_" + repId + "_r";
law.createLocalParameter(p_Krf).setValue(Kr_f);
law.createLocalParameter(p_Krr).setValue(Kr_r);
law.createLocalParameter(p_nc).setValue(nc);
@@ -523,7 +509,8 @@ private void buildRepressionFormula(Reaction reaction, String promoterId, GlyphI
try {
law.setMath(new FormulaParser(new ByteArrayInputStream(formula.getBytes(StandardCharsets.UTF_8))).parse());
} catch (Exception e) {
- throw new RuntimeException("Failed to parse repression kinetic law: " + e.getMessage(), e);
+ System.err.println("Warning: repression formula parse failed for " + promoterId + ": " + e.getMessage());
+ sbmlModel.removeReaction(reaction);
}
}
@@ -535,10 +522,14 @@ private void buildRepressionFormula(Reaction reaction, String promoterId, GlyphI
* / (1 + (ko_f/ko_r) * nr + (kao_f/kao_r) * nr * ((ka_f/ka_r) * A)^nc)
*
* Parameters:
- * kb, ka, ko_f, ko_r, kao_f, kao_r, nr, ka_f_, ka_r_, nc_
+ * kb, ka, ko_f, ko_r, kao_f, kao_r, nr, ka__f, ka__r, nc__a
*/
- private void buildActivationFormula(Reaction reaction, String promoterId, GlyphInfo promoterInfo,
+ private void buildActivationFormula(Model sbmlModel, Reaction reaction, String promoterId, GlyphInfo promoterInfo,
mxCell activatorEdge) {
+ mxCell actCell = (mxCell) activatorEdge.getSource();
+ SpeciesData actData = glyphToSpeciesData.get((String) actCell.getValue());
+ if (actData == null) return;
+
KineticLaw law = reaction.createKineticLaw();
Hashtable promoterSimData = promoterInfo.getSimulationData();
@@ -558,12 +549,6 @@ private void buildActivationFormula(Reaction reaction, String promoterId, GlyphI
law.createLocalParameter("kao_f").setValue(Kao_f);
law.createLocalParameter("kao_r").setValue(Kao_r);
law.createLocalParameter("nr").setValue(nr);
-
- mxCell actCell = (mxCell) activatorEdge.getSource();
- SpeciesData actData = glyphToSpeciesData.get((String) actCell.getValue());
- if (actData == null) {
- throw new IllegalArgumentException("Activator species not found for edge");
- }
String actId = actData.species.getId();
InteractionInfo actInfo = (InteractionInfo) interactionDict.get(activatorEdge.getValue());
@@ -573,9 +558,9 @@ private void buildActivationFormula(Reaction reaction, String promoterId, GlyphI
double Ka_r = getParam(actSimData, SBOLData.PARAM_KA_R, SystemsBiologyOntology.STIMULATION, actContext);
double nc = getParam(actSimData, SBOLData.PARAM_NC, SystemsBiologyOntology.STIMULATION, actContext);
- String p_Kaf = "ka_f_" + actId;
- String p_Kar = "ka_r_" + actId;
- String p_nc = "nc_" + actId;
+ String p_Kaf = "ka_" + actId + "_f";
+ String p_Kar = "ka_" + actId + "_r";
+ String p_nc = "nc_" + actId + "_a";
law.createLocalParameter(p_Kaf).setValue(Ka_f);
law.createLocalParameter(p_Kar).setValue(Ka_r);
law.createLocalParameter(p_nc).setValue(nc);
@@ -592,7 +577,8 @@ private void buildActivationFormula(Reaction reaction, String promoterId, GlyphI
try {
law.setMath(new FormulaParser(new ByteArrayInputStream(formula.getBytes(StandardCharsets.UTF_8))).parse());
} catch (Exception e) {
- throw new RuntimeException("Failed to parse activation kinetic law: " + e.getMessage(), e);
+ System.err.println("Warning: activation formula parse failed for " + promoterId + ": " + e.getMessage());
+ sbmlModel.removeReaction(reaction);
}
}
@@ -716,7 +702,7 @@ private void createComplexEdges(Layout layout, Reaction reaction,
*/
private void createVisualLayout(Model sbmlModel) {
if (glyphToSpeciesData.isEmpty()) {
- return; // No species — layout bounds are uninitialized
+ return; // No species -- layout bounds are uninitialized
}
Layout layout = setupLayout(sbmlModel);
@@ -747,16 +733,14 @@ private void createEvents(Model sbmlModel) {
String targetSpecies = getStringParam(simData, SBOLData.PARAM_EVENT_TARGET_SPECIES);
if (targetSpecies == null || targetSpecies.isEmpty()) {
- throw new IllegalArgumentException(context + " missing target species");
+ continue;
}
// Resolve display name to SBML species ID. The user enters a display
// name (e.g., "LacI protein") but SBML uses sanitized IDs ("LacI_protein").
String speciesId = resolveSpeciesId(sbmlModel, targetSpecies, displayNameToSpeciesId);
- if (speciesId == null) {
- throw new IllegalArgumentException(
- context + " references unknown species '" + targetSpecies + "'");
- }
+ if (speciesId == null)
+ continue;
String eventName = getStringParam(simData, SBOLData.PARAM_EVENT_NAME);
if (eventName == null || eventName.isEmpty()) {
@@ -805,10 +789,8 @@ private void createEvents(Model sbmlModel) {
*/
private Species createSpecies(Model model, mxCell glyph) {
GlyphInfo glyphInfo = (GlyphInfo) infoDict.get(glyph.getValue());
- if (glyphInfo == null) {
- throw new IllegalArgumentException(
- "No GlyphInfo found for species glyph '" + glyph.getValue() + "' (orphaned glyph?)");
- }
+ if (glyphInfo == null)
+ return null;
// SBML ID becomes the label. Pick Name over DisplayID
String displayName = glyphInfo.getDisplayID();
@@ -877,13 +859,11 @@ private Species createSpecies(Model model, mxCell glyph) {
*/
private void createDegradationReaction(Model model, mxCell edge, InteractionInfo info, mxGraphModel graphModel) {
mxCell source = (mxCell) edge.getSource();
- if (source == null) {
- throw new IllegalArgumentException("Degradation edge has no source cell (disconnected edge)");
- }
+ if (source == null)
+ return;
SpeciesData sourceData = glyphToSpeciesData.get((String) source.getValue());
- if (sourceData == null) {
- throw new IllegalArgumentException("Source species not found for degradation edge");
- }
+ if (sourceData == null)
+ return;
String speciesId = sourceData.species.getId();
String reactionId = "Degradation_" + speciesId;
@@ -903,7 +883,9 @@ private void createDegradationReaction(Model model, mxCell edge, InteractionInfo
law.setMath(new FormulaParser(
new ByteArrayInputStream(("kd * " + speciesId).getBytes(StandardCharsets.UTF_8))).parse());
} catch (Exception e) {
- throw new RuntimeException("Failed to parse degradation kinetic law: " + e.getMessage(), e);
+ System.err.println("Warning: degradation formula parse failed for " + speciesId + ": " + e.getMessage());
+ model.removeReaction(reaction);
+ return;
}
}
@@ -916,19 +898,16 @@ private void createDegradationReaction(Model model, mxCell edge, InteractionInfo
private void createComplexFormationReaction(Model model, mxCell node, InteractionInfo info,
mxGraphModel graphModel) {
Object[] outgoing = mxGraphModel.getOutgoingEdges(graphModel, node);
- if (outgoing.length == 0) {
- throw new IllegalArgumentException("Complex formation node has no product edge");
- }
+ if (outgoing.length == 0)
+ return;
mxCell outEdge = (mxCell) outgoing[0];
mxCell target = (mxCell) outEdge.getTarget();
- if (target == null) {
- throw new IllegalArgumentException("Complex formation product edge has no target cell (disconnected edge)");
- }
+ if (target == null)
+ return;
SpeciesData productData = glyphToSpeciesData.get((String) target.getValue());
- if (productData == null) {
- throw new IllegalArgumentException("Product species not found for complex formation");
- }
+ if (productData == null)
+ return;
String productId = productData.species.getId();
String reactionId = "Complex_" + productId;
@@ -945,13 +924,11 @@ private void createComplexFormationReaction(Model model, mxCell node, Interactio
for (Object obj : incoming) {
mxCell inEdge = (mxCell) obj;
mxCell source = (mxCell) inEdge.getSource();
- if (source == null) {
- throw new IllegalArgumentException("Complex formation reactant edge has no source cell (disconnected edge)");
- }
+ if (source == null)
+ continue;
SpeciesData sourceData = glyphToSpeciesData.get((String) source.getValue());
- if (sourceData == null) {
- throw new IllegalArgumentException("Reactant species not found for complex formation edge");
- }
+ if (sourceData == null)
+ continue;
String speciesId = sourceData.species.getId();
SpeciesReference r = reaction.createReactant(sourceData.species);
@@ -986,27 +963,31 @@ private void createComplexFormationReaction(Model model, mxCell node, Interactio
law.setMath(new FormulaParser(new ByteArrayInputStream(rateLaw.toString().getBytes(StandardCharsets.UTF_8)))
.parse());
} catch (Exception e) {
- throw new RuntimeException("Failed to parse complex formation kinetic law: " + e.getMessage(), e);
+ System.err.println("Warning: complex formation formula parse failed for " + productId + ": " + e.getMessage());
+ model.removeReaction(reaction);
+ return;
}
}
/**
* Extracts a double from a value that may be a Number, a numeric String,
- * or null. Returns defaultVal for null; throws for non-numeric values.
+ * or null. Returns defaultVal for null, unparseable strings, or unexpected types.
*/
- private static double extractDouble(Object val, double defaultVal, String context) {
- if (val == null) return defaultVal;
- if (val instanceof Number) return ((Number) val).doubleValue();
+ private double extractDouble(Object val, double defaultVal, String context) {
+ if (val == null)
+ return defaultVal;
+ if (val instanceof Number)
+ return ((Number) val).doubleValue();
if (val instanceof String) {
try {
return Double.parseDouble((String) val);
} catch (NumberFormatException e) {
- throw new IllegalArgumentException(
- "Non-numeric value for " + context + ": '" + val + "'", e);
+ System.err.println("Warning: non-numeric value for " + context + ": '" + val + "', using default " + defaultVal);
+ return defaultVal;
}
}
- throw new IllegalArgumentException(
- "Invalid type for " + context + ". Expected number, got: " + val.getClass().getSimpleName());
+ System.err.println("Warning: unexpected type for " + context + ": " + val.getClass().getSimpleName() + ", using default " + defaultVal);
+ return defaultVal;
}
/**
@@ -1031,7 +1012,8 @@ private double getParam(Hashtable simData, String paramName, URI
* Returns null if the key is missing or the value is null.
*/
private String getStringParam(Hashtable simData, String paramName) {
- if (simData == null || !simData.containsKey(paramName)) return null;
+ if (simData == null || !simData.containsKey(paramName))
+ return null;
Object val = simData.get(paramName);
return val != null ? val.toString() : null;
}
@@ -1065,28 +1047,27 @@ private double getDefaultValue(URI type, String paramName, String context) {
}
if (key == null) {
- throw new IllegalArgumentException(
- "Cannot find default for parameter '" + paramName + "' on " + context + ": unknown type");
+ System.err.println("Warning: no default for '" + paramName + "' on " + context + ": unknown type, using 0.0");
+ return 0.0;
}
LinkedHashMap params = SBOLData.getSimulationConfig().get(key);
if (params == null) {
- throw new IllegalArgumentException(
- "Cannot find default for parameter '" + paramName + "' on " + context +
- ": no simulation config for type '" + key + "'");
+ System.err.println("Warning: no default for '" + paramName + "' on " + context + ": no config for type '" + key + "', using 0.0");
+ return 0.0;
}
Object val = params.get(paramName);
if (val == null) {
- throw new IllegalArgumentException(
- "Missing required parameter '" + paramName + "' on " + context + ". Set this value in the Model tab.");
+ System.err.println("Warning: no default for '" + paramName + "' on " + context + ": missing from config, using 0.0");
+ return 0.0;
}
if (val instanceof Number) {
return ((Number) val).doubleValue();
}
- throw new IllegalArgumentException(
- "Invalid default value type for parameter '" + paramName + "' on " + context);
+ System.err.println("Warning: invalid default type for '" + paramName + "' on " + context + ": " + val.getClass().getSimpleName() + ", using 0.0");
+ return 0.0;
}
/**
@@ -1123,7 +1104,7 @@ private static String resolveSpeciesId(Model sbmlModel, String targetSpecies,
*
* @param id The raw ID string
* @return A valid, unique SBML SId
- * @see Converter#sanitizeAnnotationKey for XML NCName sanitization (different spec, different rules)
+ * @see Converter#sanitizeAnnotationKey for XML NCName sanitization (different rules)
*/
private String sanitizeId(String id) {
if (id == null || id.isEmpty()) {
diff --git a/SBOLCanvasBackend/src/utils/MxToSBOL.java b/SBOLCanvasBackend/src/utils/MxToSBOL.java
index a48b9b8c..7b02f91a 100644
--- a/SBOLCanvasBackend/src/utils/MxToSBOL.java
+++ b/SBOLCanvasBackend/src/utils/MxToSBOL.java
@@ -168,7 +168,11 @@ public SBOLDocument setupDocument(InputStream graphStream) throws IOException, U
.toArray(mxCell[]::new);
for(mxCell glyph: glyphs){
- createComponentDefinition(document, graph, model, glyph);
+ try {
+ createComponentDefinition(document, graph, model, glyph);
+ } catch (Exception e) {
+ System.err.println("Warning: SBOL export skipped glyph: " + e.getMessage());
+ }
}
if (layoutHelper.getGraphicalLayout(URI.create((String) circuitContainer.getValue())) != null){
@@ -176,7 +180,11 @@ public SBOLDocument setupDocument(InputStream graphStream) throws IOException, U
}
// Create Component Definition for the container itself
- createComponentDefinition(document, graph, model, circuitContainer);
+ try {
+ createComponentDefinition(document, graph, model, circuitContainer);
+ } catch (Exception e) {
+ System.err.println("Warning: SBOL export skipped container: " + e.getMessage());
+ }
}
}
@@ -190,12 +198,15 @@ public SBOLDocument setupDocument(InputStream graphStream) throws IOException, U
mxCell[] molecularSpecies = Arrays.stream(mxGraphModel.filterCells(viewChildren, molecularSpeciesFilter))
.toArray(mxCell[]::new);
- if (viewCell.getStyle().equals(STYLE_MODULE_VIEW) || circuitContainers.length > 1 || molecularSpecies.length > 0) {
- // module definitions
- createModuleDefinition(document, graph, model, viewCell);
- } else {
- // component definitions
- attachTextBoxAnnotation(model, viewCell, URI.create(viewCell.getId()));
+ try {
+ if (STYLE_MODULE_VIEW.equals(viewCell.getStyle()) || circuitContainers.length > 1 || molecularSpecies.length > 0) {
+ createModuleDefinition(document, graph, model, viewCell);
+ } else {
+ // component definitions
+ attachTextBoxAnnotation(model, viewCell, URI.create(viewCell.getId()));
+ }
+ } catch (Exception e) {
+ System.err.println("Warning: SBOL export skipped view cell: " + e.getMessage());
}
}
@@ -209,7 +220,11 @@ public SBOLDocument setupDocument(InputStream graphStream) throws IOException, U
for (mxCell cell : cells) {
if (handledContainers.contains((String) cell.getValue()))
continue;
- linkComponentDefinition(document, graph, model, cell);
+ try {
+ linkComponentDefinition(document, graph, model, cell);
+ } catch (Exception e) {
+ System.err.println("Warning: SBOL export skipped link: " + e.getMessage());
+ }
handledContainers.add((String) cell.getValue());
}
}
@@ -221,24 +236,39 @@ public SBOLDocument setupDocument(InputStream graphStream) throws IOException, U
.toArray(mxCell[]::new);
mxCell[] molecularSpecies = Arrays.stream(mxGraphModel.filterCells(viewChildren, molecularSpeciesFilter))
.toArray(mxCell[]::new);
- if (viewCell.getStyle().equals(STYLE_MODULE_VIEW) || circuitContainers.length > 1 || molecularSpecies.length > 0) {
- // module definitions
- linkModuleDefinition(document, graph, model, viewCell);
+ if (STYLE_MODULE_VIEW.equals(viewCell.getStyle()) || circuitContainers.length > 1 || molecularSpecies.length > 0) {
+ try {
+ linkModuleDefinition(document, graph, model, viewCell);
+ } catch (Exception e) {
+ System.err.println("Warning: SBOL export skipped link: " + e.getMessage());
+ }
}
}
// create the combinatorials
for (CombinatorialInfo info : combinatorialDict.values()) {
- createCombinatorial(document, graph, model, info);
+ try {
+ createCombinatorial(document, graph, model, info);
+ } catch (Exception e) {
+ System.err.println("Warning: SBOL export skipped combinatorial: " + e.getMessage());
+ }
}
// link the combinatorials
for (CombinatorialInfo info : combinatorialDict.values()) {
- linkCombinatorial(document, graph, model, info);
+ try {
+ linkCombinatorial(document, graph, model, info);
+ } catch (Exception e) {
+ System.err.println("Warning: SBOL export skipped combinatorial link: " + e.getMessage());
+ }
}
// write events as GenericTopLevel objects
- writeEvents(document, graph);
+ try {
+ writeEvents(document, graph);
+ } catch (Exception e) {
+ System.err.println("Warning: SBOL export skipped events: " + e.getMessage());
+ }
return document;
}
@@ -370,7 +400,7 @@ private void createComponentDefinition(SBOLDocument document, mxGraph graph, mxG
// store extra mxGraph information
URI identity = URI.create(glyphInfo.getFullURI());
layoutHelper.createGraphicalLayout(identity, glyphInfo.getDisplayID() + "_Layout");
- if(circuitContainer.getStyle().equals(STYLE_CIRCUIT_CONTAINER)){
+ if(STYLE_CIRCUIT_CONTAINER.equals(circuitContainer.getStyle())){
Object[] containerChildren = mxGraphModel.getChildCells(model, circuitContainer, true, false);
mxCell backboneCell = (mxCell) mxGraphModel.filterCells(containerChildren, backboneFilter)[0];
diff --git a/SBOLCanvasFrontend/src/app/graph-helpers.ts b/SBOLCanvasFrontend/src/app/graph-helpers.ts
index 306a630b..00f5349f 100644
--- a/SBOLCanvasFrontend/src/app/graph-helpers.ts
+++ b/SBOLCanvasFrontend/src/app/graph-helpers.ts
@@ -2073,7 +2073,7 @@ export class GraphHelpers extends GraphBase {
this.graph.getModel().execute(new GraphEdits.infoEdit(cell0, eventInfo, null, GraphBase.EVENT_DICT_INDEX))
}
- protected getFromEventDict(eventURI: string): EventInfo {
+ public getFromEventDict(eventURI: string): EventInfo {
const cell0 = this.graph.getModel().getCell(0)
if (!cell0.value[GraphBase.EVENT_DICT_INDEX]) {
return null
@@ -2142,7 +2142,7 @@ export class GraphHelpers extends GraphBase {
this.graph.getModel().execute(new GraphEdits.infoEdit(cell0, info, null, GraphBase.INTERACTION_DICT_INDEX))
}
- protected getFromInteractionDict(interactionURI: string): InteractionInfo {
+ public getFromInteractionDict(interactionURI: string): InteractionInfo {
const cell0 = this.graph.getModel().getCell(0)
return cell0.value[GraphBase.INTERACTION_DICT_INDEX][interactionURI]
}
diff --git a/SBOLCanvasFrontend/src/app/graph.service.ts b/SBOLCanvasFrontend/src/app/graph.service.ts
index e174097b..00c603d3 100644
--- a/SBOLCanvasFrontend/src/app/graph.service.ts
+++ b/SBOLCanvasFrontend/src/app/graph.service.ts
@@ -70,18 +70,14 @@ export class GraphService extends GraphHelpers {
},
error: err => {
console.error('[GraphService] SBOL export failed:', err)
- const message = typeof err.error === 'string' ? err.error : err.message || 'SBOL export failed'
- embeddedService.postMessage({
- error: { type: 'sbol-export', message: message }
- })
}
})
}
})
- // SBML auto-export pipeline (2000ms debounce)
+ // SBML auto-export pipeline (1000ms debounce)
modelChange$
- .pipe(debounceTime(2000))
+ .pipe(debounceTime(1000))
.subscribe(graphXml => {
if (embeddedService.isAppEmbedded()) {
console.debug('[GraphService] Model changed. Sending SBML to parent.')
@@ -91,10 +87,6 @@ export class GraphService extends GraphHelpers {
},
error: err => {
console.error('[GraphService] SBML export failed:', err)
- const message = typeof err.error === 'string' ? err.error : err.message || 'SBML export failed'
- embeddedService.postMessage({
- error: { type: 'sbml-export', message: message }
- })
}
})
}
diff --git a/SBOLCanvasFrontend/src/app/home/home.component.ts b/SBOLCanvasFrontend/src/app/home/home.component.ts
index ab089cb9..a9b6da53 100644
--- a/SBOLCanvasFrontend/src/app/home/home.component.ts
+++ b/SBOLCanvasFrontend/src/app/home/home.component.ts
@@ -29,7 +29,7 @@ export class HomeComponent implements OnInit, ComponentCanDeactivate {
leftBarOpened = true;
constructor(private graphService: GraphService, private titleService: Title, private embeddedService: EmbeddedService) {
- this.titleService.setTitle('SBOL Canvas');
+ this.titleService.setTitle('SBOLCanvas');
}
ngOnInit() {
diff --git a/SBOLCanvasFrontend/src/app/landing-page/landing-page.component.html b/SBOLCanvasFrontend/src/app/landing-page/landing-page.component.html
index e6b87845..95217c2f 100644
--- a/SBOLCanvasFrontend/src/app/landing-page/landing-page.component.html
+++ b/SBOLCanvasFrontend/src/app/landing-page/landing-page.component.html
@@ -23,10 +23,10 @@
Biologists often face the challenge of effectively communicating DNA sequences and their behaviors. An increasingly popular solution is SBOL, the Synthetic Biology Open Language. It is a diagram syntax that models genetic systems, allowing for both abstract visualizations and detailed data. Unfortunately, the complexity of creating SBOL documents is limiting this powerful language’s growth. SBOL, while characterized by graphic models, is lacking tools for graphical editing. Until now.
- SBOL Canvas is an open source web-based graphical editor that opens synthetic biology design to anyone from students to advanced researchers. Users will enjoy a simple interface for creating diagrams that are both artistic and scientific. By interfacing with existing SBOL databases, SBOL Canvas lets users share their designs and easily reference the research of others. This editor significantly lowers SBOL’s barrier to entry, helping it carry synthetic biology to new heights.
+ SBOLCanvas is an open source web-based graphical editor that opens synthetic biology design to anyone from students to advanced researchers. Users will enjoy a simple interface for creating diagrams that are both artistic and scientific. By interfacing with existing SBOL databases, SBOLCanvas lets users share their designs and easily reference the research of others. This editor significantly lowers SBOL’s barrier to entry, helping it carry synthetic biology to new heights.
- SBOL Canvas is supported in part by the SBOL Industrial Consortium.
+ SBOLCanvas is supported in part by the SBOL Industrial Consortium.
It is currently being developed by those in the Genetic Logic Lab led by Dr. Chris Myers and is part of the Synthetic Biology Data Exchange Group.