KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javacore > jmiimpl > javamodel > BehavioralFeatureImpl


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.javacore.jmiimpl.javamodel;
20
21 import java.util.ArrayList JavaDoc;
22 import org.netbeans.jmi.javamodel.BehavioralFeature;
23 import org.netbeans.jmi.javamodel.Element;
24 import org.netbeans.jmi.javamodel.JavaDoc;
25 import org.netbeans.jmi.javamodel.StatementBlock;
26 import org.netbeans.lib.java.parser.ASTree;
27 import org.netbeans.lib.java.parser.ParserTokens;
28 import org.netbeans.lib.java.parser.Token;
29 import org.netbeans.mdr.storagemodel.StorableObject;
30 import org.netbeans.modules.javacore.parser.*;
31 import javax.jmi.reflect.ConstraintViolationException;
32 import java.util.List JavaDoc;
33 import java.util.Stack JavaDoc;
34 import java.lang.ref.WeakReference JavaDoc;
35
36
37 /**
38  *
39  * @author Martin Matula, Vladimir Hudec
40  */

41 public abstract class BehavioralFeatureImpl extends FeatureImpl implements BehavioralFeature {
42     protected String JavaDoc bodyText;
43     private BodyReference body;
44     protected boolean bodyInited = false;
45     private StatementBlock hardBody;
46
47
48     /** Creates a new instance of InitializerImpl */
49     public BehavioralFeatureImpl(StorableObject s) {
50         super(s);
51     }
52
53     /** The method has to make sure that the AST infos of children are also updated.
54      */

55     protected void matchElementInfo(ElementInfo newInfo) {
56         super.matchElementInfo(newInfo);
57         resetBody();
58     }
59
60     protected void uninitialize() {
61         super.uninitialize();
62         hardBody = null;
63         retrieveBody();
64     }
65
66     protected void resetBody() {
67         StatementBlock temp = retrieveBody();
68         if (temp != null) {
69             body = null;
70             hardBody = null;
71             changeChild(temp, null);
72             temp.refDelete();
73         }
74         bodyInited = false;
75     }
76
77     protected void objectChanged(int mask) {
78         super.objectChanged(mask);
79         if ((mask | CHANGED_CHILDREN) == mask) {
80             StatementBlock body = retrieveBody();
81             if (body != null) {
82                 hardBody = body;
83             }
84         }
85     }
86
87     protected StatementBlock retrieveBody() {
88         if (body == null) return null;
89         StatementBlock result = (StatementBlock) body.get();
90         return result;
91     }
92
93     protected abstract ASTree getBodyAST();
94
95     public java.lang.String JavaDoc getBodyText() {
96         checkUpToDate();
97         if (isChanged(CHANGED_BODY)) {
98             if (hardBody != null) {
99                 throw new ConstraintViolationException(null, null, "Cannot ask for body text after the body was changed."); // NOI18N
100
}
101             return bodyText;
102         } else {
103             ASTProvider parser=getParser();
104             if (parser==null)
105                 return null;
106             ASTree body=getBodyAST();
107             if (body.getType() == ParserTokens.SEMICOLON) {
108                 return null;
109             } else {
110                 Token firstToken=parser.getToken(body.getFirstToken());
111                 Token lastToken=parser.getToken(body.getLastToken());
112
113                 // remove { } from body text
114
return parser.getSourceText().substring(firstToken.getEndOffset(),lastToken.getStartOffset());
115             }
116         }
117     }
118
119     public void setBodyText(String JavaDoc newValue) {
120         if (!childrenInited) {
121             initChildren();
122         }
123         StatementBlock temp = retrieveBody();
124         if (bodyInited && temp != null) {
125             resetBody();
126         }
127         objectChanged(CHANGED_BODY);
128         bodyInited = true;
129         bodyText = newValue;
130     }
131
132     public StatementBlock getBody() {
133         checkUpToDate();
134         if (isChanged(CHANGED_BODY) && bodyText != null) {
135             throw new ConstraintViolationException(null, null, "Cannot ask for body after the body text was changed."); // NOI18N
136
}
137         StatementBlock body = retrieveBody();
138         if (!bodyInited) {
139             body = initBody();
140         }
141         return body;
142     }
143
144     protected void resetChildren() {
145         super.resetChildren();
146         resetBody();
147     }
148
149     public StatementBlock initBody() {
150         bodyInited = false;
151         if (!childrenInited) {
152             initChildren();
153         }
154         StatementBlock body = retrieveBody();
155         FeatureInfo info = (FeatureInfo) getElementInfo();
156         if (getASTree() != null) {
157             ASTree bodyAST = getBodyAST();
158             if (bodyAST.getType() == ParserTokens.SEMICOLON) {
159                 body = null;
160             } else {
161                 info.doAttribution(this);
162                 body = (StatementBlock) initOrCreate(body, bodyAST);
163             }
164         }
165         this.body = body == null ? null : new BodyReference(body);
166         bodyInited = true;
167         return body;
168     }
169
170     protected void setData(List JavaDoc annotations, String JavaDoc javadocText, JavaDoc javadoc, StatementBlock body, String JavaDoc bodyText) {
171         super.setData(annotations, javadocText, javadoc);
172         if (bodyText == null) {
173             changeChild(null, body);
174             this.hardBody = body;
175             this.body = body == null ? null : new BodyReference(body);
176         } else {
177             if (body != null) {
178                 throw new ConstraintViolationException(null, null, "Cannot set both bodyText and body."); // NOI18N
179
}
180             this.bodyText = bodyText;
181         }
182         bodyInited = true;
183     }
184
185     public void setBody(StatementBlock newValue) {
186         StatementBlock body = retrieveBody();
187         if (!bodyInited) {
188             body = initBody();
189         }
190         changeChild(body, newValue);
191         hardBody = newValue;
192         this.body = newValue == null ? null : new BodyReference(newValue);
193         bodyText = null;
194         objectChanged(CHANGED_BODY);
195     }
196
197     public List JavaDoc getChildren() {
198         List JavaDoc list = new ArrayList JavaDoc();
199         if (!isChanged(CHANGED_BODY) || bodyText == null) {
200             addIfNotNull(list, getBody());
201         }
202         return list;
203     }
204
205     public void fixImports(Element scope, Element original) {
206         BehavioralFeature bhFeature = (BehavioralFeature)original;
207         StatementBlockImpl newBody = (StatementBlockImpl)getBody();
208         StatementBlock oldBody = bhFeature.getBody();
209         
210         if (newBody != null && oldBody != null) {
211             newBody.fixImports(scope,oldBody);
212         }
213         super.fixImports(scope,original);
214     }
215
216     protected List JavaDoc getInitedChildren() {
217         List JavaDoc list = super.getInitedChildren();
218         StatementBlock body = retrieveBody();
219         if (bodyInited && (!isChanged(CHANGED_BODY) || bodyText == null)) {
220             addIfNotNull(list, body);
221         }
222         return list;
223     }
224
225     public void replaceChild(Element oldElement, Element newElement) {
226         StatementBlock body = retrieveBody();
227         if (bodyInited && oldElement.equals(body)) {
228             setBody((StatementBlock) newElement);
229             return;
230         }
231         super.replaceChild(oldElement, newElement);
232     }
233
234     protected String JavaDoc indentBody(String JavaDoc oldBody) {
235         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
236         int state = 0;
237         StringBuffer JavaDoc line = new StringBuffer JavaDoc();
238         int level = 0;
239         int raiseLevel = 0;
240         int bracket = 0;
241         boolean isStatement = false;
242         boolean previousStatement = false;
243         int questionMark = 0;
244         Stack JavaDoc stack = new Stack JavaDoc();
245         for (int i = 0; i < oldBody.length(); i++) {
246             char ch = oldBody.charAt(i);
247             if (ch == '\n') {
248                 if (i != 0)
249                     sb.append(getBodyIndentation()).append(getInnerIndentation(level)).append(line).append(ch);
250                 else
251                     sb.append(ch);
252                 line = new StringBuffer JavaDoc();
253                 if (state != 8) state = 0;
254                 level += raiseLevel;
255                 if (isStatement && !previousStatement) {
256                     level++;
257                 } else if (!isStatement && previousStatement) {
258                     level--;
259                 }
260                 previousStatement = isStatement;
261                 raiseLevel = 0;
262             } else {
263                 switch (state) {
264                     case 0: // leading whitespaces
265
if (!Character.isWhitespace(ch)) {
266                             state = 1;
267                         } else {
268                             break;
269                         }
270                     case 1: // code
271
switch (ch) {
272                             case '/':
273                                 state = 2;
274                                 break;
275                             case '"':
276                                 state = 10;
277                                 isStatement = true;
278                                 break;
279                             case '\'':
280                                 state = 4;
281                                 isStatement = true;
282                                 break;
283                             case '{':
284                                 if (bracket == 0 && questionMark == 0) {
285                                     if (!stack.isEmpty()) {
286                                         stack.push("bracket"); // NOI18N
287
}
288                                     isStatement = false;
289                                     raiseLevel++;
290                                 } else {
291                                     isStatement = true;
292                                 }
293                                 break;
294                             case '}':
295                                 if (bracket == 0 && questionMark == 0) {
296                                     if (!stack.isEmpty()) {
297                                         if ("colon".equals(stack.pop())) level--; // NOI18N
298
}
299                                     isStatement = false;
300                                     if (line.length() == 0) {
301                                         level--;
302                                     } else {
303                                         raiseLevel--;
304                                     }
305                                 } else {
306                                     isStatement = true;
307                                 }
308                                 break;
309                             case ';':
310                                 if (bracket == 0) {
311                                     isStatement = false;
312                                 } else {
313                                     isStatement = true;
314                                 }
315                                 questionMark = 0;
316                                 break;
317                             case '?':
318                                 questionMark++;
319                                 isStatement = true;
320                                 break;
321                             case '(':
322                                 bracket++;
323                                 isStatement = true;
324                                 break;
325                             case ')':
326                                 bracket--;
327                                 isStatement = true;
328                                 break;
329                             case ':':
330                                 if (questionMark > 0) {
331                                     questionMark--;
332                                 } else {
333                                     if (!stack.isEmpty() && stack.peek().equals("colon")) { // NOI18N
334
level--;
335                                         raiseLevel++;
336                                     } else {
337                                         stack.push("colon"); // NOI18N
338
raiseLevel++;
339                                     }
340                                     isStatement = false;
341                                     break;
342                                 }
343                                 isStatement = true;
344                                 break;
345                             default:
346                                 if (!Character.isWhitespace(ch)) {
347                                     isStatement = true;
348                                 }
349                                 break;
350                         }
351                         if (ch != '\n') {
352                             line.append(ch);
353                         }
354                         break;
355                     case 2: // maybe a comment (/) - is it followed by another / or *?
356
if (ch == '/') {
357                             state = 3;
358                         } else if (ch == '*') {
359                             state = 8;
360                         } else {
361                             isStatement = true;
362                             state = 1;
363                         }
364                         line.append(ch);
365                         break;
366                     case 3: // simple comment
367
line.append(ch);
368                         break;
369                     case 8: // multi-line comment
370
if (ch == '*') {
371                             state = 9;
372                         }
373                         line.append(ch);
374                         break;
375                     case 9: // end of comment?
376
if (ch == '/') {
377                             state = 1;
378                         } else if (ch != '*') {
379                             state = 8;
380                         }
381                         line.append(ch);
382                         break;
383                     case 4: // char literal
384
if (ch == '\\') { // escape
385
state = 11;
386                         } else if (ch == '\'') {
387                             state = 1;
388                         }
389                         line.append(ch);
390                         break;
391                     case 11: // escape in char literal
392
state = 4;
393                         line.append(ch);
394                         break;
395                     case 10: // string literal
396
if (ch == '\\') {
397                             state = 12;
398                         } else if (ch == '"') {
399                             state = 1;
400                         }
401                         line.append(ch);
402                         break;
403                     case 12: // escape in string literal
404
state = 10;
405                         line.append(ch);
406                         break;
407                 }
408             }
409         }
410         if (line.length()>0)
411             sb.append(getBodyIndentation()).append(getInnerIndentation(level)).append(line).append('\n');
412         return sb.toString();
413     }
414
415     /**
416      * Generates body and appends it to the buffer provided as a parameter.
417      * If the body was set as a text, it uses the bodyText field, otherwise
418      * it generates it from the model elements.
419      * (Considers StatementBlock as a root.)
420      *
421      * NOTE: Should be called only when the body was changed!
422      *
423      * @param buf buffer to append to
424      */

425     protected void generateBody(StringBuffer JavaDoc buf) {
426         StatementBlock body = retrieveBody();
427         if (!bodyInited) {
428             body = initBody();
429         }
430         if (bodyText != null && bodyText.length() > 0 && !bodyText.equals("\n")) { // NOI18N
431
if (bodyText.startsWith("\n") || bodyText.startsWith("\r\n")) {
432                 buf.append(getElementPrefix(BODY_OPEN_CURLY)).append('{'); // NOI18N
433
} else {
434                 formatElementPart(BODY_OPEN_CURLY, buf);
435             }
436             buf.append(indentBody(bodyText));
437             formatElementPart(BODY_CLOSE_CURLY, buf);
438         } else if (body != null) {
439             buf.append(((StatementBlockImpl) body).getSourceText());
440         } else {
441             formatElementPart(BODY_OPEN_CURLY, buf);
442             formatElementPart(BODY_CLOSE_CURLY, buf);
443         }
444     }
445
446     /**
447      * Creates diff items for the body. When body text change, it adds
448      * one diff item for the whole body. Otherwise it collects changes
449      * from StatementBlock.
450      *
451      * todo (#pf): StatementBlock partial changes not implmeneted yet.
452      *
453      * @param diffList list of DiffElement, method adds new items to it
454      */

455     protected void createBodyDiffs(List JavaDoc diffList) {
456         ASTProvider parser = getParser();
457         if (hardBody == null) {// we have changed bodyText, not statement block
458
if (isChanged(CHANGED_BODY)) {
459                 int startOffset;
460                 int endOffset;
461                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
462                 if (bodyText == null) {
463                     Token bodyStart = parser.getToken(getBodyAST().getFirstToken() - 1);
464                     startOffset = bodyStart.getEndOffset();
465                     buf.append(';');
466                 } else {
467                     Token bodyStart = parser.getToken(getBodyAST().getFirstToken());
468                     startOffset = bodyStart.getStartOffset();
469                     if (bodyText.startsWith("\n") || bodyText.startsWith("\r\n")) {
470                         buf.append('{'); // NOI18N
471
} else {
472                         buf.append(IndentUtil.leftTrim(formatElementPart(BODY_OPEN_CURLY)));
473                     }
474                     buf.append(indentBody(bodyText));
475                     formatElementPart(BODY_CLOSE_CURLY, buf);
476                 }
477                 Token bodyEnd = parser.getToken(getBodyAST().getLastToken());
478                 endOffset = bodyEnd.getEndOffset();
479                 diffList.add(new DiffElement(startOffset, endOffset, buf.toString()));
480             }
481         } else { // statement block of body has been changed
482
getChildDiff(diffList, parser, getBodyAST(), (MetadataElement) getBody(), CHANGED_BODY);
483         }
484     }
485     
486     protected void _delete() {
487         // --- delete components -------------------------------------------
488
if (bodyInited && body != null) {
489            deleteChild((StatementBlock) body.get());
490         }
491         // delete all contents
492
super._delete();
493     }
494     
495     private class BodyReference extends WeakReference JavaDoc {
496         BodyReference(StatementBlock body) {
497             super(body);
498         }
499
500         public Object JavaDoc get() {
501             Object JavaDoc result = super.get();
502             if (result==null) {
503                 body = null;
504                 bodyInited = false;
505             }
506             return result;
507         }
508     }
509 }
510
Popular Tags