KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > hints > MagicSurroundWithTryCatch


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-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java.hints;
21
22 import com.sun.source.tree.BlockTree;
23 import com.sun.source.tree.CatchTree;
24 import com.sun.source.tree.ExpressionTree;
25 import com.sun.source.tree.StatementTree;
26 import com.sun.source.tree.Tree.Kind;
27 import com.sun.source.tree.TryTree;
28 import com.sun.source.tree.VariableTree;
29 import com.sun.source.util.TreePath;
30 import com.sun.source.util.TreeScanner;
31 import java.io.IOException JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Arrays JavaDoc;
34 import java.util.Collections JavaDoc;
35 import java.util.EnumSet JavaDoc;
36 import java.util.List JavaDoc;
37 import javax.lang.model.element.Element;
38 import javax.lang.model.element.Modifier;
39 import javax.lang.model.element.TypeElement;
40 import javax.lang.model.type.TypeMirror;
41 import org.netbeans.api.java.source.CancellableTask;
42 import org.netbeans.api.java.source.CompilationInfo;
43 import org.netbeans.api.java.source.JavaSource;
44 import org.netbeans.api.java.source.JavaSource.Phase;
45 import org.netbeans.api.java.source.TreeMaker;
46 import org.netbeans.api.java.source.TypeMirrorHandle;
47 import org.netbeans.api.java.source.WorkingCopy;
48 import org.netbeans.modules.java.editor.codegen.GeneratorUtils;
49 import org.netbeans.spi.editor.hints.ChangeInfo;
50 import org.netbeans.spi.editor.hints.Fix;
51 import org.openide.ErrorManager;
52
53
54 /**
55  *
56  * @author Jan Lahoda
57  */

58 final class MagicSurroundWithTryCatch implements Fix {
59     
60     private JavaSource js;
61     private List JavaDoc<TypeMirrorHandle> thandles;
62     private int offset;
63     
64     public MagicSurroundWithTryCatch(JavaSource js, List JavaDoc<TypeMirrorHandle> thandles, int offset) {
65         this.js = js;
66         this.thandles = thandles;
67         this.offset = offset;
68     }
69     
70     public String JavaDoc getText() {
71         return "Surround with try-catch";
72     }
73     
74     private static final String JavaDoc[] STREAM_ALIKE_CLASSES = new String JavaDoc[] {
75         "java.io.InputStream",
76         "java.io.OutputStream",
77         "java.io.Reader",
78         "java.io.Writer",
79     };
80     
81     private boolean isStreamAlike(CompilationInfo info, TypeMirror type) {
82         for (String JavaDoc fqn : STREAM_ALIKE_CLASSES) {
83             Element inputStream = info.getElements().getTypeElement(fqn);
84             
85             if (info.getTypes().isAssignable(type, inputStream.asType()))
86                 return true;
87         }
88         
89         return false;
90     }
91
92     public ChangeInfo implement() {
93         try {
94             js.runModificationTask(new CancellableTask<WorkingCopy>() {
95                 public void cancel() {
96                 }
97                 public void run(WorkingCopy wc) throws Exception JavaDoc {
98                     wc.toPhase(Phase.RESOLVED);
99                     TreePath currentPath = wc.getTreeUtilities().pathFor(offset + 1);
100                     
101                     //find statement:
102
while (currentPath != null && !UncaughtExceptionCreator.STATEMENT_KINDS.contains(currentPath.getLeaf().getKind()))
103                         currentPath = currentPath.getParentPath();
104                     
105                     //TODO: test for final??
106
TreePath statement = currentPath;
107                     boolean streamAlike = false;
108                     
109                     if (statement.getLeaf().getKind() == Kind.VARIABLE) {
110                         //special case variable declarations which intializers create streams or readers/writers:
111
Element curType = wc.getTrees().getElement(statement);
112                         
113                         streamAlike = isStreamAlike(wc, curType.asType());
114                     }
115                     
116                     //find try block containing this statement, if exists:
117
TreePath catchTree = currentPath;
118                     
119                     while (catchTree != null
120                             && catchTree.getLeaf().getKind() != Kind.TRY
121                             && catchTree.getLeaf().getKind() != Kind.CLASS
122                             && catchTree.getLeaf().getKind() != Kind.CATCH)
123                         catchTree = catchTree.getParentPath();
124                     
125                     if (catchTree.getLeaf().getKind() == Kind.TRY) {
126                         //only add catches for uncatched exceptions:
127
new TransformerImpl(wc, thandles, streamAlike, statement).scan(catchTree.getLeaf(), null);
128                     } else {
129                         //find block containing this statement, if exists:
130
TreePath blockTree = currentPath;
131                         
132                         while (blockTree != null
133                                 && blockTree.getLeaf().getKind() != Kind.BLOCK)
134                             blockTree = blockTree.getParentPath();
135                         
136                         new TransformerImpl(wc, thandles, streamAlike, statement).scan(blockTree.getLeaf(), null);
137                     }
138                 }
139                 }).commit();
140         } catch (IOException JavaDoc e) {
141             ErrorManager.getDefault().notify(e);
142         }
143         return null;
144     }
145     
146     private final class TransformerImpl extends TreeScanner<Void JavaDoc, Void JavaDoc> {
147         
148         private WorkingCopy info;
149         private List JavaDoc<TypeMirrorHandle> thandles;
150         private boolean streamAlike;
151         private TreePath statement;
152         private TreeMaker make;
153         
154         public TransformerImpl(WorkingCopy info, List JavaDoc<TypeMirrorHandle> thandles, boolean streamAlike, TreePath statement) {
155             this.info = info;
156             this.thandles = thandles;
157             this.streamAlike = streamAlike;
158             this.statement = statement;
159             this.make = info.getTreeMaker();
160         }
161         
162         private StatementTree createExceptionsStatement() {
163             TypeElement exceptions = info.getElements().getTypeElement("org.openide.util.Exceptions");
164             
165             if (exceptions == null) {
166                 return null;
167             }
168             
169             return make.ExpressionStatement(make.MethodInvocation(Collections.<ExpressionTree>emptyList(), make.MemberSelect(make.QualIdent(exceptions), "printStackTrace"), Arrays.asList(make.Identifier("ex"))));
170         }
171         
172         private StatementTree createLogStatement() {
173             if (!GeneratorUtils.supportsOverride(info.getFileObject()))
174                 return null;
175             
176             TypeElement logger = info.getElements().getTypeElement("java.util.logging.Logger");
177             TypeElement level = info.getElements().getTypeElement("java.util.logging.Level");
178             
179             if (logger == null || level == null) {
180                 return null;
181             }
182             
183             ExpressionTree etExpression = make.MethodInvocation(Collections.<ExpressionTree>emptyList(), make.MemberSelect(make.QualIdent(logger), "getLogger"), Collections.singletonList(make.Literal("global")));
184             ExpressionTree levelExpression = make.MemberSelect(make.QualIdent(level), "SEVERE");
185             
186             return make.ExpressionStatement(make.MethodInvocation(Collections.<ExpressionTree>emptyList(), make.MemberSelect(etExpression, "log"), Arrays.asList(levelExpression, make.Literal(null), make.Identifier("ex"))));
187         }
188         
189         private StatementTree createPrintStackTraceStatement() {
190             return make.ExpressionStatement(make.MethodInvocation(Collections.<ExpressionTree>emptyList(), make.MemberSelect(make.Identifier("ex"), "printStackTrace"), Collections.<ExpressionTree>emptyList()));
191         }
192         
193         private CatchTree createCatch(TypeMirror type) {
194             StatementTree logStatement = createExceptionsStatement();
195             
196             if (logStatement == null) {
197                 logStatement = createLogStatement();
198             }
199             
200             if (logStatement == null) {
201                 logStatement = createPrintStackTraceStatement();
202             }
203             
204             return make.Catch(make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), "ex", make.Type(type), null), make.Block(Collections.singletonList(logStatement), false));
205         }
206         
207         private List JavaDoc<CatchTree> createCatches() {
208             List JavaDoc<CatchTree> catches = new ArrayList JavaDoc<CatchTree>();
209             
210             for (TypeMirrorHandle th : thandles) {
211                 catches.add(createCatch(th.resolve(info)));
212             }
213             
214             return catches;
215         }
216         
217         public @Override JavaDoc Void JavaDoc visitTry(TryTree tt, Void JavaDoc p) {
218             List JavaDoc<CatchTree> catches = createCatches();
219             
220             catches.addAll(tt.getCatches());
221             
222             if (!streamAlike) {
223                 info.rewrite(tt, make.Try(tt.getBlock(), catches, tt.getFinallyBlock()));
224             } else {
225                 VariableTree originalDeclaration = (VariableTree) statement.getLeaf();
226                 VariableTree declaration = make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), originalDeclaration.getName(), originalDeclaration.getType(), make.Literal(null));
227                 StatementTree assignment = make.ExpressionStatement(make.Assignment(make.Identifier(originalDeclaration.getName()), originalDeclaration.getInitializer()));
228                 List JavaDoc<StatementTree> finallyStatements = new ArrayList JavaDoc<StatementTree>(tt.getFinallyBlock() != null ? tt.getFinallyBlock().getStatements() : Collections.<StatementTree>emptyList());
229                 
230                 finallyStatements.add(createFinallyCloseBlockStatement(originalDeclaration.getName()));
231                 
232                 BlockTree finallyTree = make.Block(finallyStatements, false);
233                 
234                 info.rewrite(originalDeclaration, assignment);
235                 
236                 TryTree nueTry = make.Try(tt.getBlock(), catches, finallyTree);
237                 
238                 TreePath currentBlockCandidate = statement;
239                 
240                 while (currentBlockCandidate.getLeaf() != tt) {
241                     currentBlockCandidate = currentBlockCandidate.getParentPath();
242                 }
243                 
244                 if (currentBlockCandidate.getLeaf().getKind() == Kind.BLOCK) {
245                     BlockTree originalTree = (BlockTree) currentBlockCandidate.getLeaf();
246                     List JavaDoc<StatementTree> statements = new ArrayList JavaDoc<StatementTree>(originalTree.getStatements());
247                     int index = statements.indexOf(tt);
248                     
249                     statements.remove(index);
250                     statements.add(index, nueTry);
251                     statements.add(index, declaration);
252                     info.rewrite(originalTree, make.Block(statements, false));
253                 } else {
254                     BlockTree nueBlock = make.Block(Arrays.asList(declaration, nueTry), false);
255                     
256                     info.rewrite(tt, nueBlock);
257                 }
258             }
259             
260             return null;
261         }
262         
263         private StatementTree createFinallyCloseBlockStatement(CharSequence JavaDoc name) {
264             StatementTree close = make.ExpressionStatement(make.MethodInvocation(Collections.<ExpressionTree>emptyList(), make.MemberSelect(make.Identifier(name), "close"), Collections.<ExpressionTree>emptyList()));
265             StatementTree tryStatement = make.Try(make.Block(Collections.singletonList(close), false), Collections.singletonList(createCatch(info.getElements().getTypeElement("java.io.IOException").asType())), null);
266             
267             return tryStatement;
268         }
269         
270         public @Override JavaDoc Void JavaDoc visitBlock(BlockTree bt, Void JavaDoc p) {
271             List JavaDoc<CatchTree> catches = createCatches();
272             
273             if (!streamAlike) {
274                 info.rewrite(bt, make.Block(Collections.singletonList(make.Try(bt, catches, null)), false));
275             } else {
276                 VariableTree originalDeclaration = (VariableTree) statement.getLeaf();
277                 VariableTree declaration = make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), originalDeclaration.getName(), originalDeclaration.getType(), make.Identifier("null"));
278                 StatementTree assignment = make.ExpressionStatement(make.Assignment(make.Identifier(originalDeclaration.getName()), originalDeclaration.getInitializer()));
279                 BlockTree finallyTree = make.Block(Collections.singletonList(createFinallyCloseBlockStatement(originalDeclaration.getName())), false);
280                 
281                 info.rewrite(originalDeclaration, assignment);
282                 info.rewrite(bt, make.Block(Arrays.asList(declaration, make.Try(bt, catches, finallyTree)), false));
283             }
284             
285             return null;
286         }
287         
288     }
289     
290 }
291
Popular Tags