001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.uml.integration.ide.events;
043:
044: import java.lang.reflect.Modifier;
045: import java.util.ArrayList;
046: import java.util.HashSet;
047: import java.util.HashMap;
048:
049: import org.netbeans.modules.uml.common.Util;
050: import org.netbeans.modules.uml.core.metamodel.infrastructure.IDerivationClassifier;
051: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.Classifier;
052: import org.netbeans.modules.uml.core.support.umlsupport.StringUtilities;
053:
054: import org.netbeans.modules.uml.integration.ide.ChangeUtils;
055: import org.netbeans.modules.uml.integration.ide.JavaClassUtils;
056: import org.netbeans.modules.uml.core.metamodel.core.foundation.IDependency;
057: import org.netbeans.modules.uml.core.metamodel.core.foundation.IElement;
058: import org.netbeans.modules.uml.core.metamodel.core.foundation.INamedElement;
059: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IAttribute;
060: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IClassifier;
061: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IOperation;
062: import org.netbeans.modules.uml.core.metamodel.infrastructure.coreinfrastructure.IParameter;
063: import org.netbeans.modules.uml.core.metamodel.structure.IProject;
064: import org.netbeans.modules.uml.core.support.umlsupport.Log;
065: import org.netbeans.modules.uml.core.support.umlutils.ETList;
066: import org.netbeans.modules.uml.integration.ide.UMLSupport;
067:
068: /**
069: * The MethodInfo communicates with the EventManager to update Describe.
070: * MethodInfo is still a high level class. It knows how to communicate
071: * with the EventMangaer to update Describe, but it does not know any of the
072: * details of how to update Describe.
073: * <br>
074: * Because MethodInfo contains both before and after data, MethodInfo
075: * is able to search for the metohd and update it to how the source file current
076: * represents the method.
077: *
078: * Revision History
079: * No. Date Who What
080: * --- ---- --- ----
081: * 1 2002-04-25 Darshan Reformatted to 4-space indent and added
082: * constructor to create MethodInfo from an
083: * IOperation
084: * 2 2002-04-26 Darshan Fixed dropped modifiers, corrected handling
085: * of return types and parameters when
086: * constructing a MethodInfo off an IOperation.
087: * 3 2002-04-26 Darshan Fixed NullPointerException when retrieving
088: * return type for constructors.
089: * 4 2002-04-30 Darshan Used JavaClassUtils to map Describe's modifiers
090: * to Java modifiers.
091: * 5 2002-05-02 Darshan Refixed using JavaClassUtils to map modifiers
092: * - the wrong modifier was still being used.
093: * 6 2002-05-03 Darshan Kludged method parameter type retrieval to
094: * default to int if no parameter type is found.
095: * This prevents faulty events from producing
096: * an unparseable Java file.
097: * 7 2002-05-06 Darshan Changed the MethodInfo(ClassInfo, IOperation)
098: * constructor to call ElementInfo(INamedElement)
099: * for model-source work.
100: * 8 2002-05-15 Darshan Added toString() method.
101: * 9 2002-05-22 Darshan Added code to handle method concurrency.
102: * 10 2002-06-04 Darshan Fixed bug with not picking up method parameters
103: * correctly (issue #19).
104: * 11 2002-06-14 Darshan Fixed bug with code assuming that the parent
105: * for an IOperation must be an IClass, instead of
106: * an IClassifier.
107: * 12 2002-06-19 Darshan Added code to prevent interface methods being
108: * explicitly flagged abstract.
109: *
110: * @see EventManager
111: * @see ConstructorInfo
112: */
113: public class MethodInfo extends ConstructorInfo {
114: // Describe synchronization (concurrency) constants
115: public static final int CCK_SEQUENTIAL = 0;
116: public static final int CCK_GUARDED = 1;
117: public static final int CCK_CONCURRENT = 2;
118:
119: String mReturn = null;
120:
121: private int lineNo = 0;
122:
123: /**
124: * The operation which this MethodInfo wraps. Will be null for source-model
125: * operations, non-null for model-source operations.
126: */
127: private IOperation operation;
128:
129: /**
130: * If this operation is an accessor or mutator, the attribute in question.
131: */
132: private MemberInfo attribute;
133:
134: /**
135: * This is used to identify the attribute for which this is a getter or setter.
136: * If this method is not getter or setter, this varibale will be null.
137: */
138: private String attributeName = null;
139:
140: private MethodParameterInfo returnParameter = null;
141:
142: /**
143: * This is used to identify if this method is a getter or setter.
144: * True indicates a getter
145: * False indicates a setter.
146: */
147: private boolean accessor = false;
148: private boolean mutator = false;
149:
150: /**
151: * @return Returns the lineNo.
152: */
153: public int getLineNo() {
154: return lineNo;
155: }
156:
157: /**
158: * @param lineNo The lineNo to set.
159: */
160: public void setLineNo(int lineNo) {
161: this .lineNo = lineNo;
162: }
163:
164: /**
165: * Initializes a new MethodInfo.
166: * @param container The class that contains the data member.
167: * @param type The transaction type.
168: * @see ElementInfo
169: */
170: public MethodInfo(ClassInfo container, int type) {
171: super (container, type);
172: }
173:
174: public MethodInfo(ClassInfo container, IOperation op) {
175: super (container, op);
176: setOtherMethodInfo(container, op);
177: }
178:
179: /* (non-Javadoc)
180: * @see com.embarcadero.integration.events.ElementInfo#getOwningProject()
181: */
182: public IProject getOwningProject() {
183: return operation != null ? (IProject) operation.getProject()
184: : getContainingClass() != null ? getContainingClass()
185: .getOwningProject() : null;
186: }
187:
188: protected void setOtherMethodInfo(ClassInfo container, IOperation op) {
189: operation = op;
190:
191: if (container == null) {
192: IElement owner = op.getOwner();
193: if (owner != null && owner instanceof IClassifier) {
194: IClassifier cpowner = (IClassifier) owner;
195: //container = new ClassInfo(cpowner);
196: container = ClassInfo.getRefClassInfo(cpowner, true);
197:
198: setContainingClass(container);
199: }
200: }
201:
202: setName(op.getName());
203:
204: boolean parentIsInterface = getContainingClass() != null
205: && getContainingClass().isInterface();
206:
207: int mods = JavaClassUtils.getJavaModifier(op.getVisibility());
208: if (op.getIsFinal())
209: mods |= Modifier.FINAL;
210: if (op.getIsStatic())
211: mods |= Modifier.STATIC;
212: if (op.getIsAbstract() && !parentIsInterface)
213: mods |= Modifier.ABSTRACT;
214: if (op.getIsNative())
215: mods |= Modifier.NATIVE;
216: if (op.getConcurrency() == CCK_GUARDED)
217: mods |= Modifier.SYNCHRONIZED;
218: if (op.getIsStrictFP())
219: mods |= Modifier.STRICT;
220:
221: // we don't want to call setModifiers(new Integer(mods)) directly;
222: mModifiers = new Integer(mods);
223: accessor = mutator = false;
224:
225: String getStr = checkIfGetter(op);
226: if (getStr != null) {
227: attributeName = getStr;
228: accessor = true;
229: }
230:
231: String setStr = checkIfSetter(op);
232: if (setStr != null) {
233: attributeName = setStr;
234: mutator = true;
235: accessor = false;
236: }
237:
238: IParameter ret = op.getReturnType();
239:
240: // conover - replacing String type with MethodParameterInfo type
241: // if (op.getIsConstructor() || ret == null )
242: // {
243: // setReturnType(null);
244: // }
245: //
246: // else
247: // {
248: // setReturnType(MethodParameterInfo.getType(ret, accessor));
249: // }
250: // conover - using MethodParameterInfo instead of String allows for more robust
251: // code generation, like for Collection Override
252:
253: if (!op.getIsConstructor() && ret != null)
254: setReturnParameter(new MethodParameterInfo(this , ret, false));
255:
256: setParameters(mutator ? getMutatorParameter(attribute, op)
257: : getParameterInfo(op));
258:
259: // add exceptions info
260: ETList<IClassifier> exceptions = op.getRaisedExceptions();
261:
262: if (exceptions != null) {
263: String[] raisedExceptions = new String[exceptions
264: .getCount()];
265:
266: for (int i = 0; i < exceptions.getCount(); i++) {
267: raisedExceptions[i] = JavaClassUtils
268: .replaceDollarSign(JavaClassUtils
269: .getFullyQualifiedName(exceptions
270: .item(i)));
271: }
272:
273: setExceptions(raisedExceptions);
274: }
275: }
276:
277: /**
278: * Set the access modifiers for this method. Interface methods will be
279: * forced abstract, regardless of the actual modifiers set (unless null).
280: *
281: * @param mods An <code>Integer</code> of the modifiers as defined in
282: * <code>java.lang.ref.Modifier</code>. If <code>null</code>,
283: * the modifiers will not be updated to the model.
284: */
285: public void setModifiers(Integer mods) {
286: ClassInfo owner = getContainingClass();
287: if (owner != null && owner.isInterface() && mods != null
288: && (mods.intValue() & Modifier.ABSTRACT) == 0)
289: mods = new Integer(mods.intValue() | Modifier.ABSTRACT);
290: super .setModifiers(mods);
291: }
292:
293: public MemberInfo getAttribute() {
294: return attribute;
295: }
296:
297: public boolean isCollectionType() {
298: return attribute != null && attribute.isUseCollectionOverride();
299: }
300:
301: public String getFilename() {
302: return (getContainingClass() != null ? getContainingClass()
303: .getFilename() : null);
304: }
305:
306: public IProject getProject() {
307: return operation != null ? (IProject) operation.getProject()
308: : null;
309: }
310:
311: private MethodParameterInfo[] getMutatorParameter(MemberInfo minfo,
312: IOperation op) {
313: if (attribute == null) {
314: Log.impossible("getMutatorParameter(): null attribute?"); // NOI18N
315: return null;
316: }
317:
318: MethodParameterInfo[] params = getParameterInfo(op);
319: if (params != null && params.length == 1) {
320: // Note that we have to be careful here - if this MethodInfo
321: // represents the *old* state of a method, we shouldn't set the
322: // parameter type to the *current* type of the associated attribute.
323: if (minfo.getCollectionOverrideDataType() != null
324: && MethodParameterInfo.isArray(params[0].getType())
325: && (params[0].getType().equals(minfo.getType()) || params[0]
326: .getType().equals(minfo.getQualifiedType()))) {
327: Log.out("Changing parameter type from " // NOI18N
328: + params[0].getType() + " to " // NOI18N
329: + minfo.getCollectionOverrideDataType());
330:
331: params[0]
332: .setType(minfo.getCollectionOverrideDataType());
333: }
334: }
335: return params;
336: }
337:
338: /**
339: * Returns an array of MethodParameterInfos describing the parameters of
340: * the given operation.
341: * If the operation has no parameters, an empty array will be returned.
342: * @param op A valid (non-null) operation
343: * @return
344: */
345: private MethodParameterInfo[] getParameterInfo(IOperation op) {
346: ETList<IParameter> pars = op.getFormalParameters();
347:
348: if (pars == null || pars.getCount() < 1)
349: return new MethodParameterInfo[0];
350:
351: MethodParameterInfo[] params = new MethodParameterInfo[pars
352: .getCount()];
353:
354: for (int i = 0; i < pars.getCount(); ++i) {
355: IParameter param = pars.item(i);
356:
357: MethodParameterInfo mpi = new MethodParameterInfo(this ,
358: param, false);
359:
360: params[i] = mpi;
361: }
362:
363: return params;
364: }
365:
366: private String checkIfGetter(IOperation op) {
367: ETList<IDependency> clDeps = op.getClientDependencies();
368: if (clDeps != null) {
369: for (int i = 0; i < clDeps.getCount(); i++) {
370: IDependency dep = clDeps.item(i);
371: INamedElement ne = dep.getSupplier();
372: if (ne instanceof IAttribute) {
373: attribute = new MemberInfo((IAttribute) ne);
374: return ne.getName();
375: }
376: }
377: }
378: return null;
379: }
380:
381: private String checkIfSetter(IOperation op) {
382: ETList<IDependency> suDeps = op.getSupplierDependencies();
383: if (suDeps != null) {
384: for (int j = 0; j < suDeps.getCount(); j++) {
385: IDependency dep = suDeps.item(j);
386: INamedElement ne = dep.getClient();
387: if (ne instanceof IAttribute) {
388: attribute = new MemberInfo((IAttribute) ne);
389: return ne.getName();
390: }
391: }
392: }
393: return null;
394: }
395:
396: /**
397: * Set the return type of the method.
398: * @param value The return type.
399: */
400: public void setReturnType(String value) {
401: mReturn = value;
402: }
403:
404: /**
405: * Gets the return type of the method.
406: * @return The return type.
407: */
408: public String getCodeGenReturnType() {
409: // if no return param, probably a Constructor; return empty string
410: if (getReturnParameter() == null)
411: return ""; // NOI18N
412:
413: MethodParameterInfo param = getReturnParameter();
414: IParameter element = param.getParameterElement();
415: String[] shortNames = GenCodeUtil
416: .getCollectionOverrideDataTypes(element
417: .getMultiplicity(), false);
418: return GenCodeUtil
419: .getCodeGenType(element.getType(), shortNames, param
420: .isUseGenerics(), element.getMultiplicity(),
421: false, getContainingClass());
422: }
423:
424: /**
425: * Returns <code>true</code> if this is an accessor.
426: */
427: public boolean isAccessor() {
428: return accessor;
429: }
430:
431: /**
432: * Returns <code>true</code> if this is a mutator.
433: */
434: public boolean isMutator() {
435: return mutator;
436: }
437:
438: /**
439: * Gets the member name for which this is an accessor.
440: */
441: public String getMemberName() {
442: return attributeName;
443: }
444:
445: /**
446: * Updates the method. A Class Transaction is began and
447: * {@link #update(GDSymbolTransaction trans) update}
448: * is called.
449: */
450: public void update() {
451: super .update();
452: }
453:
454: /**
455: * Updates the method using the specified Symbol transaction.
456: * @param trans The transaction that is to be used to update the correct symbol.
457: * @return The method transaction that was created to update the data member.
458: */
459: public MethodTransaction update(SymbolTransaction symTrans) {
460: MethodTransaction retVal = super .update(symTrans);
461: if ((retVal != null) && (getChangeType() != ElementInfo.DELETE)) {
462: IOperation oper = retVal.getOperation();
463: boolean cons;
464: if (oper != null
465: && (cons = oper.getName().equals(
466: symTrans.getSymbol().getName())) != oper
467: .getIsConstructor())
468: oper.setIsConstructor(cons);
469:
470: /*
471: if(getReturnType() != null)
472: {
473: EventManager manager = EventManager.getEventManager();
474: try
475: {
476: IOperation oper = retVal.getOperation();
477: if((oper != null) && !oper.getName().equals(symTrans.getSymbol().getName())) {
478: oper.setReturnType2(getReturnType());
479: } else {
480: if(oper != null) {
481: oper.setIsConstructor(true);
482: }
483: }
484: }
485: catch(Exception E)
486: {
487: String msg = "Error occured while updating a Describe "
488: + "method attribute.<br>";
489: msg += " to the value: " + getReturnType();
490: ExceptionDialog.showExceptionError(msg, E);
491: }
492: }
493:
494: */
495: }
496: return retVal;
497: }
498:
499: /**
500: * Returns whether the parameter list of this method needs to be
501: * updated to the Describe model.
502: *
503: * @return <code>true</code> if the model needs to be updated.
504: */
505: protected boolean needParameterUpdate() {
506: return true;
507: }
508:
509: protected ETList<IParameter> getParameterCollection(IOperation op) {
510: ETList<IParameter> pars = super .getParameterCollection(op);
511:
512: if (getCodeGenReturnType() != null) {
513: IParameter ret = op.createReturnType();
514:
515: String type = getCodeGenReturnType();
516: int mul = MemberInfo.getMultiplicity(type);
517: type = MemberInfo.getTypeName(type);
518:
519: ret.setType2(JavaClassUtils.convertJavaToUML(type));
520: MemberInfo.setMultiplicity(ret, mul, 0);
521: pars.add(ret);
522: }
523:
524: return pars;
525: }
526:
527: protected void updateParameters(MethodTransaction trans) {
528: if (getNewParameters() == null) {
529: if (getCodeGenReturnType() != null) {
530: EventManager.getEventManager().getEventFilter()
531: .blockEventType(
532: ChangeUtils.RDT_DEPENDENCY_ADDED);
533: try {
534: IOperation op = trans.getOperation();
535: Log.out("updateParameters: Operation is " + op);
536: Log
537: .out("updateParameters: Operation return type is "
538: + op.getReturnType2()
539: + "("
540: + op.getReturnType() + ")");
541: // if (op.getCodeGenReturnType() == null
542: // || !JavaClassUtils.convertJavaToUML(getCodeGenReturnType()).equals(
543: // op.getCodeGenReturnType().getTypeName())) {
544: String type = getCodeGenReturnType();
545: int mul = MemberInfo.getMultiplicity(type);
546: type = MemberInfo.getTypeName(type);
547:
548: IDerivationClassifier derivation = getDerivationClassifer(
549: op, type);
550: if (derivation != null) {
551: IParameter param = op.getReturnType();
552: if (param == null) {
553: param = op.createParameter2(derivation, "");
554: }
555: op.setReturnType(param);
556: } else {
557: op.setReturnType2(JavaClassUtils
558: .convertJavaToUML(type));
559: }
560:
561: IParameter retp = op.getReturnType();
562: MemberInfo.setMultiplicity(retp, mul, MemberInfo
563: .getMultiplicity(retp));
564: } finally {
565: EventManager.getEventManager().getEventFilter()
566: .unblockEventType(
567: ChangeUtils.RDT_DEPENDENCY_ADDED);
568: }
569: // }
570: }
571: } else
572: super .updateParameters(trans);
573: }
574:
575: public String getCode() {
576: return "M";
577: }
578:
579: protected String getDisplayString(String fnName,
580: MethodParameterInfo[] mpi) {
581: String s = super .getDisplayString(fnName, mpi);
582: String type = getCodeGenReturnType();
583:
584: if (type != null)
585: s += ": " + type;
586:
587: return s;
588: }
589:
590: public MethodParameterInfo getReturnParameter() {
591: return returnParameter;
592: }
593:
594: public void setReturnParameter(MethodParameterInfo val) {
595: returnParameter = val;
596: }
597:
598: public IOperation getOperation() {
599: return operation;
600: }
601:
602: public void setOperation(IOperation operation) {
603: this .operation = operation;
604: }
605:
606: //
607: // added for template codegen
608: //
609:
610: public Integer getModifiers() {
611: Integer mods = super .getModifiers();
612: if (getOperation() != null && getOperation().getIsConstructor()
613: && getContainingClass().isEnumeration()) {
614: int m = mods.intValue();
615: m &= (~(Modifier.PUBLIC | Modifier.PROTECTED));
616: mods = new Integer(m);
617: }
618: return mods;
619: }
620:
621: public boolean isAbstract() {
622: return (Modifier.isAbstract(getModifiers()) || (getContainingClass() != null && getContainingClass()
623: .isInterface()));
624: }
625:
626: public boolean isNative() {
627: return Modifier.isNative(getModifiers());
628: }
629:
630: public ArrayList<MethodParameterInfo> getParameterInfos() {
631: ArrayList<MethodParameterInfo> res = new ArrayList<MethodParameterInfo>();
632: MethodParameterInfo[] parms = getParameterInfo(getOperation());
633: if (parms == null && parms.length == 0) {
634: return null;
635: }
636: for (int i = 0; i < parms.length; i++) {
637: if (parms[i] != null) {
638: res.add(parms[i]);
639: }
640: }
641: return res;
642: }
643:
644: // see getCodeGenType() for how the type string is formed
645: public ArrayList<String[]> getReferredCodeGenTypes() {
646:
647: ArrayList<String[]> res = new ArrayList<String[]>();
648: HashSet<String> fqNames = new HashSet<String>();
649:
650: MethodParameterInfo retType = getReturnParameter();
651: if (retType != null) {
652: ArrayList<String[]> refs = retType
653: .getReferredCodeGenTypes();
654: GenCodeUtil.mergeReferredCodeGenTypes(res, fqNames, refs);
655: }
656:
657: MethodParameterInfo[] params = getParameters();
658: if (params != null) {
659: for (int i = 0; i < params.length; i++) {
660: if (params[i] != null) {
661: ArrayList<String[]> refs = params[i]
662: .getReferredCodeGenTypes();
663: GenCodeUtil.mergeReferredCodeGenTypes(res, fqNames,
664: refs);
665: }
666: }
667: }
668:
669: /* isn't needed as the exceptions contains fully-qualified names
670: String[] exceptions = getExceptions();
671: if (exceptions != null) {
672: for(int i = 0; i < exceptions.length; i++) {
673: if (exceptions[i] != null) {
674: // TBD - exception string may be with generic
675: String[] pn = new String[]{JavaClassUtils.getPackageName(exceptions[i]),
676: JavaClassUtils.getShortClassName(exceptions[i])};
677: ArrayList<String[]> refs = new ArrayList<String[]>();
678: refs.add(pn);
679: GenCodeUtil.mergeReferredCodeGenTypes(res, fqNames, refs);
680: }
681: }
682: }
683: */
684:
685: return res;
686: }
687:
688: private static final HashMap<String, String> defaultReturnValues = new HashMap<String, String>();
689:
690: static {
691: defaultReturnValues.put("int", "0");
692: defaultReturnValues.put("short", "0");
693: defaultReturnValues.put("long", "0");
694: defaultReturnValues.put("float", "0.0f");
695: defaultReturnValues.put("double", "0.0");
696: defaultReturnValues.put("byte", "0");
697: defaultReturnValues.put("char", "'a'");
698: defaultReturnValues.put("boolean", "true");
699: }
700:
701: public String getDefaultReturnValue() {
702: String retType = getCodeGenReturnType();
703: if (retType == null || retType.equals("void")) {
704: return null;
705: }
706: String res = defaultReturnValues.get(retType);
707: if (res == null) {
708: return "null";
709: }
710: return res;
711: }
712:
713: }
|