KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > j2ee > jpa > verification > JPAProblemFinder


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.j2ee.jpa.verification;
21
22 import com.sun.source.tree.Tree;
23 import com.sun.source.util.TreePath;
24 import java.beans.PropertyChangeEvent JavaDoc;
25 import java.beans.PropertyChangeListener JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.logging.Level JavaDoc;
31 import java.util.logging.Logger JavaDoc;
32 import javax.lang.model.element.AnnotationMirror;
33 import javax.lang.model.element.AnnotationValue;
34 import javax.lang.model.element.TypeElement;
35 import javax.swing.text.Document JavaDoc;
36 import org.netbeans.api.java.source.CancellableTask;
37 import org.netbeans.api.java.source.CompilationController;
38 import org.netbeans.api.java.source.CompilationInfo;
39 import org.netbeans.api.java.source.JavaSource;
40 import org.netbeans.api.project.FileOwnerQuery;
41 import org.netbeans.api.project.Project;
42 import org.netbeans.modules.j2ee.jpa.model.JPAAnnotations;
43 import org.netbeans.modules.j2ee.jpa.model.JPAHelper;
44 import org.netbeans.modules.j2ee.jpa.verification.common.Utilities;
45 import org.netbeans.modules.j2ee.persistence.api.PersistenceScope;
46 import org.netbeans.modules.j2ee.persistence.api.PersistenceScopes;
47 import org.netbeans.spi.editor.hints.ErrorDescription;
48 import org.netbeans.spi.editor.hints.HintsController;
49 import org.openide.filesystems.FileAttributeEvent;
50 import org.openide.filesystems.FileChangeListener;
51 import org.openide.filesystems.FileEvent;
52 import org.openide.filesystems.FileObject;
53 import org.openide.filesystems.FileRenameEvent;
54 import org.openide.util.WeakListeners;
55
56 /**
57  *
58  * @author Tomasz.Slota@Sun.COM
59  */

60 public abstract class JPAProblemFinder {
61     private boolean cancelled = false;
62     private FileObject file = null;
63     private Object JavaDoc cancellationLock = new Object JavaDoc();
64     private JPAProblemContext context = null;
65     public final static Logger JavaDoc LOG = Logger.getLogger(JPAProblemFinder.class.getName());
66     private final static String JavaDoc PERSISTENCE_SCOPES_LISTENER = "jpa.verification.scopes_listener";
67     
68     public JPAProblemFinder(FileObject file){
69         this.file = file;
70     }
71     
72     public void run(CompilationInfo info) throws Exception JavaDoc{
73         // the 'cancelled' flag must be reset as the instance of JPAProblemFinder is reused
74
cancelled = false;
75         List JavaDoc<ErrorDescription> problemsFound = new ArrayList JavaDoc<ErrorDescription>();
76         createPersistenceScopesListener(file, info.getDocument());
77         
78         for (Tree tree : info.getCompilationUnit().getTypeDecls()){
79             if (isCancelled()){
80                 break;
81             }
82             
83             if (tree.getKind() == Tree.Kind.CLASS){
84                 TreePath path = info.getTrees().getPath(info.getCompilationUnit(), tree);
85                 TypeElement javaClass = (TypeElement) info.getTrees().getElement(path);
86                 LOG.fine("processing class " + javaClass.getSimpleName());
87                 context = findProblemContext(info, javaClass, false);
88                 JPARulesEngine rulesEngine = new JPARulesEngine();
89                 javaClass.accept(rulesEngine, context);
90                 problemsFound.addAll(rulesEngine.getProblemsFound());
91                 
92                 problemsFound.addAll(processIdClassAnnotation(info, javaClass));
93                 
94                 synchronized(cancellationLock){
95                     context = null;
96                 }
97             }
98         }
99         
100         //TODO: should we really reset the errors if the task is cancelled?
101
LOG.log(Level.FINE, "resetting errors, current number of errors in file: {0}", problemsFound.size());
102         HintsController.setErrors(file, "JPA Verification", problemsFound); //NOI18N
103
}
104     
105     /**
106      * If there is IdClassAnotation present run the rules on the pointed class and show
107      * found errors locally
108      */

109     private List JavaDoc<ErrorDescription> processIdClassAnnotation(CompilationInfo info, TypeElement javaClass){
110         AnnotationMirror annIdClass = Utilities.findAnnotation(javaClass, JPAAnnotations.ID_CLASS);
111         
112         if (annIdClass != null){
113             AnnotationValue annValue = Utilities.getAnnotationAttrValue(annIdClass, JPAAnnotations.VALUE_ATTR);
114             
115             if (annValue != null){
116                 Object JavaDoc rawIdClass = annValue.getValue();
117                 TypeElement idClass = info.getElements().getTypeElement(rawIdClass.toString());
118                 
119                 if (idClass != null){
120                     JPAProblemContext context = findProblemContext(info, idClass, true);
121                     context.setElementToAnnotate(info.getTrees().getTree(javaClass, annIdClass, annValue));
122                     JPARulesEngine rulesEngine = new JPARulesEngine();
123                     idClass.accept(rulesEngine, context);
124                     return rulesEngine.getProblemsFound();
125                 }
126             }
127         }
128         
129         return Collections.EMPTY_LIST;
130     }
131     
132     private JPAProblemContext findProblemContext(CompilationInfo info,
133             TypeElement javaClass, boolean idClass){
134         
135         JPAProblemContext context = new JPAProblemContext();
136         
137         if (!idClass){
138             AnnotationMirror annEntity = Utilities.findAnnotation(javaClass, JPAAnnotations.ENTITY);
139             
140             if (annEntity != null){
141                 context.setEntity(true);
142                 context.setElementToAnnotate(info.getTrees().getTree(javaClass, annEntity));
143             }
144             
145             AnnotationMirror annEmbeddable = Utilities.findAnnotation(javaClass, JPAAnnotations.EMBEDDABLE);
146             
147             if (annEmbeddable != null){
148                 context.setEmbeddable(true);
149                 context.setElementToAnnotateOrNullIfExists(info.getTrees().getTree(javaClass, annEmbeddable));
150             }
151             
152             AnnotationMirror annMappedSuperClass = Utilities.findAnnotation(javaClass, JPAAnnotations.MAPPED_SUPERCLASS);
153             
154             if (annMappedSuperClass != null){
155                 context.setMappedSuperClass(true);
156                 context.setElementToAnnotateOrNullIfExists(info.getTrees().getTree(javaClass, annMappedSuperClass));
157             }
158         }
159         context.setIdClass(idClass);
160         context.setFileObject(file);
161         context.setCompilationInfo(info);
162         
163         if (context.isJPAClass()){
164             context.setAccessType(JPAHelper.findAccessType(javaClass));
165         }
166         
167         return context;
168     }
169     
170     public void cancel(){
171         cancelled = true;
172         
173         synchronized(cancellationLock){
174             if (context != null){
175                 context.setCancelled(true);
176             }
177         }
178     }
179     
180     public boolean isCancelled(){
181         return cancelled;
182     }
183     
184     private void createPersistenceScopesListener(FileObject file, Document JavaDoc doc){
185         if (doc == null){
186             return;
187         }
188         
189         LOG.fine("Creating PersistenceScopesListener on " + file.getName());
190         Project project = FileOwnerQuery.getOwner(file);
191         
192         if (project != null){
193             PersistenceScopes scopes = PersistenceScopes.getPersistenceScopes(project);
194             
195             if (scopes != null){
196                 PersistenceScopesListener listener = (PersistenceScopesListener) doc.getProperty(PERSISTENCE_SCOPES_LISTENER);
197                 
198                 if (listener == null){
199                     listener = new PersistenceScopesListener(file);
200                     PropertyChangeListener JavaDoc weakListener = WeakListeners.create(PropertyChangeListener JavaDoc.class, listener, null);
201                     scopes.addPropertyChangeListener(weakListener);
202                     
203                     // scopes listener should live as long as the document
204
doc.putProperty(PERSISTENCE_SCOPES_LISTENER, listener);
205                 }
206                 
207                 ArrayList JavaDoc<PersistenceXMLListener> pxmlListeners = new ArrayList JavaDoc<PersistenceXMLListener>();
208                 
209                 for (PersistenceScope scope : scopes.getPersistenceScopes()){
210                     FileObject persistenceXML = scope.getPersistenceXml();
211                     PersistenceXMLListener pxmlListener = new PersistenceXMLListener(file);
212                     FileChangeListener weakPXMLListener = WeakListeners.create(FileChangeListener.class, pxmlListener, null);
213                     persistenceXML.addFileChangeListener(weakPXMLListener);
214                     pxmlListeners.add(pxmlListener);
215                     LOG.fine("Added PersistenceXMLListener to " + persistenceXML.getName());
216                 }
217                 
218                 // persistence.xml listeners should live as long as the scopes listener
219
listener.setPXMLListeners(pxmlListeners);
220             }
221         }
222     }
223     
224     private abstract class RescanTrigger{
225         private FileObject file;
226         
227         RescanTrigger(FileObject file){
228             this.file = file;
229         }
230         
231         void rescan(){
232             JavaSource javaSrc = JavaSource.forFileObject(file);
233             
234             if (javaSrc != null){
235                 try{
236                     javaSrc.runUserActionTask(new ProblemFinderCompControl(file), true);
237                 } catch (IOException JavaDoc e){
238                     LOG.log(Level.WARNING, e.getMessage(), e);
239                 }
240             }
241         }
242     }
243     
244     private class PersistenceScopesListener extends RescanTrigger implements PropertyChangeListener JavaDoc{
245         List JavaDoc<PersistenceXMLListener> pxmlListeners;
246         
247         PersistenceScopesListener(FileObject file){
248             super(file);
249         }
250         
251         public void propertyChange(PropertyChangeEvent JavaDoc evt){
252             LOG.fine("Received a change event from PersistenceScopes");
253             rescan();
254         }
255         
256         void setPXMLListeners(List JavaDoc<PersistenceXMLListener> pxmlListeners){
257             this.pxmlListeners = pxmlListeners;
258         }
259     }
260     
261     private class PersistenceXMLListener extends RescanTrigger implements FileChangeListener{
262         PersistenceXMLListener(FileObject file){
263             super(file);
264         }
265         
266         public void fileChanged(FileEvent fe){
267             LOG.fine("Received a change event from persistence.xml");
268             rescan();
269         }
270         
271         public void fileFolderCreated(FileEvent fe){}
272         public void fileDataCreated(FileEvent fe){}
273         public void fileDeleted(FileEvent fe){}
274         public void fileRenamed(FileRenameEvent fe){}
275         public void fileAttributeChanged(FileAttributeEvent fe){}
276     }
277     
278     public static class ProblemFinderCompInfo extends JPAProblemFinder implements CancellableTask<CompilationInfo>{
279         public ProblemFinderCompInfo(FileObject file){
280             super(file);
281         }
282     }
283     
284     public static class ProblemFinderCompControl extends JPAProblemFinder implements CancellableTask<CompilationController>{
285         public ProblemFinderCompControl(FileObject file){
286             super(file);
287         }
288         
289         public void run(CompilationController controller) throws Exception JavaDoc {
290             controller.toPhase(JavaSource.Phase.RESOLVED);
291             super.run(controller);
292         }
293     }
294 }
295
Popular Tags