/******************************************************************************* * 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); } }