0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.uml.codegen.java.merging;
0043:
0044: import java.lang.ref.WeakReference;
0045: import java.io.IOException;
0046: import java.util.ArrayList;
0047: import java.util.Collections;
0048: import java.util.Comparator;
0049: import java.util.Iterator;
0050: import java.util.HashSet;
0051: import java.util.Hashtable;
0052: import java.util.List;
0053: import java.util.Properties;
0054: import java.util.WeakHashMap;
0055:
0056: //import org.dom4j.Attribute;
0057: import org.dom4j.Document;
0058: import org.dom4j.Element;
0059: import org.dom4j.Node;
0060:
0061: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.Attribute;
0062: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.Classifier;
0063: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IAttribute;
0064: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IClassifier;
0065: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IInterface;
0066: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.Interface;
0067: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IOperation;
0068: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.Operation;
0069: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IParameter;
0070: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.Parameter;
0071: import org.netbeans.modules.uml.core.metamodel.core.constructs.IEnumeration;
0072: import org.netbeans.modules.uml.core.metamodel.core.constructs.Enumeration;
0073: import org.netbeans.modules.uml.core.metamodel.core.constructs.IEnumerationLiteral;
0074: import org.netbeans.modules.uml.core.metamodel.core.constructs.EnumerationLiteral;
0075:
0076: import org.netbeans.modules.uml.core.coreapplication.ICoreProduct;
0077: import org.netbeans.modules.uml.core.metamodel.core.constructs.Class;
0078: import org.netbeans.modules.uml.core.metamodel.core.constructs.Enumeration;
0079: import org.netbeans.modules.uml.core.metamodel.core.constructs.IClass;
0080: import org.netbeans.modules.uml.core.metamodel.core.constructs.IEnumeration;
0081: import org.netbeans.modules.uml.core.metamodel.core.foundation.IElement;
0082: import org.netbeans.modules.uml.core.metamodel.core.foundation.INamedElement;
0083: import org.netbeans.modules.uml.core.metamodel.core.foundation.Namespace;
0084: import org.netbeans.modules.uml.core.metamodel.core.foundation.INamedElement;
0085: import org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.IUMLParserEventDispatcher;
0086: import org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.IUMLParserEventsSink;
0087: import org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.IUMLParser;
0088: import org.netbeans.modules.uml.core.reverseengineering.parsingfacilities.UMLParser;
0089: import org.netbeans.modules.uml.core.reverseengineering.reframework.IClassEvent;
0090: import org.netbeans.modules.uml.core.reverseengineering.reframework.IDependencyEvent;
0091: import org.netbeans.modules.uml.core.reverseengineering.reframework.IPackageEvent;
0092: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IErrorEvent;
0093: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IFacility;
0094: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IFacilityManager;
0095: import org.netbeans.modules.uml.core.reverseengineering.reintegration.UMLParsingIntegrator;
0096: import org.netbeans.modules.uml.core.support.umlsupport.IResultCell;
0097: import org.netbeans.modules.uml.core.support.umlsupport.ProductRetriever;
0098: import org.netbeans.modules.uml.core.support.umlsupport.XMLManip;
0099: import org.netbeans.modules.uml.core.support.umlsupport.IStrings;
0100: import org.netbeans.modules.uml.core.support.umlsupport.Strings;
0101:
0102: public class Merger implements IUMLParserEventsSink {
0103:
0104: public static final String REGENERATE_MARKER_STRING = "generated";
0105: public static final String MARKER_SIGN = "#";
0106:
0107: private Properties props;
0108: private String newFile;
0109: private String oldFile;
0110: private String targetFile;
0111: private FileBuilder fileBuilder;
0112: private ElementMatcher matcher;
0113: private ArrayList<IClassifier> classNodes;
0114: private ArrayList<Import> imports;
0115: private ArrayList<Node> packageNodes;
0116: private ParsedInfo parsedNew;
0117: private ParsedInfo parsedOld;
0118: private HashSet<IElement> matchedNew = new HashSet<IElement>();
0119: private HashSet<IElement> matchedOld = new HashSet<IElement>();
0120: private static WeakHashMap<Node, WeakReference<IElement>> cache = new WeakHashMap<Node, WeakReference<IElement>>();
0121: private IUMLParser pParser;
0122: private boolean errorHappened = false;
0123:
0124: public Merger(Properties props) {
0125: this .props = props;
0126: }
0127:
0128: public void merge(ParsedInfo parsedNew, String newFile,
0129: ParsedInfo parsedOld, String oldFile, String targetFile)
0130: throws IOException {
0131: this .newFile = newFile;
0132: this .oldFile = oldFile;
0133: this .targetFile = targetFile;
0134: this .parsedOld = parsedOld;
0135: this .parsedNew = parsedNew;
0136:
0137: fileBuilder = new FileBuilder(newFile, oldFile, targetFile);
0138:
0139: // TBD using of Java Model, ie. Info* classes.
0140: // At this moment the sequence of tranforms are
0141: // JavaSource-> [ UML XML model->UML core model ] -> JavaSource
0142: // whereis codegen adds Java specific model in between
0143: // UML core model -> Java[Info* classes] -> JavaSource
0144: // The above reverse engineering for merging in generic case
0145: // should be done into and logical merging analysis should be performed at
0146: // the level of platform specific (in this case would be Java) model
0147:
0148: // using stateless matching for now, though more
0149: // powerfull statefull matching may be an option later
0150: matcher = new ElementMatcher();
0151:
0152: Node stImportNode = null;
0153: if (parsedOld.getImports().size() > 0) {
0154: Collections.sort(parsedOld.getImports(),
0155: new Comparator<Import>() {
0156: public int compare(Import im1, Import im2) {
0157: return (int) (im1.getStartPos() - im2
0158: .getStartPos());
0159: }
0160: });
0161: stImportNode = parsedOld.getImports().get(0).getNode();
0162: }
0163:
0164: Node stClassNode = null;
0165: ArrayList<IClassifier> oldClasses = parsedOld.getClasses();
0166: if (oldClasses.size() > 0) {
0167: sortElementsByPosition(oldClasses);
0168: stClassNode = oldClasses.get(0).getNode();
0169: }
0170:
0171: if (!parsedNew.getPackageName().equals(
0172: parsedOld.getPackageName())) {
0173: mergePackages(parsedNew.getPack(), parsedOld.getPack(),
0174: stImportNode == null ? stClassNode : stImportNode);
0175: }
0176:
0177: mergeImports(parsedNew.getImports(), parsedOld.getImports(),
0178: oldClasses.get(0));
0179:
0180: //mergeTop(newClass, oldClass);
0181: merge(null, null, parsedNew.getClasses(), oldClasses);
0182:
0183: fileBuilder.completed();
0184: }
0185:
0186: public ParsedInfo parse(String fileName, String charset) {
0187: pParser = connectToParser();
0188: errorHappened = false;
0189: classNodes = new ArrayList<IClassifier>();
0190: imports = new ArrayList<Import>();
0191: packageNodes = new ArrayList<Node>();
0192: if (charset != null
0193: && java.nio.charset.Charset.isSupported(charset)
0194: && pParser instanceof UMLParser) {
0195: ((UMLParser) pParser).processStreamFromFile(fileName,
0196: charset);
0197: } else {
0198: pParser.processStreamFromFile(fileName);
0199: }
0200: if (errorHappened || classNodes.size() == 0) {
0201: return null;
0202: }
0203: return new ParsedInfo(packageNodes, imports, classNodes,
0204: fileName);
0205: //establishIDs(classNodes.get(0));
0206: }
0207:
0208: /**
0209: */
0210: private void mergePackages(Node newPack, Node oldPack, Node insPoint) {
0211: if (newPack == null) {
0212: if (oldPack != null) {
0213: fileBuilder.remove(new ElementDescriptor(oldPack));
0214: }
0215: } else {
0216: if (oldPack != null) {
0217:
0218: fileBuilder.replace(new ElementDescriptor(newPack),
0219: new ElementDescriptor(oldPack));
0220: } else {
0221: fileBuilder.insert(new ElementDescriptor(newPack),
0222: new ElementDescriptor(insPoint), false, -1);
0223: }
0224: }
0225: }
0226:
0227: /**
0228: * merge all new imports into old ones if
0229: * not present already
0230: */
0231: private void mergeImports(List<Import> newImports,
0232: List<Import> oldImports, IClassifier oldClass) {
0233:
0234: Hashtable newByName = fillHashtable(newImports, true);
0235: Hashtable oldByName = fillHashtable(oldImports, true);
0236: //Hashtable newByPosition = fillHashtable(newImports, false);
0237: Hashtable oldByPosition = fillHashtable(oldImports, false);
0238:
0239: ArrayList newNames = new ArrayList(newByName.keySet());
0240: ArrayList oldStartPositions = new ArrayList(oldByPosition
0241: .keySet());
0242:
0243: Collections.sort(newNames);
0244: Collections.sort(oldStartPositions);
0245:
0246: Iterator newIter = newNames.iterator();
0247: while (newIter.hasNext()) {
0248: String name = (String) newIter.next();
0249: if (oldByName != null && oldByName.get(name) != null) {
0250: continue;
0251: }
0252: int i = name.lastIndexOf(".");
0253: if (i > -1 && i < (name.length() - 1)) {
0254: String pack = name.substring(0, i);
0255: pack += ".*";
0256: if (oldByName != null && oldByName.get(pack) != null) {
0257: continue;
0258: }
0259: }
0260: // nor class, nor it's package ".*" is imported
0261: Iterator oldIter = oldStartPositions.iterator();
0262: boolean inserted = false;
0263: while (oldIter.hasNext()) {
0264: Import imp = (Import) oldByPosition.get(oldIter.next());
0265: if (imp != null && imp.getName().compareTo(name) < 0) {
0266: fileBuilder.insert((Import) newByName.get(name),
0267: (Import) imp, true);
0268: inserted = true;
0269: break;
0270: }
0271: }
0272: if (!inserted) {
0273: fileBuilder.insert((Import) newByName.get(name),
0274: new ElementDescriptor(oldClass.getNode()),
0275: false);
0276: }
0277: }
0278: }
0279:
0280: /**
0281: * ID Marker based match takes precedence
0282: * TBD with an element moved from one owner to another
0283: *
0284: */
0285: private void mergeTop(IClassifier newClass, IClassifier oldClass) {
0286: // match names of passed in top level nodes
0287: // if no match - undecided TBD
0288:
0289: String oldName = oldClass.getName();
0290: String newName = newClass.getName();
0291: if (ElementMatcher.isMarked(oldClass) || isOverwriteProp()
0292: || (!newName.equals(oldName))) {
0293: fileBuilder
0294: .replace(
0295: new ElementDescriptor(newClass.getNode()),
0296: new ElementDescriptor(oldClass.getNode()),
0297: ElementMatcher.isRegenBody(oldClass) ? FileBuilder.HEADER_AND_BODY
0298: : FileBuilder.HEADER_ONLY);
0299: }
0300:
0301: merge(newClass, oldClass);
0302:
0303: }
0304:
0305: /**
0306: * ID Marker based match takes precedence
0307: * TBD with an element moved from one owner to another
0308: *
0309: */
0310: private void merge(IClassifier newClass, IClassifier oldClass) {
0311:
0312: List<IEnumerationLiteral> newLits = getEnumLiterals(newClass);
0313: List<IEnumerationLiteral> oldLits = getEnumLiterals(oldClass);
0314: mergeLiterals(newClass, oldClass, newLits, oldLits);
0315: mergeLiteralSectionTerminators(newClass, oldClass);
0316:
0317: List<IAttribute> newAttrs = getAttributes(newClass);
0318: List<IAttribute> oldAttrs = getAttributes(oldClass);
0319: merge(newClass, oldClass, newAttrs, oldAttrs);
0320:
0321: List<IOperation> newOps = getOperations(newClass);
0322: List<IOperation> oldOps = getOperations(oldClass);
0323: merge(newClass, oldClass, newOps, oldOps);
0324:
0325: // and subtypes with recursion embedded
0326: List<IClassifier> newSubTypes = getSubTypes(newClass);
0327: List<IClassifier> oldSubTypes = getSubTypes(oldClass);
0328: merge(newClass, oldClass, newSubTypes, oldSubTypes);
0329:
0330: }
0331:
0332: private void merge(IClassifier newClass, IClassifier oldClass,
0333: List<? extends INamedElement> newElems,
0334: List<? extends INamedElement> oldElems) {
0335:
0336: for (ElementMatcher.MatchType mt : ElementMatcher.MatchType
0337: .values()) {
0338: for (INamedElement newElem : newElems) {
0339: if (mt == ElementMatcher.MatchType.SHORT_PARAM_TYPES
0340: && !(newElem instanceof IOperation)) {
0341: continue;
0342: }
0343: if (matchedNew.contains(newElem)) {
0344: // has been already matched using ID marker
0345: continue;
0346: }
0347: INamedElement elem = matcher.findElementMatch(newElem,
0348: oldElems, mt);
0349: if (elem != null) {
0350: if (!matchedOld.contains(elem)) {
0351: if ((ElementMatcher.isMarked(elem) || isOverwriteProp())
0352: && !ElementMatcher
0353: .isMarkedByOthers(elem)) {
0354: fileBuilder
0355: .replace(
0356: new ElementDescriptor(
0357: newElem.getNode()),
0358: new ElementDescriptor(elem
0359: .getNode()),
0360: ElementMatcher
0361: .isRegenBody(elem) ? FileBuilder.HEADER_AND_BODY
0362: : FileBuilder.HEADER_ONLY);
0363: }
0364: addToMatched(matchedNew, newElem);
0365: addToMatched(matchedOld, elem);
0366: // and recursion for nested types
0367: if (newElem instanceof IClassifier) {
0368: // TBD if not full body replacement
0369: merge((IClassifier) newElem,
0370: (IClassifier) elem);
0371: }
0372: } else {
0373: // TBD we've already matched that element
0374: // need to at least log the error
0375: }
0376: continue;
0377: }
0378: }
0379: }
0380:
0381: // adding all un-matched new elements
0382: for (INamedElement newElem : newElems) {
0383: if (matchedNew.contains(newElem)) {
0384: // has been already matched using ID marker
0385: continue;
0386: }
0387: if (oldClass != null) {
0388: fileBuilder.add(
0389: new ElementDescriptor(newElem.getNode()),
0390: new ElementDescriptor(oldClass.getNode()));
0391: } else {
0392: ArrayList<IClassifier> oldClasses = parsedOld
0393: .getClasses();
0394: sortElementsByPosition(oldClasses);
0395: fileBuilder.insert(new ElementDescriptor(newElem
0396: .getNode()), new ElementDescriptor(oldClasses
0397: .get(oldClasses.size() - 1).getNode()), true);
0398: }
0399: }
0400:
0401: // removing all un-matched regenerateable old elements
0402: for (INamedElement oldElem : oldElems) {
0403: if (matchedOld.contains(oldElem)) {
0404: // has been already matched using ID marker
0405: continue;
0406: }
0407: if ((ElementMatcher.isMarked(oldElem) || isOverwriteProp())
0408: && !ElementMatcher.isMarkedByOthers(oldElem)) {
0409: // the element is regenerateable,
0410: // ie. not having been matched means to be deleted
0411: fileBuilder.remove(new ElementDescriptor(oldElem
0412: .getNode()));
0413: }
0414: }
0415: }
0416:
0417: class Mapping {
0418:
0419: INamedElement ne;
0420: INamedElement oe;
0421: int pr = 0;
0422:
0423: Mapping(INamedElement ne, INamedElement oe) {
0424: this .ne = ne;
0425: this .oe = oe;
0426: }
0427:
0428: }
0429:
0430: /**
0431: *
0432: *
0433: */
0434: private void mergeLiterals(IClassifier newClass,
0435: IClassifier oldClass, List<IEnumerationLiteral> newElems,
0436: List<IEnumerationLiteral> oldElems) {
0437:
0438: Mapping map[] = new Mapping[newElems.size()];
0439: int i = 0;
0440: // marker ID based matching
0441: for (INamedElement newElem : newElems) {
0442: INamedElement elem = matcher.findElementMatch(newElem,
0443: oldElems, ElementMatcher.MatchType.ID_MARKER_MATCH);
0444: if (elem != null) {
0445: if (!matchedOld.contains(elem)) {
0446: map[i] = new Mapping(newElem, elem);
0447: addToMatched(matchedNew, newElem);
0448: addToMatched(matchedOld, elem);
0449: } else {
0450: // TBD we've already matched that element
0451: // need to at least log the error
0452: }
0453: }
0454: i++;
0455: }
0456:
0457: i = 0;
0458: // base matching, ie. name (signature for operations) based
0459: for (INamedElement newElem : newElems) {
0460: if (!matchedNew.contains(newElem)) {
0461: INamedElement elem = matcher.findElementMatch(newElem,
0462: oldElems, ElementMatcher.MatchType.BASE_MATCH);
0463: if (elem != null) {
0464: if (!matchedOld.contains(elem)) {
0465: map[i] = new Mapping(newElem, elem);
0466: addToMatched(matchedNew, newElem);
0467: addToMatched(matchedOld, elem);
0468: } else {
0469: // TBD we've already matched that element
0470: // need to at least log the error
0471: }
0472:
0473: }
0474: }
0475: i++;
0476: }
0477:
0478: int pnt = 0;
0479: INamedElement lastProcessed = null;
0480: for (i = 0; i < map.length; i++) {
0481: boolean processed = false;
0482: if (map[i] == null) {
0483: ;
0484: } else {
0485: Mapping m = map[i];
0486: if (lastProcessed == null
0487: || isOrdered(lastProcessed, m.oe)) {
0488: for (int j = pnt; j < i; j++) {
0489: if (map[j] != null) {
0490: if ((ElementMatcher.isMarked(map[j].oe) || isOverwriteProp())
0491: && !ElementMatcher
0492: .isMarkedByOthers(map[j].oe)) {
0493: fileBuilder
0494: .remove(new ElementDescriptor(
0495: map[j].oe.getNode()));
0496: } else {
0497: continue;
0498: }
0499: }
0500: fileBuilder.insert(new ElementDescriptor(
0501: newElems.get(j).getNode()),
0502: new ElementDescriptor(m.oe.getNode()),
0503: false, j - i);
0504: }
0505: if ((ElementMatcher.isMarked(m.oe) || isOverwriteProp())
0506: && !ElementMatcher.isMarkedByOthers(m.oe)) {
0507: fileBuilder
0508: .replace(
0509: new ElementDescriptor(m.ne
0510: .getNode()),
0511: new ElementDescriptor(m.oe
0512: .getNode()),
0513: ElementMatcher
0514: .isRegenBody(m.oe) ? FileBuilder.HEADER_AND_BODY
0515: : FileBuilder.HEADER_ONLY);
0516: }
0517: lastProcessed = m.oe;
0518: pnt = i + 1;
0519: processed = true;
0520: }
0521: }
0522: if (!processed && i == map.length - 1) {
0523: INamedElement anchor = null;
0524: if (oldElems != null && oldElems.size() > 0) {
0525: sortElementsByPosition(oldElems);
0526: anchor = oldElems.get(oldElems.size() - 1);
0527: }
0528: for (int j = pnt; j < map.length; j++) {
0529: if (map[j] != null) {
0530: if ((ElementMatcher.isMarked(map[j].oe) || isOverwriteProp())
0531: && !ElementMatcher
0532: .isMarkedByOthers(map[j].oe)) {
0533: fileBuilder.remove(new ElementDescriptor(
0534: map[j].oe.getNode()));
0535: } else {
0536: continue;
0537: }
0538: }
0539: if (anchor != null) {
0540: fileBuilder
0541: .insert(new ElementDescriptor(newElems
0542: .get(j).getNode()),
0543: new ElementDescriptor(anchor
0544: .getNode()), true, j
0545: - map.length);
0546: } else {
0547: fileBuilder.add(new ElementDescriptor(newElems
0548: .get(j).getNode()),
0549: new ElementDescriptor(oldClass
0550: .getNode()), j - map.length);
0551: }
0552: }
0553: }
0554: }
0555:
0556: // removing all un-matched regenerateable old elements
0557: for (INamedElement oldElem : oldElems) {
0558: if (matchedOld.contains(oldElem)) {
0559: // has been already matched using ID marker
0560: continue;
0561: }
0562: if ((ElementMatcher.isMarked(oldElem) || isOverwriteProp())
0563: && !ElementMatcher.isMarkedByOthers(oldElem)) {
0564: // the element is regenerateable,
0565: // ie. not having been matched means to be deleted
0566: fileBuilder.remove(new ElementDescriptor(oldElem
0567: .getNode()));
0568: }
0569: }
0570:
0571: }
0572:
0573: private void mergeLiteralSectionTerminators(IClassifier newClass,
0574: IClassifier oldClass) {
0575: if (newClass == null || oldClass == null) {
0576: return;
0577: }
0578: ElementDescriptor nd = new ElementDescriptor(newClass.getNode());
0579: ElementDescriptor od = new ElementDescriptor(oldClass.getNode());
0580:
0581: if (ElementMatcher.isMarked(oldClass)) {
0582: if ("Enumeration".equals(nd.getModelElemType())) {
0583: if (od.getPosition("Literal Section Terminator") < 0) {
0584: fileBuilder.insertLiteralSectionTerminator(nd, od);
0585: }
0586: } else {
0587: if (od.getPosition("Literal Section Terminator") > -1) {
0588: fileBuilder.removeLiteralSectionTerminator(od);
0589: }
0590: }
0591: }
0592: }
0593:
0594: private boolean addToMatched(HashSet<IElement> list, IElement elem) {
0595: if (list.contains(elem)) {
0596: // TBD we've already matched that attribute
0597: // need to at least log the error
0598: return false;
0599: } else {
0600: list.add(elem);
0601: return true;
0602: }
0603: }
0604:
0605: private void establishIDs(Node node) {
0606: establishXMIID(node, ElementMatcher.getIDMarker(node));
0607:
0608: String query = ".//UML:Attribute";
0609: List ats = XMLManip.selectNodeList(node, query);
0610: if (ats != null) {
0611: Iterator iter = ats.iterator();
0612: while (iter.hasNext()) {
0613: Node n = (Node) iter.next();
0614: establishXMIID(n, ElementMatcher.getIDMarker(n));
0615: }
0616: }
0617:
0618: query = ".//UML:Operation";
0619: List ops = XMLManip.selectNodeList(node, query);
0620: if (ops != null) {
0621: Iterator iter = ops.iterator();
0622: while (iter.hasNext()) {
0623: Node n = (Node) iter.next();
0624: establishXMIID(n, ElementMatcher.getIDMarker(n));
0625: }
0626: }
0627:
0628: query = ".//UML:Class";
0629: List cs = XMLManip.selectNodeList(node, query);
0630: if (cs != null) {
0631: Iterator iter = ops.iterator();
0632: while (iter.hasNext()) {
0633: Node n = (Node) iter.next();
0634: //establishIDs(n);
0635: }
0636: }
0637: }
0638:
0639: protected static List<IOperation> getOperations(IClassifier cl) {
0640: ArrayList<IOperation> res = new ArrayList<IOperation>();
0641: String query = "./UML:Element.ownedElement/UML:Operation";
0642: List ops = XMLManip.selectNodeList(cl.getNode(), query);
0643: if (ops != null) {
0644: Iterator iter = ops.iterator();
0645: while (iter.hasNext()) {
0646: Node n = (Node) iter.next();
0647: IOperation o = (IOperation) retrieveElement(n);
0648: if (o == null) {
0649: o = new Operation();
0650: o.setNode(n);
0651: cacheElement(o);
0652: }
0653: res.add(o);
0654: }
0655: }
0656: return res;
0657: }
0658:
0659: protected static List<IEnumerationLiteral> getEnumLiterals(
0660: IClassifier cl) {
0661: ArrayList<IEnumerationLiteral> res = new ArrayList<IEnumerationLiteral>();
0662: String query = "./UML:Enumeration.literal/UML:EnumerationLiteral";
0663: List lits = XMLManip.selectNodeList(cl.getNode(), query);
0664: if (lits != null) {
0665: Iterator iter = lits.iterator();
0666: while (iter.hasNext()) {
0667: Node n = (Node) iter.next();
0668: IEnumerationLiteral l = (IEnumerationLiteral) retrieveElement(n);
0669: if (l == null) {
0670: l = new EnumerationLiteral();
0671: l.setNode(n);
0672: cacheElement(l);
0673: }
0674: res.add(l);
0675: }
0676: }
0677: return res;
0678: }
0679:
0680: protected static List<IParameter> getParameters(IOperation op) {
0681: ArrayList<IParameter> res = new ArrayList<IParameter>();
0682: String query = "./UML:Element.ownedElement/UML:Parameter";
0683: List pars = XMLManip.selectNodeList(op.getNode(), query);
0684: if (pars != null) {
0685: Iterator iter = pars.iterator();
0686: while (iter.hasNext()) {
0687: Node n = (Node) iter.next();
0688: String direction = XMLManip.getAttributeValue(n,
0689: "direction");
0690: if (direction == null || !direction.equals("result")) {
0691: IParameter p = (IParameter) retrieveElement(n);
0692: if (p == null) {
0693: p = new Parameter();
0694: p.setNode(n);
0695: cacheElement(p);
0696: }
0697: res.add(p);
0698: }
0699: }
0700: }
0701: return res;
0702: }
0703:
0704: protected static List<IAttribute> getAttributes(IClassifier cl) {
0705: ArrayList<IAttribute> res = new ArrayList<IAttribute>();
0706: String query = "./UML:Element.ownedElement/UML:Attribute";
0707: List ats = XMLManip.selectNodeList(cl.getNode(), query);
0708: if (ats != null) {
0709: Iterator iter = ats.iterator();
0710: while (iter.hasNext()) {
0711: Node n = (Node) iter.next();
0712: IAttribute a = (IAttribute) retrieveElement(n);
0713: if (a == null) {
0714: a = new Attribute();
0715: a.setNode(n);
0716: cacheElement(a);
0717: }
0718: res.add(a);
0719: }
0720: }
0721: return res;
0722: }
0723:
0724: protected static List<IClassifier> getSubTypes(IClassifier cl) {
0725: ArrayList<IClassifier> res = new ArrayList<IClassifier>();
0726: String query = "./UML:Element.ownedElement/UML:Class";
0727: List subnodes = XMLManip.selectNodeList(cl.getNode(), query);
0728: if (subnodes != null) {
0729: Iterator iter = subnodes.iterator();
0730: while (iter.hasNext()) {
0731: Node n = (Node) iter.next();
0732: IClass s = (IClass) retrieveElement(n);
0733: if (s == null) {
0734: s = new Class();
0735: s.setNode(n);
0736: cacheElement(s);
0737: }
0738: res.add(s);
0739: }
0740: }
0741: query = "./UML:Element.ownedElement/UML:Interface";
0742: subnodes = XMLManip.selectNodeList(cl.getNode(), query);
0743: if (subnodes != null) {
0744: Iterator iter = subnodes.iterator();
0745: while (iter.hasNext()) {
0746: Node n = (Node) iter.next();
0747: IInterface s = (IInterface) retrieveElement(n);
0748: if (s == null) {
0749: s = new Interface();
0750: s.setNode(n);
0751: cacheElement(s);
0752: }
0753: res.add(s);
0754: }
0755: }
0756: query = "./UML:Element.ownedElement/UML:Enumeration";
0757: subnodes = XMLManip.selectNodeList(cl.getNode(), query);
0758: if (subnodes != null) {
0759: Iterator iter = subnodes.iterator();
0760: while (iter.hasNext()) {
0761: Node n = (Node) iter.next();
0762: IEnumeration s = (IEnumeration) retrieveElement(n);
0763: if (s == null) {
0764: s = new Enumeration();
0765: s.setNode(n);
0766: cacheElement(s);
0767: }
0768: res.add(s);
0769: }
0770: }
0771: return res;
0772: }
0773:
0774: public static boolean compareNodeLists(List l1, List l2,
0775: NodeComparator nodeCpr) {
0776: if (l1 == null) {
0777: if (l2 != null) {
0778: return false;
0779: }
0780: } else {
0781: if (l2 == null) {
0782: return false;
0783: }
0784: if (l1.size() != l2.size()) {
0785: return false;
0786: }
0787: Iterator iter1 = l1.iterator();
0788: Iterator iter2 = l2.iterator();
0789: while (iter1.hasNext()) {
0790: if (!nodeCpr.compare((Node) iter1.next(), (Node) iter2
0791: .next())) {
0792: return false;
0793: }
0794: }
0795: }
0796: return true;
0797: }
0798:
0799: public static interface NodeComparator {
0800:
0801: public boolean compare(Node n1, Node n2);
0802:
0803: }
0804:
0805: public static interface StringPreProcessor {
0806:
0807: public String preprocess(String val);
0808:
0809: }
0810:
0811: public static class BySpecificAttributeNodeComparator implements
0812: NodeComparator {
0813:
0814: String attrName;
0815: StringPreProcessor pp;
0816:
0817: public BySpecificAttributeNodeComparator(String attrName) {
0818: this .attrName = attrName;
0819: }
0820:
0821: public BySpecificAttributeNodeComparator(String attrName,
0822: StringPreProcessor pp) {
0823: this .attrName = attrName;
0824: this .pp = pp;
0825: }
0826:
0827: public boolean compare(Node n1, Node n2) {
0828: if ((n1 == null) != (n2 == null)) {
0829: return false;
0830: } else if (n1 != null) {
0831: String v1 = XMLManip.getAttributeValue(n1, attrName);
0832: String v2 = XMLManip.getAttributeValue(n2, attrName);
0833: if (pp != null) {
0834: v1 = pp.preprocess(v1);
0835: v2 = pp.preprocess(v2);
0836: }
0837: if (!compareStringValues(v1, v2)) {
0838: return false;
0839: }
0840: }
0841: return true;
0842: }
0843:
0844: }
0845:
0846: public static class PackageFilter implements StringPreProcessor {
0847:
0848: public String preprocess(String fqName) {
0849: if (fqName != null) {
0850: int li = fqName.lastIndexOf("::");
0851: if (li > -1) {
0852: if (li < fqName.length() - 2) {
0853: return fqName.substring(li + 2);
0854: } else {
0855: return "";
0856: }
0857: }
0858: return fqName;
0859: }
0860: return null;
0861: }
0862:
0863: }
0864:
0865: public static boolean compareStringValues(String s1, String s2) {
0866: if ((s1 == null) != (s2 == null)) {
0867: return false;
0868: } else if ((s1 != null) && (!s1.equals(s2))) {
0869: return false;
0870: }
0871: return true;
0872: }
0873:
0874: public static boolean compareParameters(IParameter par1,
0875: IParameter par2, boolean fq) {
0876:
0877: Node pn1 = par1.getNode();
0878: Node pn2 = par2.getNode();
0879:
0880: StringPreProcessor pp = null;
0881: if (!fq) {
0882: pp = new PackageFilter();
0883: }
0884: if (!new BySpecificAttributeNodeComparator("type", pp).compare(
0885: pn1, pn2)) {
0886: return false;
0887: }
0888:
0889: String query = "./UML:TypedElement.multiplicity/UML:Multiplicity/UML:Multiplicity.range/UML:MultiplicityRange";
0890: List mrs1 = XMLManip.selectNodeList(pn1, query);
0891: List mrs2 = XMLManip.selectNodeList(pn2, query);
0892:
0893: if (!compareNodeLists(mrs1, mrs2,
0894: new BySpecificAttributeNodeComparator("collectionType"))) {
0895: return false;
0896: }
0897:
0898: query = ".//TDerivation";
0899: mrs1 = XMLManip.selectNodeList(pn1, query);
0900: mrs2 = XMLManip.selectNodeList(pn2, query);
0901: if (!compareNodeLists(mrs1, mrs2,
0902: new BySpecificAttributeNodeComparator("name"))) {
0903: return false;
0904: }
0905:
0906: query = ".//DerivationParameter";
0907: mrs1 = XMLManip.selectNodeList(pn1, query);
0908: mrs2 = XMLManip.selectNodeList(pn2, query);
0909: if (!compareNodeLists(mrs1, mrs2,
0910: new BySpecificAttributeNodeComparator("value"))) {
0911: return false;
0912: }
0913:
0914: return true;
0915:
0916: }
0917:
0918: public boolean isOverwriteProp() {
0919: boolean overwrite = false;
0920: if (props != null) {
0921: String val = props.getProperty("addMarkers", "false"); // NOI18N
0922: if (val != null) {
0923: overwrite = Boolean.valueOf(val).booleanValue();
0924: }
0925: }
0926: return overwrite;
0927: }
0928:
0929: protected static IElement retrieveElement(Node n) {
0930: if (cache.get(n) != null) {
0931: return cache.get(n).get();
0932: }
0933: return null;
0934: }
0935:
0936: protected static void cacheElement(IElement e) {
0937: if (e != null && e.getNode() != null) {
0938: cache.put(e.getNode(), new WeakReference(e));
0939: }
0940: }
0941:
0942: private void establishXMIID(Node node, String markerIDValue) {
0943: try {
0944: String curID = XMLManip.getAttributeValue(node, "xmi.id");
0945: if (curID == null || curID.length() == 0) {
0946: String id;
0947: if (markerIDValue == null
0948: || markerIDValue.length() == 0) {
0949: id = XMLManip.retrieveDCEID();
0950: } else {
0951: id = markerIDValue;
0952: }
0953: XMLManip.setAttributeValue(node, "xmi.id", id);
0954: }
0955: } catch (Exception e) {
0956: //
0957: }
0958: }
0959:
0960: private IUMLParser connectToParser() {
0961: try {
0962: IFacilityManager pManager = null;
0963: ICoreProduct pProduct = ProductRetriever.retrieveProduct();
0964: ProductRetriever retriever;
0965: if (pProduct != null) {
0966: pManager = pProduct.getFacilityManager();
0967: if (pManager != null) {
0968: IFacility pFacility = pManager
0969: .retrieveFacility("Parsing.UMLParser");
0970: IUMLParser pParser = pFacility instanceof IUMLParser ? (IUMLParser) pFacility
0971: : null;
0972: if (pParser != null) {
0973: IUMLParserEventDispatcher m_Dispatcher = pParser
0974: .getUMLParserDispatcher();
0975: if (m_Dispatcher != null) {
0976: m_Dispatcher.revokeUMLParserSink(this );
0977: m_Dispatcher.registerForUMLParserEvents(
0978: this , " ");
0979: }
0980: return pParser;
0981: }
0982: }
0983: }
0984: } catch (Exception e) {
0985: e.printStackTrace(System.out);
0986: }
0987: return null;
0988: }
0989:
0990: // interface IUMLParserEventsSink
0991:
0992: public void onPackageFound(IPackageEvent data, IResultCell cell) {
0993: Node dataNode = null;
0994: try {
0995: dataNode = data.getEventData();
0996: if (dataNode != null) {
0997: packageNodes.add(dataNode);
0998: }
0999: } catch (Exception e) {
1000: e.printStackTrace(System.out);
1001: }
1002: }
1003:
1004: public void onDependencyFound(IDependencyEvent data,
1005: IResultCell cell) {
1006: Node dataNode = null;
1007: try {
1008: dataNode = data.getEventData();
1009: if (dataNode != null) {
1010: imports.add(new Import(dataNode));
1011: }
1012: } catch (Exception e) {
1013: e.printStackTrace(System.out);
1014: }
1015: }
1016:
1017: public void onClassFound(IClassEvent data, IResultCell cell) {
1018:
1019: Node dataNode = null;
1020:
1021: try {
1022:
1023: dataNode = data.getEventData();
1024: if (dataNode != null) {
1025:
1026: IClassifier cls = new Classifier();
1027: cls.setNode(dataNode);
1028: classNodes.add(cls);
1029: /*
1030: System.out.println("\nMerger.onClassFound \n dataNode = "+dataNode);
1031: String query = ".//TDescriptor";
1032: List nodes = XMLManip.selectNodeList(dataNode, query);
1033: for (Iterator iter = nodes.iterator(); iter.hasNext(); ) {
1034: Node curElement = (Node)iter.next();
1035: //System.out.println("\nMerger.onClassFound \n curElement = "+curElement);
1036: }
1037: */
1038: }
1039:
1040: } catch (Exception e) {
1041: e.printStackTrace(System.out);
1042: }
1043: }
1044:
1045: public void onBeginParseFile(String fileName, IResultCell cell) {
1046: }
1047:
1048: public void onEndParseFile(String fileName, IResultCell cell) {
1049:
1050: try {
1051: /*
1052: fileName = fileName.replace('\\', '_');
1053: fileName = fileName.replace('/', '_');
1054: fileName = fileName.replace(':', '_');
1055: if (classNodes.size() > 0)
1056: XMLManip.save(classNodes.get(0).getNode().getDocument(), "/tmp/out.txt."+fileName);
1057: */
1058: } catch (Exception ex) {
1059: ex.printStackTrace(System.out);
1060: }
1061:
1062: }
1063:
1064: public void onError(IErrorEvent data, IResultCell cell) {
1065: errorHappened = true;
1066: //System.out.println("\nPARSER ERROR\n");
1067: }
1068:
1069: // end of interface IUMLParserEventsSink
1070:
1071: public static class Import extends ElementDescriptor {
1072:
1073: public Import(Node n) {
1074: super (n);
1075: }
1076:
1077: public String getName() {
1078: String query = "TokenDescriptors/TDescriptor[@type=\"Name\"]";
1079: Node n = XMLManip.selectSingleNode(getNode(), query);
1080: String name = XMLManip.getAttributeValue(n, "value");
1081: return name;
1082: }
1083:
1084: }
1085:
1086: private Hashtable fillHashtable(List<Import> imports, boolean byName) {
1087: Hashtable res = new Hashtable();
1088: if (imports != null) {
1089: for (Import imp : imports) {
1090: Object key;
1091: if (byName) {
1092: key = imp.getName();
1093: } else {
1094: key = new Long(imp.getStartPos());
1095: }
1096: res.put(key, imp);
1097: }
1098: }
1099: return res;
1100: }
1101:
1102: public void sortElementsByPosition(List<? extends IElement> list) {
1103: Collections.sort(list, new Comparator<IElement>() {
1104: public int compare(IElement c1, IElement c2) {
1105: return (int) (new ElementDescriptor(c1.getNode())
1106: .getStartPos() - new ElementDescriptor(c2
1107: .getNode()).getStartPos());
1108: }
1109: });
1110: }
1111:
1112: public boolean isOrdered(IElement c1, IElement c2) {
1113: return (new ElementDescriptor(c1.getNode()).getStartPos() - new ElementDescriptor(
1114: c2.getNode()).getStartPos()) < 0;
1115: }
1116:
1117: public static class ParsedInfo {
1118: ArrayList<Node> pack;
1119: ArrayList<Import> imports;
1120: ArrayList<IClassifier> classes;
1121: String filePath = null;
1122:
1123: public ParsedInfo(ArrayList<Node> pack,
1124: ArrayList<Import> imports,
1125: ArrayList<IClassifier> classes, String filePath) {
1126: this .pack = pack;
1127: this .imports = imports;
1128: this .classes = classes;
1129: this .filePath = filePath;
1130: }
1131:
1132: public Node getPack() {
1133: if (pack != null && pack.size() > 0) {
1134: return pack.get(0);
1135: }
1136: return null;
1137: }
1138:
1139: public String getPackageName() {
1140: String res = "";
1141: Node n = getPack();
1142: if (n != null) {
1143: ElementDescriptor d = new ElementDescriptor(n);
1144: res = d.getModelElemAttribute("name");
1145: }
1146: return res;
1147: }
1148:
1149: public ArrayList<Import> getImports() {
1150: return imports;
1151:
1152: }
1153:
1154: public ArrayList<IClassifier> getClasses() {
1155: return classes;
1156: }
1157:
1158: public String getFilePath() {
1159: return filePath;
1160: }
1161:
1162: public List<String> getDefinitiveClassIds() {
1163: ArrayList<String> res = new ArrayList<String>();
1164: if (classes == null) {
1165: return res;
1166: }
1167: for (IClassifier cls : classes) {
1168: String id = null;
1169: Node n = cls.getNode();
1170: if (n != null) {
1171: id = ElementMatcher.getIDMarker(n);
1172: String vis = new ElementDescriptor(n)
1173: .getModelElemAttribute("visibility");
1174: if (vis != null && vis.equals("public")) {
1175: if (id != null) {
1176: res = new ArrayList<String>();
1177: res.add(id);
1178: return res;
1179: } else {
1180: return null;
1181: }
1182: }
1183: }
1184: if (id != null) {
1185: res.add(id);
1186: }
1187: }
1188: return res;
1189: }
1190:
1191: }
1192:
1193: }
|