1 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 ; 25 import java.beans.PropertyChangeListener ; 26 import java.io.IOException ; 27 import java.util.ArrayList ; 28 import java.util.Collections ; 29 import java.util.List ; 30 import java.util.logging.Level ; 31 import java.util.logging.Logger ; 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 ; 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 60 public abstract class JPAProblemFinder { 61 private boolean cancelled = false; 62 private FileObject file = null; 63 private Object cancellationLock = new Object (); 64 private JPAProblemContext context = null; 65 public final static Logger LOG = Logger.getLogger(JPAProblemFinder.class.getName()); 66 private final static String 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 { 73 cancelled = false; 75 List <ErrorDescription> problemsFound = new ArrayList <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 LOG.log(Level.FINE, "resetting errors, current number of errors in file: {0}", problemsFound.size()); 102 HintsController.setErrors(file, "JPA Verification", problemsFound); } 104 105 109 private List <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 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 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 weakListener = WeakListeners.create(PropertyChangeListener .class, listener, null); 201 scopes.addPropertyChangeListener(weakListener); 202 203 doc.putProperty(PERSISTENCE_SCOPES_LISTENER, listener); 205 } 206 207 ArrayList <PersistenceXMLListener> pxmlListeners = new ArrayList <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 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 e){ 238 LOG.log(Level.WARNING, e.getMessage(), e); 239 } 240 } 241 } 242 } 243 244 private class PersistenceScopesListener extends RescanTrigger implements PropertyChangeListener { 245 List <PersistenceXMLListener> pxmlListeners; 246 247 PersistenceScopesListener(FileObject file){ 248 super(file); 249 } 250 251 public void propertyChange(PropertyChangeEvent evt){ 252 LOG.fine("Received a change event from PersistenceScopes"); 253 rescan(); 254 } 255 256 void setPXMLListeners(List <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 { 290 controller.toPhase(JavaSource.Phase.RESOLVED); 291 super.run(controller); 292 } 293 } 294 } 295 | Popular Tags |