KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javacore > TryWrapper


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;
20
21 import java.util.*;
22 import org.netbeans.jmi.javamodel.*;
23 import org.netbeans.modules.javacore.internalapi.GuardedQuery;
24 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
25 import org.netbeans.modules.javacore.internalapi.JavaModelUtil;
26 import org.netbeans.modules.javacore.jmiimpl.javamodel.*;
27 import org.openide.filesystems.FileObject;
28 import org.openide.util.NbBundle;
29
30 /**
31  * TryWrapper can encapsulate block with a try statement
32  * @author Jan Becicka
33  */

34 public class TryWrapper {
35     /**
36      * element which will be replaced by try statement
37      */

38     private Element elementToReplace;
39     /**
40      * parent of elementToReplace
41      */

42     private Element replaceParent;
43     
44     private JavaModelPackage model;
45
46     private List tryBody;
47     
48     /**
49      * TryWrapper can encapsulate block with a try statement
50      * @param fo FileObject where try will be added
51      * @param from begin index
52      * @param to end index
53      */

54     public TryWrapper(FileObject fo, int from, int to) {
55         this(JavaModelUtil.getSelectedStatements(JavaMetamodel.getManager().getResource(fo), from, to));
56     }
57
58     public TryWrapper(List/*<Statement>*/ statements) {
59         if (statements==null) {
60             throw new GeneralException(NbBundle.getMessage(TryWrapper.class, "MSG_CannotEncapsulate"));
61         }
62         tryBody = new ArrayList(statements);
63         
64         elementToReplace = (Element) tryBody.get(0);
65         if (GuardedQuery.isSectionGuarded(elementToReplace.getResource(), JavaMetamodel.getManager().getElementPosition(elementToReplace))) {
66             throw new GeneralException(NbBundle.getMessage(TryWrapper.class, "MSG_CannotEncapsulateGuardedBlock"));
67         }
68         replaceParent = (Element) elementToReplace.refImmediateComposite();
69         model = (JavaModelPackage) elementToReplace.refOutermostPackage();
70     }
71     
72     private void check(List body, List declaredVariables) {
73         Iterator it = body.iterator();
74         while (it.hasNext()) {
75             Object JavaDoc o = it.next();
76             if (o instanceof LocalVarDeclaration) {
77                 LocalVarDeclaration decl = (LocalVarDeclaration) o;
78                 declaredVariables.addAll(decl.getVariables());
79             }
80         }
81     }
82     
83     private ExpressionStatement createAssignment(LocalVariable var) {
84         VariableAccess access = model.getVariableAccess().createVariableAccess(var.getName(),null, false);
85         InitialValue initValue = var.getInitialValue();
86         var.setInitialValue(null);
87         Assignment a = model.getAssignment().createAssignment(access, OperatorEnum.ASSIGN, (Expression) initValue);
88         ExpressionStatement s = model.getExpressionStatement().createExpressionStatement(a);
89         return s;
90     }
91     
92     private Set getUsedVariables(List decl, List statements) {
93         Set used = new LinkedHashSet();
94         LinkedList l = new LinkedList();
95         l.addAll(statements);
96         while (!l.isEmpty()) {
97             Element e = (Element) l.removeFirst();
98             if (e instanceof VariableAccess) {
99                 Iterator i = decl.iterator();
100                 while (i.hasNext()) {
101                     LocalVariable var = (LocalVariable) i.next();
102 // if (((VariableAccess) e).getElement().equals(var)) {
103
// used.add(var);
104
// }
105
if (((VariableAccess) e).getName().equals(var.getName())) {
106                         used.add(var);
107                     }
108                 }
109             }
110             l.addAll(e.getChildren());
111         }
112         return used;
113     }
114     
115     /**
116      * wrap given selection with a try statement
117      * @return TryStatement
118      */

119     public TryStatement wrap() {
120         //try block
121
List decl = new ArrayList();
122         check(tryBody, decl);
123         
124         List catches = createCatches(getExceptions(tryBody));
125         
126         //empty finally block
127
StatementBlock finallyBlock = !catches.isEmpty()?null:model.getStatementBlock().createStatementBlock();
128         
129         TryStatement tryStatement = model.getTryStatement().createTryStatement();
130         tryStatement.getCatches().addAll(catches);
131         tryStatement.setFinalizer(finallyBlock);
132         
133         if (replaceParent instanceof Feature) {
134             ArrayList l = new ArrayList();
135             l.add(tryStatement);
136             replaceParent.replaceChild(elementToReplace, model.getStatementBlock().createStatementBlock(l));
137             StatementBlock tryBlock = model.getStatementBlock().createStatementBlock(tryBody);
138             tryStatement.setBody(tryBlock);
139         } else {
140             List ll = new ArrayList();
141             ll.addAll(replaceParent.getChildren());
142             ll.remove(elementToReplace);
143             replaceParent.replaceChild(elementToReplace, tryStatement);
144             ArrayList tryBody2 = new ArrayList(tryBody);
145             tryBody.remove(elementToReplace);
146             for (Iterator i = tryBody.iterator(); i.hasNext() ; ) {
147                 Element e = (Element) i.next();
148                 replaceParent.replaceChild(e, null);
149                 ll.remove(e);
150             }
151             StatementBlock tryBlock = model.getStatementBlock().createStatementBlock(tryBody2);
152             tryStatement.setBody(tryBlock);
153             Set l = getUsedVariables(decl, ll);
154             List body;
155             if (replaceParent instanceof StatementBlock) {
156                 // commands are mostly closed in statement blocks,
157
body = ((StatementBlock) replaceParent).getStatements();
158             } else {
159                 // but they can be also in if/else statements outside the
160
// block, e.g.
161
// if (b == true) throw new IllegalArgumentException
162
body = Collections.singletonList(tryStatement);
163             }
164             int index = body.indexOf(tryStatement);
165             body.addAll(index, separateDeclsAndInits(l, tryBlock));
166             // leave all the other declarations!!!
167
}
168         return tryStatement;
169     }
170     
171     /**
172      * Separetes declarations and initializers of variables. This separation
173      * is used when initial value of local variable in declaration throws
174      * exception and variable is used outside target try block. In such a case,
175      * we have to create new declaration before the try statement, but
176      * initializer has to be inside as it can throw exception. It is obvious
177      * from example:
178      * <code>
179      * FileInputStream fis = new FileInputStream(new File("jezFile"));
180      * if (fis == null) return;
181      * </code>
182      * Consider you are wrapping first line of code with declaring <tt>fis</tt>
183      * variable. Constructor can throw <tt>java.io.IOException</tt>, so the
184      * code has to be changed to:
185      * <code>
186      * FileInputStream fis;
187      * try {
188      * fis = new FileInputStream(new File("jezFile"));
189      * } catch (FileNotFoundException ex) {
190      * ex.printStackTrace();
191      * }
192      * if (fis == null) return;
193      * </code>
194      * Variable <tt>fis</tt> is used outside the try block, it has to be
195      * declared before.
196      *
197      * The method also solve cases when more then one variable is declared
198      * in a row, i.e.
199      * <code>
200      * FileInputStream fis = new FileInputStream(new File("jezFile")),
201      * fis2 = new FileInputStream(new File("nejezFile"));
202      * </code>
203      *
204      * @param usedVars set of local variable which are used outside the
205      * try block and needs separation of declaration and init values
206      * @param addInitializersTo statement block, where the initializers
207      * separated from declaration will be added. From the example
208      * above, newly created assignement
209      * <tt>fis = new FileInputStream(new File("jezFile"));</tt>
210      * is added.
211      * @return list of newly created declarations which has to be added
212      * before the try block. From the example above,
213      * <tt>FileInputStream fis;</tt> is added to the list.
214      *
215      */

216     private List separateDeclsAndInits(Set usedVars, StatementBlock addInitializersTo) {
217         List decl = new ArrayList();
218         Iterator varsIt = usedVars.iterator();
219         Set separated = new HashSet(2);
220         List statements = addInitializersTo.getStatements();
221         while (varsIt.hasNext()) {
222             LocalVariable var = (LocalVariable) varsIt.next();
223             LocalVarDeclaration parent = (LocalVarDeclaration) var.refImmediateComposite();
224             // work only on set of declarations. All the variables from
225
// one declaration are solved toghether. So next variable
226
// from the same declaration was solved already, skip it.
227
if (!separated.contains(parent)) {
228                 separated.add(parent);
229                 LocalVarDeclaration lvdCopy = (LocalVarDeclaration) parent.duplicate();
230                 // operate with all variables in declaration
231
LocalVariable[] vars = (LocalVariable[]) lvdCopy.getVariables().toArray(new LocalVariable[0]);
232                 boolean removeInitVals = false;
233                 for (int varInDecl = 0; varInDecl < vars.length; varInDecl++) {
234                     for (Iterator varsIt2 = usedVars.iterator(); varsIt2.hasNext(); ) {
235                         LocalVariable lv_used = (LocalVariable) varsIt2.next();
236                         if (lv_used.getName().equals(vars[varInDecl].getName())) {
237                             // if we have found the first used variable declared
238
// in specified declaration and used outside the
239
// try block, we have to separate declaration and
240
// initialization. Set the flag.
241
removeInitVals = true;
242                             break;
243                         }
244                     }
245                     // if any of initial value from local variable declaration
246
// can throw exception, the variable is initialized
247
// inside the try block in assignement expression, outside
248
// the declaration.
249
if (removeInitVals) {
250                         List newAssignments = new ArrayList();
251                         int parentIndex = statements.indexOf(parent);
252                         
253                         for (int j = 0; j < vars.length; j++) {
254                             if (vars[j].getInitialValue() != null) {
255                                 newAssignments.add(createAssignment(vars[j]));
256                                 vars[j].setInitialValue(null);
257                             }
258                         }
259                         statements.addAll(parentIndex,newAssignments);
260                         break;
261                     }
262                 }
263                 // if any of declarations was separated from its initializers
264
// (initializer of variable throws exception), put the newly
265
// created declaration to the return list.
266
if (removeInitVals) {
267                     decl.add(lvdCopy);
268                     parent.refDelete();
269                 }
270             }
271         }
272         return decl;
273     }
274
275     /**
276      * creates catch statements from List of Exception names
277      * @param ex List of ElementReferences
278      * @return List of Catch statements
279      */

280     private List createCatches(Collection ex) {
281         List catches = new ArrayList();
282         String JavaDoc parName = "ex"; // NOI18N
283

284         for (Iterator i = ex.iterator(); i.hasNext();) {
285             MultipartId e = (MultipartId) i.next();
286             Parameter par = model.getParameter().createParameter(parName, null, false, e, 0, false);
287             MultipartId var = model.getMultipartId().createMultipartId(parName, null, null);
288             MethodInvocation m = model.getMethodInvocation().createMethodInvocation("printStackTrace", Collections.EMPTY_LIST, var, false); //NOI18N
289
Statement st = model.getExpressionStatement().createExpressionStatement(m);
290             StatementBlock block = model.getStatementBlock().createStatementBlock(Collections.singletonList(st));
291             
292             catches.add(model.getCatch().createCatch(par, block));
293         }
294         return catches;
295     }
296     
297     /**
298      *
299      * @param b Statement block to search
300      * @return Exception names of all callable features in statement blcok
301      */

302     private Collection getExceptions(List b) {
303         Set exSet = JavaModelUtil.getExceptionsFromStatements(b);
304         Map exMap = new TreeMap();
305         Collection result = new ArrayList();
306         Collection exceptions;
307         int index = 0;
308         int exs = exSet.size();
309                 
310         for (Iterator i = exSet.iterator(); i.hasNext(); index++) {
311             JavaClass c = (JavaClass) i.next();
312             int id = -(getExceptionLevel(c)*exs+index);
313             
314             exMap.put(new Integer JavaDoc(id),c);
315         }
316         exceptions = exMap.values();
317         for (Iterator i = exceptions.iterator(); i.hasNext();) {
318             JavaClass c = (JavaClass) i.next();
319             result.add(JavaModelUtil.resolveImportsForClass(replaceParent, c));
320         }
321         return result;
322     }
323     
324     private int getExceptionLevel(JavaClass ex) {
325         if (ex.getName().equals("java.lang.Object")) { // to prevent endless loop
326
return 0; // for unresolved classes
327
}
328         if (ex.getName().equals("java.lang.Throwable")) {
329             return 0;
330         }
331         return getExceptionLevel(ex.getSuperClass())+1;
332     }
333     
334 }
335
Popular Tags