Skip to content

Commit

Permalink
added support for default namespace, refactoring, added junit test
Browse files Browse the repository at this point in the history
issue #345
  • Loading branch information
rsoika committed May 17, 2024
1 parent 48a21ae commit 4a594b1
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 56 deletions.
125 changes: 91 additions & 34 deletions open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/BPMNModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ public BPMNModel(Document doc) throws BPMNModelException {

definitions = doc.getDocumentElement();

// test if we have a default namespace without use of the 'bpmn:' prefix
// e.g: xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
String defaultNameSpace = definitions.getAttribute("xmlns");
if (defaultNameSpace != null && !defaultNameSpace.isEmpty()) {
setPrefix(BPMNNS.BPMN2, "");
setUri(BPMNNS.BPMN2, defaultNameSpace);
}

// parse the BPMN namespaces
NamedNodeMap defAttributes = definitions.getAttributes();
for (int j = 0; j < defAttributes.getLength(); j++) {
Expand Down Expand Up @@ -168,36 +176,74 @@ public BPMNModel(Document doc) throws BPMNModelException {
}
}

// find bpmndi:BPMNDiagram
NodeList diagramList = doc.getElementsByTagName(getPrefix(BPMNNS.BPMNDI) + ":BPMNDiagram");
if (diagramList != null && diagramList.getLength() > 0) {
bpmnDiagram = diagramList.item(0);
} else {
// no diagram included - so we create an empty one
getLogger().warning("No bpmndi:BPMNDiagram found - created default diagram");
// <bpmndi:BPMNDiagram id="BPMNDiagram_1" name="Default Process Diagram">
Element bpmnDiagram = createElement(BPMNNS.BPMNDI, "BPMNDiagram");
bpmnDiagram.setAttribute("id", "BPMNDiagram_1");
bpmnDiagram.setAttribute("name", "OpenBPMN Diagram");
definitions.appendChild(bpmnDiagram);
setBpmnDiagram(bpmnDiagram);
}
// Load BPMNDiagram element....
loadBpmnDiagram();

// find BPMNPlane
NodeList planeList = doc.getElementsByTagName(getPrefix(BPMNNS.BPMNDI) + ":BPMNPlane");
if (planeList != null && planeList.getLength() > 0) {
bpmnPlane = (Element) planeList.item(0);
}
// Load BPMNPlane element....
loadBpmnPlane();

// init the participant and process list
loadParticipantList();
loadProcessList();
// load global elements
loadMessageList();
loadMessageFlowList();
loadSignalList();
}
}

/**
* This method loads the first BPMNDiagram element. If
* no BPMNDiagram yet exists, then the method build one.
*
*/
private void loadBpmnDiagram() {
// find bpmndi:BPMNDiagram
NodeList diagramList = doc.getElementsByTagName(getPrefix(BPMNNS.BPMNDI) + "BPMNDiagram");
if (diagramList != null && diagramList.getLength() > 0) {
bpmnDiagram = diagramList.item(0);
} else {
// no diagram included - so we create an empty one
getLogger().warning("No bpmndi:BPMNDiagram found - created default diagram");
// <bpmndi:BPMNDiagram id="BPMNDiagram_1" name="Default Process Diagram">
Element bpmnDiagram = createElement(BPMNNS.BPMNDI, "BPMNDiagram");
bpmnDiagram.setAttribute("id", "BPMNDiagram_1");
bpmnDiagram.setAttribute("name", "OpenBPMN Diagram");
definitions.appendChild(bpmnDiagram);
setBpmnDiagram(bpmnDiagram);
}
}

/**
* This method loads the first BPMNPlane from the BPMNDiagram. If
* no BPMN Plane yet exists, then the method build one.
*
*/
private void loadBpmnPlane() {
// find the corresponding BPMNPlane
NodeList planeList = doc.getElementsByTagName(getPrefix(BPMNNS.BPMNDI) + "BPMNPlane");
if (planeList != null && planeList.getLength() > 0) {
bpmnPlane = (Element) planeList.item(0);
}
// if no plane exists yes, we create one
if (bpmnPlane == null) {
// <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="process_1">
getLogger().warning("No bpmndi:BPMNPlane found - created default plane");
bpmnPlane = createElement(BPMNNS.BPMNDI, "BPMNPlane");
bpmnPlane.setAttribute("id", "BPMNPlane_1");
NodeList nodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + "collaboration");
if (nodeList == null || nodeList.getLength() == 0) {
// Take the default process as plane ref...
nodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + "process");
}
if (nodeList != null && nodeList.getLength() > 0) {
Element refElement = (Element) nodeList.item(0);
bpmnPlane.setAttribute("bpmnElement", refElement.getAttribute("id"));
}
getBpmnDiagram().appendChild(bpmnPlane);
}
}

/**
* Returns the namespace uri for a given namespace
*
Expand Down Expand Up @@ -230,9 +276,20 @@ public String getPrefix(BPMNNS ns) {
/**
* Updates the namespace prefix for a given BPMN namespace - e.g. 'bpmn2' or
* 'bpmndi'
* The method automatically adds the prefix separator ':' if the prefix is not
* empty. This is necessary to handle default namespaces without a prefix
* correctly
*/
public void setPrefix(BPMNNS ns, String prefix) {
PREFIX_BY_NAMESPACE.put(ns, prefix);
if (prefix == null) {
prefix = "";
}
if (prefix.isEmpty()) {
PREFIX_BY_NAMESPACE.put(ns, prefix);
} else {
PREFIX_BY_NAMESPACE.put(ns, prefix + ":");
}

}

public Element getDefinitions() {
Expand Down Expand Up @@ -664,7 +721,7 @@ public void deleteParticipant(Participant participant) {
* Creates an element with a given namespace
*/
public Element createElement(BPMNNS ns, String type) {
Element element = this.getDoc().createElementNS(getUri(ns), getPrefix(ns) + ":" + type);
Element element = this.getDoc().createElementNS(getUri(ns), getPrefix(ns) + type);
return element;
}

Expand Down Expand Up @@ -747,8 +804,8 @@ public void deleteMessageFlow(String id) {
for (int j = 0; j < childs.getLength(); j++) {
Node child = childs.item(j);
if (child.getNodeType() == Node.ELEMENT_NODE
&& (child.getNodeName().equals(getPrefix(BPMNNS.BPMN2) + ":incoming")
|| child.getNodeName().equals(getPrefix(BPMNNS.BPMN2) + ":outgoing"))) {
&& (child.getNodeName().equals(getPrefix(BPMNNS.BPMN2) + "incoming")
|| child.getNodeName().equals(getPrefix(BPMNNS.BPMN2) + "outgoing"))) {
if (id.equals(child.getTextContent())) {
targetElement.getElementNode().removeChild(child);
break;
Expand All @@ -762,8 +819,8 @@ public void deleteMessageFlow(String id) {
for (int j = 0; j < childs.getLength(); j++) {
Node child = childs.item(j);
if (child.getNodeType() == Node.ELEMENT_NODE
&& (child.getNodeName().equals(getPrefix(BPMNNS.BPMN2) + ":incoming")
|| child.getNodeName().equals(getPrefix(BPMNNS.BPMN2) + ":outgoing"))) {
&& (child.getNodeName().equals(getPrefix(BPMNNS.BPMN2) + "incoming")
|| child.getNodeName().equals(getPrefix(BPMNNS.BPMN2) + "outgoing"))) {
if (id.equals(child.getTextContent())) {
sourceElement.getElementNode().removeChild(child);
break;
Expand Down Expand Up @@ -1342,7 +1399,7 @@ public Participant findParticipantByProcessId(String processId) {
public Set<Element> findChildNodesByName(Element parent, BPMNNS ns, String nodeName) {
Set<Element> result = new LinkedHashSet<Element>();
// resolve the tag name
String tagName = getPrefix(ns) + ":" + nodeName;
String tagName = getPrefix(ns) + nodeName;
if (parent != null && nodeName != null) {
NodeList childs = parent.getChildNodes();
for (int i = 0; i < childs.getLength(); i++) {
Expand Down Expand Up @@ -1650,7 +1707,7 @@ public Node findBPMNPlaneElement(String nodeName, String id) {
if (id == null || id.isEmpty() || bpmnPlane == null || nodeName == null) {
return null;
}
String fullNodeName = getPrefix(BPMNNS.BPMNDI) + ":" + nodeName;
String fullNodeName = getPrefix(BPMNNS.BPMNDI) + nodeName;
NodeList childList = bpmnPlane.getChildNodes();
for (int i = 0; i < childList.getLength(); i++) {
Node child = childList.item(i);
Expand Down Expand Up @@ -1710,14 +1767,14 @@ public static void debug(String message) {
private void loadParticipantList() throws BPMNModelException {
participants = new LinkedHashSet<Participant>();
List<Element> invalidParticipantElementList = new ArrayList<Element>();
NodeList collaborationNodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + ":collaboration");
NodeList collaborationNodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + "collaboration");
if (collaborationNodeList != null && collaborationNodeList.getLength() > 0) {

// we only take the first collaboration element (this is what is expected)
collaborationElement = (Element) collaborationNodeList.item(0);
// now find all participants...
NodeList participantList = collaborationElement
.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + ":participant");
.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + "participant");
logger.fine("..found " + participantList.getLength() + " participants");
for (int i = 0; i < participantList.getLength(); i++) {
Element item = (Element) participantList.item(i);
Expand Down Expand Up @@ -1761,7 +1818,7 @@ private void loadProcessList() throws BPMNModelException {
int publicCount = 0;

// find process
NodeList processList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + ":process");
NodeList processList = definitions.getElementsByTagNameNS(getUri(BPMNNS.BPMN2), "process");
if (processList != null && processList.getLength() > 0) {
for (int i = 0; i < processList.getLength(); i++) {
Element item = (Element) processList.item(i);
Expand Down Expand Up @@ -1851,13 +1908,13 @@ private void loadProcessList() throws BPMNModelException {
*/
private void loadMessageFlowList() throws BPMNModelException {
messageFlows = new LinkedHashSet<MessageFlow>();
NodeList collaborationNodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + ":collaboration");
NodeList collaborationNodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + "collaboration");
if (collaborationNodeList != null && collaborationNodeList.getLength() > 0) {
// we only take the first collaboration element (this is what is expected)
collaborationElement = (Element) collaborationNodeList.item(0);
// now find all messageFlows...
NodeList messageFlowList = collaborationElement
.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + ":" + BPMNTypes.MESSAGE_FLOW);
.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + BPMNTypes.MESSAGE_FLOW);
logger.fine("..found " + messageFlowList.getLength() + " messageFlows");
for (int i = 0; i < messageFlowList.getLength(); i++) {
Element item = (Element) messageFlowList.item(i);
Expand All @@ -1878,7 +1935,7 @@ private void loadMessageFlowList() throws BPMNModelException {
private void loadSignalList() throws BPMNModelException {
signals = new LinkedHashSet<Signal>();
List<String> duplicates = new ArrayList<>();
NodeList signalNodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + ":" + BPMNTypes.SIGNAL);
NodeList signalNodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + BPMNTypes.SIGNAL);
if (signalNodeList != null && signalNodeList.getLength() > 0) {
for (int i = 0; i < signalNodeList.getLength(); i++) {
Element item = (Element) signalNodeList.item(i);
Expand All @@ -1902,7 +1959,7 @@ private void loadSignalList() throws BPMNModelException {
*/
private void loadMessageList() throws BPMNModelException {
messages = new LinkedHashSet<Message>();
NodeList messageNodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + ":" + BPMNTypes.MESSAGE);
NodeList messageNodeList = definitions.getElementsByTagName(getPrefix(BPMNNS.BPMN2) + BPMNTypes.MESSAGE);
if (messageNodeList != null && messageNodeList.getLength() > 0) {
for (int i = 0; i < messageNodeList.getLength(); i++) {
Element item = (Element) messageNodeList.item(i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -930,8 +930,8 @@ private void removeElementEdge(String id) {
for (int j = 0; j < childs.getLength(); j++) {
Node child = childs.item(j);
if (child.getNodeType() == Node.ELEMENT_NODE
&& (child.getNodeName().equals(getModel().getPrefix(BPMNNS.BPMN2) + ":incoming")
|| child.getNodeName().equals(getModel().getPrefix(BPMNNS.BPMN2) + ":outgoing"))) {
&& (child.getNodeName().equals(getModel().getPrefix(BPMNNS.BPMN2) + "incoming")
|| child.getNodeName().equals(getModel().getPrefix(BPMNNS.BPMN2) + "outgoing"))) {
if (id.equals(child.getTextContent())) {
targetElement.getElementNode().removeChild(child);
break;
Expand All @@ -946,8 +946,8 @@ private void removeElementEdge(String id) {
for (int j = 0; j < childs.getLength(); j++) {
Node child = childs.item(j);
if (child.getNodeType() == Node.ELEMENT_NODE
&& (child.getNodeName().equals(getModel().getPrefix(BPMNNS.BPMN2) + ":incoming")
|| child.getNodeName().equals(getModel().getPrefix(BPMNNS.BPMN2) + ":outgoing"))) {
&& (child.getNodeName().equals(getModel().getPrefix(BPMNNS.BPMN2) + "incoming")
|| child.getNodeName().equals(getModel().getPrefix(BPMNNS.BPMN2) + "outgoing"))) {
if (id.equals(child.getTextContent())) {
sourceElement.getElementNode().removeChild(child);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public BPMNBounds(Node _bpmndiElement, BPMNModel model) throws BPMNMissingElemen
NodeList childList = bpmndiElement.getChildNodes();
for (int i = 0; i < childList.getLength(); i++) {
Node child = childList.item(i);
if ((model.getPrefix(BPMNNS.DC) + ":Bounds").equals(child.getNodeName()) && child.hasAttributes()) {
if ((model.getPrefix(BPMNNS.DC) + "Bounds").equals(child.getNodeName()) && child.hasAttributes()) {
elementNode = (Element) child;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ public void clearWayPoints() {
// find all di:waypoint
for (int i = 0; i < childList.getLength(); i++) {
Node child = childList.item(i);
if ((model.getPrefix(BPMNNS.DI) + ":waypoint").equals(child.getNodeName()) && child.hasAttributes()) {
if ((model.getPrefix(BPMNNS.DI) + "waypoint").equals(child.getNodeName()) && child.hasAttributes()) {
// collect node....
deletionList.add(child);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ public void updateSequenceFlowReferences() {
}
// remove incoming childs...
NodeList incomingSequenceFlows = getElementNode()
.getElementsByTagName(bpmnProcess.getModel().getPrefix(BPMNNS.BPMN2) + ":incoming");
.getElementsByTagName(bpmnProcess.getModel().getPrefix(BPMNNS.BPMN2) + "incoming");
for (int i = 0; i < incomingSequenceFlows.getLength(); i++) {
Element item = (Element) incomingSequenceFlows.item(i);
// test if the sequence flow exists...
Expand All @@ -332,7 +332,7 @@ public void updateSequenceFlowReferences() {
}
// remove outgoing childs...
NodeList outgoingSequenceFlows = getElementNode()
.getElementsByTagName(bpmnProcess.getModel().getPrefix(BPMNNS.BPMN2) + ":outgoing");
.getElementsByTagName(bpmnProcess.getModel().getPrefix(BPMNNS.BPMN2) + "outgoing");
for (int i = 0; i < outgoingSequenceFlows.getLength(); i++) {
Element item = (Element) outgoingSequenceFlows.item(i);
// test if the sequence flow exists...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public BPMNLabel(BPMNModel model, Node _bpmnShape) throws BPMNMissingElementExce
NodeList childList = bpmnShape.getChildNodes();
for (int i = 0; i < childList.getLength(); i++) {
Node child = childList.item(i);
if ((model.getPrefix(BPMNNS.BPMNDI) + ":BPMNLabel").equals(child.getNodeName())) {
if ((model.getPrefix(BPMNNS.BPMNDI) + "BPMNLabel").equals(child.getNodeName())) {
label = (Element) child;
// find the dc:Bounds element of the label...

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,19 +165,10 @@ public static BPMNModel read(InputStream is, Path path) throws BPMNModelExceptio

// explicit remove whitespace
removeWhitespaceNodes(root);
BPMNModel model = new BPMNModel(doc);
setOpenBPMNNameSpace(model.getDefinitions());

if (!"bpmn2:definitions".equals(root.getNodeName())
&&
!"bpmn:definitions".equals(root.getNodeName())) {
logger.severe("Invalid BPMN File: Missing root element 'bpmn2:definitions'!");
return null;
} else {
BPMNModel model = new BPMNModel(doc);
setOpenBPMNNameSpace(model.getDefinitions());

return model;
}

return model;
} catch (ParserConfigurationException | SAXException | IOException e) {
logger.severe(e.getMessage());
// create a runtimeException to show a error message in the client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,28 @@ public void testReadEmptyModelWithCustomNamespace() throws BPMNModelException {
// next validate the BPMN Default Namespaces
assertEquals("http://www.omg.org/spec/BPMN/20100524/MODEL", model.getUri(BPMNNS.BPMN2));

logger.info("...model read sucessful");
logger.info("...model read successful");

}

/**
* This Test verifies if a BPMN model with custom namespace URIs can be read if
* no bpmn2: exists
*
* @throws BPMNModelException
*
*/
@Test
public void testReadModelWithoutBPMN2Prefix() throws BPMNModelException {

logger.info("...read model");

BPMNModel model = BPMNModelFactory.read("/process_1_custom_namespace-nopaefix.bpmn");
System.out.println("Root Element :" + model.getDoc().getDocumentElement().getNodeName());
// next validate the default namespace mapped to bpmn2
assertEquals("http://www.omg.org/spec/BPMN/20100524/MODEL", model.getUri(BPMNNS.BPMN2));

logger.info("...model read successful");

}

Expand Down
Loading

0 comments on commit 4a594b1

Please sign in to comment.