blob: 509e2986aedb51dcbda73b531548b1cc3315e464 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 Intel Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Dennis Ushakov, Intel - Initial API and Implementation
* Oleg Danilov, Intel
*
*******************************************************************************/
package org.eclipse.bpel.model.util;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.eclipse.bpel.model.ExtensionActivity;
import org.eclipse.wst.wsdl.WSDLElement;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
public class ElementPlacer {
private static HashMap<String, List<String>> mapper = new HashMap<String, List<String>>();
private static final String ACTIVITY = "activity";
static {
// TODO: (DU) add other activities
// Process
String processElements[] = { BPELConstants.ND_EXTENSIONS,
BPELConstants.ND_IMPORT, BPELConstants.ND_PARTNER_LINKS,
BPELConstants.ND_MESSAGE_EXCHANGES, BPELConstants.ND_VARIABLES,
BPELConstants.ND_CORRELATION_SETS,
BPELConstants.ND_FAULT_HANDLERS,
BPELConstants.ND_EVENT_HANDLERS, ACTIVITY };
mapper.put(BPELConstants.ND_PROCESS, Arrays.asList(processElements));
// FaultHandlers
String faultHandlersElements[] = { BPELConstants.ND_CATCH,
BPELConstants.ND_CATCH_ALL };
mapper.put(BPELConstants.ND_FAULT_HANDLERS, Arrays
.asList(faultHandlersElements));
// EventHandlers
String eventHandlersElements[] = { BPELConstants.ND_ON_EVENT,
BPELConstants.ND_ON_ALARM };
mapper.put(BPELConstants.ND_EVENT_HANDLERS, Arrays
.asList(eventHandlersElements));
// Invoke
String invokeElements[] = { BPELConstants.ND_CORRELATIONS,
BPELConstants.ND_CATCH, BPELConstants.ND_CATCH_ALL,
BPELConstants.ND_COMPENSATION_HANDLER,
BPELConstants.ND_TO_PARTS, BPELConstants.ND_FROM_PARTS };
mapper.put(BPELConstants.ND_INVOKE, Arrays.asList(invokeElements));
// While
String whileElements[] = { BPELConstants.ND_CONDITION, ACTIVITY };
mapper.put(BPELConstants.ND_WHILE, Arrays.asList(whileElements));
// ForEach
String forEachElements[] = { BPELConstants.ND_START_COUNTER_VALUE,
BPELConstants.ND_FINAL_COUNTER_VALUE,
BPELConstants.ND_COMPLETION_CONDITION, ACTIVITY };
mapper.put(BPELConstants.ND_FOR_EACH, Arrays.asList(forEachElements));
// RepeatUntil
String repeatElements[] = { ACTIVITY, BPELConstants.ND_CONDITION };
mapper
.put(BPELConstants.ND_REPEAT_UNTIL, Arrays
.asList(repeatElements));
// If
String ifElements[] = { BPELConstants.ND_CONDITION, ACTIVITY,
BPELConstants.ND_ELSEIF, BPELConstants.ND_ELSE };
mapper.put(BPELConstants.ND_IF, Arrays.asList(ifElements));
// ElseIf
String elseIfElements[] = { BPELConstants.ND_CONDITION, ACTIVITY };
mapper.put(BPELConstants.ND_ELSEIF, Arrays.asList(elseIfElements));
}
public static void placeChild(WSDLElement parent, Node child) {
Element parentElement = parent.getElement();
if (parent instanceof ExtensionActivity){
parentElement = ReconciliationHelper.getExtensionActivityChildElement(parentElement);
}
List<String> nodeTypeList = mapper.get(parentElement.getLocalName());
if (nodeTypeList != null) {
String nodeName = child.getLocalName();
String nodeType = findType(nodeName, nodeTypeList);
if (nodeType != null) {
Node beforeElement = parentElement.getFirstChild();
while (beforeElement != null
&& (!isPreviousType(nodeType, findType(beforeElement
.getLocalName(), nodeTypeList), nodeTypeList) || beforeElement
.getNodeType() != Node.ELEMENT_NODE)) {
beforeElement = beforeElement.getNextSibling();
}
while (beforeElement != null
&& (isType(beforeElement.getLocalName(), nodeType) || beforeElement
.getNodeType() != Node.ELEMENT_NODE)) {
beforeElement = beforeElement.getNextSibling();
}
ElementPlacer.niceInsertBefore(parent, child, beforeElement);
return;
}
}
ElementPlacer.niceAppend(parent, child);
}
private static String findType(String nodeName, List<String> nodeTypeList) {
for (String nodeType : nodeTypeList) {
if (isType(nodeName, nodeType)) {
return nodeType;
}
}
return null;
}
private static boolean isPreviousType(String typeName1, String typeName2,
List<String> nodeTypeList) {
int type1Index = nodeTypeList.indexOf(typeName1);
int type2Index = nodeTypeList.indexOf(typeName2);
return type1Index < type2Index || (type2Index < 0 && type1Index >= 0);
}
private static boolean isType(String nodeName, String typeName) {
return ACTIVITY.equals(typeName) ? isActivity(nodeName) : typeName
.equals(nodeName);
}
private static boolean isActivity(String nodeName) {
return BPELConstants.ND_ASSIGN.equals(nodeName)
|| BPELConstants.ND_COMPENSATE.equals(nodeName)
|| BPELConstants.ND_COMPENSATE_SCOPE.equals(nodeName)
|| BPELConstants.ND_EMPTY.equals(nodeName)
|| BPELConstants.ND_EXIT.equals(nodeName)
|| BPELConstants.ND_EXTENSION_ACTIVITY.equals(nodeName)
|| BPELConstants.ND_FLOW.equals(nodeName)
|| BPELConstants.ND_FOR_EACH.equals(nodeName)
|| BPELConstants.ND_IF.equals(nodeName)
|| BPELConstants.ND_INVOKE.equals(nodeName)
|| BPELConstants.ND_PICK.equals(nodeName)
|| BPELConstants.ND_RECEIVE.equals(nodeName)
|| BPELConstants.ND_REPEAT_UNTIL.equals(nodeName)
|| BPELConstants.ND_REPLY.equals(nodeName)
|| BPELConstants.ND_RETHROW.equals(nodeName)
|| BPELConstants.ND_SCOPE.equals(nodeName)
|| BPELConstants.ND_SEQUENCE.equals(nodeName)
|| BPELConstants.ND_THROW.equals(nodeName)
|| BPELConstants.ND_VALIDATE.equals(nodeName)
|| BPELConstants.ND_WAIT.equals(nodeName)
|| BPELConstants.ND_WHILE.equals(nodeName)
|| BPELConstants.ND_OPAQUEACTIVITY.equals(nodeName);
}
public static void niceInsertBefore(WSDLElement parent, Node newChild,
Node referenceChild) {
boolean was = ReconciliationHelper.isUpdatingDom(parent);
Element parentElement = parent.getElement();
if (parent instanceof ExtensionActivity){
parentElement = ReconciliationHelper.getExtensionActivityChildElement(parentElement);
}
ReconciliationHelper.setUpdatingDom(parent, true);
Node child = (referenceChild == null) ? parentElement.getLastChild()
: referenceChild.getPreviousSibling();
// DO: parentElement has no children ( <tag /> )
if (child == null) {
StringBuffer indent = new StringBuffer();
for (Node ancestor = parentElement.getParentNode(); ancestor != null
&& ancestor.getNodeType() != Node.DOCUMENT_NODE; ancestor = ancestor
.getParentNode()) {
indent.append(" ");
}
Text text = parentElement.getOwnerDocument().createTextNode(
"\n" + indent + " ");
parentElement.insertBefore(text, referenceChild);
text = parentElement.getOwnerDocument().createTextNode(
"\n" + indent);
referenceChild = parentElement.insertBefore(text, referenceChild);
parentElement.insertBefore(newChild, referenceChild);
return;
}
while (child != null) {
short nodeType = child.getNodeType();
if (nodeType == Node.ELEMENT_NODE)
break;
if (nodeType != Node.TEXT_NODE) {
child = child.getPreviousSibling();
continue;
}
Text text = (Text) child;
String data = text.getData();
int index = data.lastIndexOf('\n');
if (index == -1) {
child = child.getPreviousSibling();
continue;
}
StringBuffer indent = new StringBuffer();
for (Node ancestor = parentElement.getParentNode(); ancestor != null
&& ancestor.getNodeType() != Node.DOCUMENT_NODE; ancestor = ancestor
.getParentNode()) {
indent.append(" ");
}
if (index + 1 < data.length() && data.charAt(index + 1) == '\r') {
index++;
}
text.replaceData(index + 1, data.length() - index - 1, indent
+ " ");
// DO:
// Format children of the newChild.
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=335458
// traverse the child's descendants also, inserting the
// proper indentation for each
StringBuffer childIndent = new StringBuffer(indent);
Node nextNewChild = newChild;
Node innerChild = newChild.getFirstChild();
while (innerChild != null) {
// add "\n" + indent before every child
Node nextInnerChild = innerChild;
while (nextInnerChild != null) {
boolean textNodeIsWhitespaceOnly = false;
if (nextInnerChild instanceof Text) {
String content = ((Text)nextInnerChild).getData();
textNodeIsWhitespaceOnly = (content==null || content.trim().isEmpty());
}
if (textNodeIsWhitespaceOnly) {
// remove an old indentation
nextNewChild.removeChild(nextInnerChild);
} else {
nextNewChild.insertBefore(nextNewChild.getOwnerDocument()
.createTextNode("\n" + childIndent + " "),
nextInnerChild);
}
nextInnerChild = nextInnerChild.getNextSibling();
}
// add "\n" after the last child
nextNewChild.appendChild(nextNewChild.getOwnerDocument()
.createTextNode("\n" + childIndent + " "));
childIndent.append(" ");
nextNewChild = innerChild;
innerChild = innerChild.getFirstChild();
}
if (referenceChild != null) {
indent.append(" ");
}
text = parentElement.getOwnerDocument().createTextNode(
"\n" + indent);
parentElement.insertBefore(text, referenceChild);
referenceChild = text;
break;
}
parentElement.insertBefore(newChild, referenceChild);
ReconciliationHelper.setUpdatingDom(parent, was);
}
public static void niceAppend(WSDLElement parent, Node child) {
niceInsertBefore(parent, child, null);
}
public static void niceRemoveChild(WSDLElement parent, Node child) {
boolean was = ReconciliationHelper.isUpdatingDom(parent);
ReconciliationHelper.setUpdatingDom(parent, true);
Element parseElement = parent.getElement();
if (parent instanceof ExtensionActivity) {
parseElement = ReconciliationHelper.getExtensionActivityChildElement(parseElement);
}
boolean done = false;
Node previous = child.getPreviousSibling();
if (previous != null && previous.getNodeType() == Node.TEXT_NODE) {
Text text = (Text) previous;
String data = text.getData();
int index = data.lastIndexOf('\n');
if (index != -1) {
if (index - 1 > 0 && data.charAt(index - 1) == '\r') {
text.deleteData(index - 1, data.length() - index + 1);
} else {
text.deleteData(index, data.length() - index);
}
done = true;
}
}
if (!done) {
for (Node next = child.getNextSibling(); next != null; next = next
.getNextSibling()) {
if (next.getNodeType() == Node.TEXT_NODE) {
Text text = (Text) next;
String data = text.getData();
int index = data.indexOf('\n');
if (index != -1) {
if (index + 1 < data.length()
&& data.charAt(index + 1) == '\r') {
text.deleteData(0, index + 2);
} else {
text.deleteData(0, index + 1);
}
break;
}
continue;
}
if (next.getNodeType() == Node.ELEMENT_NODE) {
break;
}
}
}
parseElement.removeChild(child);
ReconciliationHelper.setUpdatingDom(parent, was);
}
}