001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019: package org.netbeans.modules.xslt.mapper.model;
020:
021: import java.util.ArrayList;
022: import java.util.Collection;
023: import java.util.HashSet;
024: import java.util.List;
025: import java.util.Set;
026: import org.netbeans.modules.soa.mapper.common.IMapperEvent;
027: import org.netbeans.modules.soa.mapper.common.IMapperLink;
028: import org.netbeans.modules.soa.mapper.common.IMapperListener;
029: import org.netbeans.modules.soa.mapper.common.IMapperNode;
030: import org.netbeans.modules.soa.mapper.common.basicmapper.methoid.IFieldNode;
031: import org.netbeans.modules.soa.mapper.common.basicmapper.methoid.IMethoid;
032: import org.netbeans.modules.soa.mapper.common.basicmapper.methoid.IMethoidNode;
033: import org.netbeans.modules.soa.mapper.common.basicmapper.tree.IMapperTreeNode;
034: import org.netbeans.modules.xml.xpath.AbstractXPathModelHelper;
035: import org.netbeans.modules.xml.xpath.XPathExpression;
036: import org.netbeans.modules.xslt.mapper.methoid.Constants;
037: import org.netbeans.modules.xslt.mapper.model.nodes.Node;
038: import org.netbeans.modules.xslt.mapper.model.nodes.TreeNode;
039: import org.netbeans.modules.xslt.mapper.model.targettree.SchemaNode;
040: import org.netbeans.modules.xslt.mapper.model.targettree.StylesheetNode;
041: import org.netbeans.modules.xslt.mapper.view.NodeCreatorVisitor;
042: import org.netbeans.modules.xslt.mapper.view.SetExpressionVisitor;
043: import org.netbeans.modules.xslt.mapper.view.XsltMapper;
044: import org.netbeans.modules.xslt.model.XslComponent;
045: import org.netbeans.modules.xslt.model.XslModel;
046: import org.openide.filesystems.FileObject;
047:
048: /**
049: *
050: * @author Alexey
051: * Keeps mapper data model in sync with XSLT model:
052: * -Propogates changes made on diagram to XSLT document
053: * -reacts on changes made to XSLT model from source view by updating mapper data model
054: */
055: public class XsltModelBridge extends ModelBridge implements
056: IMapperListener {
057:
058: public XsltModelBridge(XsltMapper mapper) {
059: super (mapper);
060: super .subscribe(mapper.getContext().getXSLModel());
061: }
062:
063: /**
064: * This method gets and processes the user input events and makes
065: * modifications to the model.
066: */
067: public void eventInvoked(IMapperEvent e) {
068:
069: if (IMapperEvent.LINK_ADDED.equals(e.getEventType())
070: || IMapperEvent.LINK_DEL.equals(e.getEventType())) {
071: onGraphChanged(((IMapperLink) e.getTransferObject())
072: .getEndNode());
073: } else if (IMapperEvent.REQ_UPDATE_NODE
074: .equals(e.getEventType())) {
075: onGraphChanged((IMapperNode) e.getTransferObject());
076: } else if (IMapperEvent.REQ_NEW_NODE.equals(e.getEventType())) {
077: onMethoidAdded((IMethoidNode) e.getTransferObject());
078: }
079: }
080:
081: private void onGraphChanged(IMapperNode target) {
082: if (getMapper().getBuilder().isUpdating()) {
083: return;
084: }
085: Node node = null;
086:
087: if (target instanceof IMapperTreeNode) {
088: node = (Node) TreeNode.getNode((IMapperTreeNode) target);
089: } else if (target instanceof IFieldNode) {
090: node = (Node) ((IFieldNode) target).getGroupNode()
091: .getNodeObject();
092: } else if (target instanceof IMethoidNode) {
093: node = (Node) ((IMethoidNode) target).getNodeObject();
094: }
095:
096: if (node == null) {
097: return;
098: }
099:
100: //step 1. Walk downstream of mapper graph to find node owning the subtree was changes
101: Collection<? extends Node> nodesList = findAffectedTargetNodes(node);
102: if (nodesList == null) {
103: return;
104: }
105: //
106: // Rebuild expressions for each affected target node.
107: for (Node owner : nodesList) {
108:
109: BuildExpressionVisitor visitor_ge = new BuildExpressionVisitor(
110: getMapper().getContext());
111:
112: //check if owner node has graph connected
113: if (!owner.getPreviousNodes().isEmpty()) {
114: Node rootNode = owner.getPreviousNodes().get(0);
115: if (rootNode != null) {
116: /*
117: * If yes, accept visitor on root element of this graph.
118: * Visitor will perform recursion over the whole subtree and return
119: * expression as result
120: */
121: rootNode.accept(visitor_ge);
122: }
123: }
124:
125: XslComponent xslc = null;
126: if (owner instanceof SchemaNode
127: && visitor_ge.getResult() != null
128: && visitor_ge.getResult().getExpressionString() != null
129: && visitor_ge.getResult().getExpressionString()
130: .length() > 0) {
131: XslModel model = getMapper().getContext().getXSLModel();
132: xslc = new BranchConstructor((SchemaNode) owner,
133: getMapper()).construct();
134: } else {
135: xslc = (XslComponent) owner.getDataObject();
136: }
137:
138: //push expression string to XSL model element
139: SetExpressionVisitor visitor_ue = new SetExpressionVisitor(
140: visitor_ge.getResult());
141:
142: if (xslc != null) {
143: xslc.getModel().startTransaction();
144: try {
145: xslc.accept(visitor_ue);
146: } finally {
147: xslc.getModel().endTransaction();
148: }
149: } else {
150: assert false : "Trying to assign expression to non-xslt node";
151: }
152: }
153: }
154:
155: private void onMethoidAdded(IMethoidNode node) {
156: if (getMapper().getBuilder().isUpdating()) {
157: return;
158: }
159: IMethoid methoid = (IMethoid) node.getMethoidObject();
160: FileObject mfo = (FileObject) methoid.getData();
161:
162: String methodName = mfo.getName();
163: if (methodName == null || ("").equals(methodName.trim())) {
164: return;
165: }
166: XPathExpression expr = null;
167: if (methodName.equals(Constants.NUMBER_LITERAL)) {
168: expr = AbstractXPathModelHelper.getInstance()
169: .newXPathNumericLiteral(new Long(0));
170: } else if (methodName.equals(Constants.DURATION_LITERAL)) {
171: expr = AbstractXPathModelHelper.getInstance()
172: .newXPathStringLiteral("P0Y0M0DT0H0M0S");
173: } else if (methodName.equals(Constants.STRING_LITERAL)
174: || methodName.equals(Constants.XPATH_LITERAL)) {
175: expr = AbstractXPathModelHelper.getInstance()
176: .newXPathStringLiteral("");
177: } else {
178:
179: if (mfo.getAttribute(Constants.XPATH_FUNCTION) != null) {
180: String fname = (String) mfo
181: .getAttribute(Constants.XPATH_FUNCTION);
182: int typeID = AbstractXPathModelHelper.getInstance()
183: .getFunctionType(fname).intValue();
184: expr = AbstractXPathModelHelper.getInstance()
185: .newXPathCoreFunction(typeID);
186: } else if (mfo.getAttribute(Constants.XPATH_OPERATOR) != null) {
187: String opname = (String) mfo
188: .getAttribute(Constants.XPATH_OPERATOR);
189:
190: //Workaround for bug in XPath OM to fix IZ95683
191: if ("=".equals(opname)) {
192: opname = "==";
193: }
194: //end of woraround
195: int typeID = AbstractXPathModelHelper.getInstance()
196: .getOperatorType(opname).intValue();
197: expr = AbstractXPathModelHelper.getInstance()
198: .newXPathCoreOperation(typeID);
199: }
200: }
201: if (expr != null) {
202: NodeCreatorVisitor visitor_nc = new NodeCreatorVisitor(
203: getMapper());
204: expr.accept(visitor_nc);
205: Node data_node = visitor_nc.getResult();
206: if (node != null) {
207: data_node.setMapperNode(node);
208: node.setNodeObject(data_node);
209: }
210: }
211: }
212:
213: protected void onModelChanged() {
214: if (!checkErrors()) {
215: return;
216: }
217: super .reloadTree(getMapper().getMapperViewManager()
218: .getDestView().getTree());
219:
220: getMapper().getBuilder().updateDiagram(true);
221: }
222:
223: /* can return null */
224: private Collection<? extends Node> findAffectedTargetNodes(Node node) {
225: //
226: // Provide specific processing for the mapper tree nodes from the source tree
227: if (node instanceof TreeNode
228: && ((TreeNode) node).isSourceViewNode()) {
229: //
230: // Take the target tree root element
231: TreeNode root = (TreeNode) getMapper()
232: .getMapperViewManager().getDestView().getTree()
233: .getModel().getRoot();
234: if (root == null) {
235: return null;
236: }
237: //
238: FindAffectedTargetNodesVisitor vis = new FindAffectedTargetNodesVisitor(
239: (TreeNode) node);
240: root.accept(vis);
241: Collection<StylesheetNode> result = vis.getResultList();
242: return result;
243: } else {
244: ArrayList<Node> result = new ArrayList<Node>();
245: HashSet<Node> visited = new HashSet<Node>();
246: findOwnerNodes(node, visited, result);
247: return result;
248: }
249: }
250:
251: /**
252: * Looks for the nodes in the target tree, to which connection links can lead.
253: * Results are added to the result list.
254: */
255: private void findOwnerNodes(Node node, Set<Node> visited,
256: List<Node> result) {
257:
258: if (node == null) {
259: return;
260: }
261:
262: //mark node as visited to avoid hangups if circular links are on diagram
263: if (visited.contains(node)) {
264: return;
265: } else {
266: visited.add(node);
267: }
268: //
269: IMapperNode mn = node.getMapperNode();
270: if (mn instanceof IMapperTreeNode) {
271: if (((IMapperTreeNode) mn).isDestTreeNode()) {
272: if (!result.contains(node)) {
273: result.add(node);
274: }
275: return;
276: }
277: }
278: //
279: for (Node n : node.getNextNodes()) {
280: findOwnerNodes(n, visited, result);
281: }
282: }
283:
284: }
|