KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > JavaDataObject


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
20 package org.netbeans.modules.java;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.beans.PropertyVetoException JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.ObjectInputStream JavaDoc;
27 import java.util.*;
28 import org.netbeans.api.java.classpath.ClassPath;
29 import org.netbeans.jmi.javamodel.JavaClass;
30 import org.netbeans.jmi.javamodel.JavaModelPackage;
31 import org.netbeans.jmi.javamodel.Resource;
32 import org.netbeans.modules.java.bridge.DefaultLangModel;
33 import org.netbeans.modules.java.bridge.LangModel;
34 import org.netbeans.modules.java.bridge.SrcElementImpl;
35 import org.netbeans.modules.java.parser.JavaParser;
36 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
37 import org.netbeans.modules.javacore.jmiimpl.javamodel.ResourceClassImpl;
38 import org.openide.ErrorManager;
39 import org.openide.cookies.*;
40 import org.openide.filesystems.*;
41 import org.openide.loaders.*;
42 import org.openide.nodes.AbstractNode;
43 import org.openide.nodes.CookieSet;
44 import org.openide.nodes.Node;
45 import org.openide.src.*;
46 import org.openide.src.nodes.ElementNodeFactory;
47 import org.openide.src.nodes.FilterFactory;
48 import org.openide.text.CloneableEditorSupport;
49 import org.openide.util.*;
50
51 /**
52  * Data object representing a Java source file.
53  * May be subclassed (but please don't).
54  */

55 public class JavaDataObject extends MultiDataObject implements CookieSet.Factory {
56     /** generated Serialized Version UID */
57     static final long serialVersionUID = -6035788991669336965L;
58
59     /**
60      * Holds a reference to editor support class. Lazy initialized from getJavaEditor,
61      * or a getter for EditorSupport.class cookie.
62      */

63     transient private JavaEditor editorSupport;
64
65     transient protected AbstractNode alteranteParent;
66
67     /** WeakListener that intercepts external modification while the file is not
68      * opened in the Editor.
69      */

70     transient private FileChangeListener fileChangeListener;
71
72     /** Hook to keep the WeakListener alive for the lifetime of the DataObject
73      */

74     transient private FileChangeListener fileChangeListenerHook;
75
76
77     /** TEMPORARY: Filename of the primary file before it was changed (DO was
78      * renamed or moved.
79      */

80     transient private String JavaDoc previousFileName;
81
82     /** Lock for parsing and connection support
83      */

84     transient private Object JavaDoc lock;
85
86     private transient boolean initialized;
87
88     /**
89      * Holds a reference to the glue between the parser and the dataobject.
90      * Lazy initialized from {@link #initializeParsingSupport}
91      */

92     private transient JavaParserGlue parserGlue;
93
94     private transient SourceElement source = null;
95
96     private transient DefaultLangModel model = null;
97
98     /** Create new data object.
99     * @param pf primary file object for this data object (i.e. the source file)
100     * @param loader the associated loader
101     */

102     public JavaDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException {
103         super(pf, loader);
104         init();
105     }
106
107     private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
108         in.defaultReadObject();
109         init();
110     }
111
112     private void init() {
113         MultiDataObject.Entry entry = getPrimaryEntry();
114         CookieSet cookies = getCookieSet();
115         Class JavaDoc[] cookieClasses = new Class JavaDoc[] {
116             JavaEditor.class,
117             JavaParser.class,
118             SourceCookie.Editor.class,
119         };
120         cookies.add(cookieClasses, this);
121
122         PrimaryListener l = new PrimaryListener();
123     addPropertyChangeListener(l);
124         fileChangeListenerHook = l;
125     fileChangeListener = FileUtil.weakFileChangeListener(fileChangeListenerHook, entry.getFile());
126         lock = new Object JavaDoc();
127         addSourceChangeListener(null);
128         initialized = true;
129         // [TODO] the following code was comented out as it interfered with FileScanner during IDE startup
130
// it should be uncommented after we figure out how to avoid the interference
131
// try {
132
// updateResource();
133
// } catch (IOException ex) {
134
// ErrorManager.getDefault().notify(ex);
135
// }
136
}
137     
138     public synchronized DefaultLangModel getModel () {
139         if (model == null) {
140             synchronized (lock) {
141                 if (model == null)
142                     model = new DefaultLangModel (this);
143             }
144         }
145         return model;
146     }
147
148
149     void firePropertyChange0(String JavaDoc s, Object JavaDoc v1, Object JavaDoc v2) {
150         super.firePropertyChange(s, v1, v2);
151     }
152
153     /**
154      * Creates a parsing support.
155      */

156     private JavaParser initializeParsingSupport() {
157         if (parserGlue != null)
158             return parserGlue.getParser();
159         synchronized (lock) {
160             if (parserGlue != null) {
161                 return parserGlue.getParser();
162             }
163
164             parserGlue = new JavaParserGlue(getPrimaryEntry());
165             if (editorSupport != null) {
166                 parserGlue.cloneableSupportCreated(editorSupport);
167             }
168         }
169         return parserGlue.getParser();
170     }
171
172     public void setValid(boolean v) throws PropertyVetoException JavaDoc {
173         super.setValid(v);
174         if (!v) {
175             synchronized (this) {
176                 if (parserGlue != null) {
177                     parserGlue.suspendDocumentChanges();
178                 }
179             }
180         }
181     }
182
183     /**
184      * Finds a cloneableEditorSupport that holds the displayable/parseable source. The implementation
185      * currently uses a hack, that extract package-private member from the EditorSupport's
186      * implementation.
187      */

188     protected CloneableEditorSupport findCloneableEditorSupport() {
189         return (JavaEditor)getCookie(JavaEditor.class);
190         //return extractCloneableEditor(supp);
191
}
192
193     /** Attaches a file change listener to the primary (source) file.
194      * Optionally removes the listener from previously used file object.
195      * @param previousPrimary if not null, then the method removes change listener from this
196      * file object.
197      */

198     void addSourceChangeListener(FileObject previousPrimary) {
199       if (previousPrimary != null) {
200         previousPrimary.removeFileChangeListener(fileChangeListener);
201       }
202       getPrimaryEntry().getFile().addFileChangeListener(fileChangeListener);
203     }
204
205     void addSaveCookie(SaveCookie save) {
206         getCookieSet().add(save);
207     }
208     
209     void removeSaveCookie(SaveCookie save) {
210         getCookieSet().remove(save);
211     }
212
213     public void resumeSupports() {
214         parserGlue.resumeDocumentChanges();
215     }
216
217     public void suspendSupports() {
218         // initialize support objects. If they were requested after this method,
219
// they would be created in an active state.
220
initializeParsingSupport();
221         // suspend everything that is bound to the model and document
222
parserGlue.suspendDocumentChanges();
223     }
224
225     boolean isJavaFileReadOnly() {
226     FileObject primary = getPrimaryFile();
227     if (!isValid() || !primary.isValid()) {
228         return true;
229     }
230     return !primary.canWrite();
231     }
232
233     // ==================== Handle methods =======================
234

235     protected DataObject handleCopy(DataFolder df) throws IOException JavaDoc {
236         String JavaDoc originalName = getName();
237         DataObject dob = super.handleCopy(df);
238         if (!Repository.getDefault().getDefaultFileSystem().equals(dob.getPrimaryFile().getFileSystem())) {
239             JavaMetamodel.getDefaultRepository().beginTrans(true);
240             boolean fail = true;
241             try {
242                 ClassPath cp = ClassPath.getClassPath(dob.getPrimaryFile(),ClassPath.SOURCE);
243                 if (cp!=null) {
244                     JavaModelPackage model = JavaMetamodel.getManager().resolveJavaExtent(cp.findOwnerRoot(dob.getPrimaryFile()));
245                     if (model == null) {
246                         ErrorManager.getDefault().log(ErrorManager.WARNING, "JavaDataObject: Extent for " + dob.getName() + " not found");
247                         fail = false;
248                         return dob;
249                     }
250                     ResourceClassImpl resClass = (ResourceClassImpl) model.getResource();
251                     String JavaDoc resourceName = cp.getResourceName(dob.getPrimaryFile());
252                     Resource res = resClass.resolveResource(resourceName, true, false);
253                 
254                     res.setPackageName(cp.getResourceName(df.getPrimaryFile()).replace('/','.'));
255                     Iterator i = res.getClassifiers().iterator();
256                     while (i.hasNext()) {
257                         JavaClass clazz = (JavaClass) i.next();
258                         if (clazz.getSimpleName().equals(originalName)) {
259                             clazz.setSimpleName(dob.getName());
260                         }
261                     }
262                 }
263                 fail = false;
264             } finally {
265                 JavaMetamodel.getDefaultRepository().endTrans(fail);
266             }
267         }
268         return dob;
269     }
270     
271     /* Renames all entries and changes their files to new ones.
272     */

273     protected FileObject handleRename (String JavaDoc name) throws IOException JavaDoc {
274         if (!"package-info".equals(name) && !Utilities.isJavaIdentifier(name)) // NOI18N
275
throw new IOException JavaDoc(NbBundle.getMessage(JavaDataObject.class, "FMT_Not_Valid_FileName", name));
276
277         FileObject fo = super.handleRename(name);
278         return fo;
279     }
280
281     /* Moves primary and secondary files to a new folder.
282      * May ask for user confirmation before overwriting.
283      * @param df the new folder
284      * @return the moved primary file object
285      * @throws IOException if there was a problem moving
286      * @throws UserCancelException if the user cancelled the move
287     */

288     protected FileObject handleMove (DataFolder df) throws IOException JavaDoc {
289         FileObject f = super.handleMove(df);
290         SrcElementImpl src = (SrcElementImpl) getSource().getCookie(SrcElementImpl.class);
291         src.invalidateDelegate();
292         return f;
293     }
294
295     /* Creates new object from template.
296     * @exception IOException
297     */

298     protected DataObject handleCreateFromTemplate (DataFolder df, String JavaDoc name) throws IOException JavaDoc {
299         if (name == null) {
300             // special case: name is null (unspecified or from one-parameter createFromTemplate)
301
name = FileUtil.findFreeFileName(df.getPrimaryFile(),
302                 getPrimaryFile().getName(), "java"); // NOI18N
303
} else if (!"package-info".equals(name) && !Utilities.isJavaIdentifier(name)) // NOI18N
304
throw new IOException JavaDoc(NbBundle.getMessage(JavaDataObject.class, "FMT_Not_Valid_FileName", name));
305
306         IndentFileEntry entry = (IndentFileEntry)getPrimaryEntry();
307         entry.initializeIndentEngine();
308         DataObject obj;
309
310         boolean failed = true;
311         JavaMetamodel.getDefaultRepository().beginTrans(true);
312         try {
313             obj = createDataObject(df, name);
314             ClassPath cp = ClassPath.getClassPath(df.getPrimaryFile(),ClassPath.SOURCE);
315                 if (cp != null) {
316                     String JavaDoc packageName = cp.getResourceName (df.getPrimaryFile(),'.',false);
317                     assert packageName != null;
318                     //if (isValidPackageName(packageName)) {
319
JavaModelPackage model = JavaMetamodel.getManager().resolveJavaExtent(cp.findOwnerRoot (obj.getPrimaryFile()));
320                       ResourceClassImpl resClass = (ResourceClassImpl) model.getResource();
321                       String JavaDoc resourceName = cp.getResourceName (obj.getPrimaryFile());
322                       Resource res = resClass.resolveResource(resourceName, true, false);
323                       res.setName(resourceName);
324                       Iterator i = res.getClassifiers().iterator();
325                       if (i.hasNext()) {
326                           JavaClass clazz = (JavaClass) i.next();
327                           clazz.setSimpleName(name);
328                       }
329                       //package name is set only if package name was already set
330
if (!"".equals(res.getPackageName())) {
331                           res.setPackageName(packageName);
332                       }
333                 }
334                 else {
335                     //Destnation folder is not in project
336
//Skeep update but log
337
//TODO: Remove logging
338
ErrorManager.getDefault().log ("Can not update source while creating from template, destination folder "+
339                         df.getPrimaryFile().getPath()+" is not in any project."); // NOI18N
340
}
341             failed = false;
342         } finally {
343             JavaMetamodel.getDefaultRepository().endTrans(failed);
344             entry.setIndentEngine(null);
345         }
346         return obj;
347     }
348
349     /**
350      * creates new file and its data object from template
351      * @param df where to create
352      * @param name file name
353      * @return new data object
354      * @throws IOException
355      */

356     private DataObject createDataObject(DataFolder df, String JavaDoc name) throws IOException JavaDoc {
357         DataObject obj = super.handleCreateFromTemplate(df, name);
358         
359         // <workaround issue=56870>
360
try {
361             obj.setValid(false);
362             obj = DataObject.find(obj.getPrimaryFile());
363         } catch (PropertyVetoException JavaDoc e) {
364             // do nothing
365
}
366         // </workaround>
367
return obj;
368     }
369
370     /** Create the editor support for this data object.
371     * By default, creates a <code>JavaEditor</code> with the source file entry;
372     * subclasses may override this.
373     * @return the editor support
374     */

375     protected JavaEditor createJavaEditor () {
376         JavaEditor je = new JavaEditor (this);
377         return je;
378     }
379
380     /** Provide node that should represent this data object.
381     * This implementation creates and returns a {@link JavaNode}.
382     * Subclasses may wish to return a specialized subclass of this node type.
383     * You should probably make the default action be {@link OpenAction}.
384     * @return the node representation for this data object
385     */

386     protected Node createNodeDelegate () {
387         JavaNode node = new JavaNode (this);
388         return node;
389     }
390
391     /** Get the parsed representation of this source file.
392     * May not be fully parsed yet; the source element itself indicates its status.
393     * @return the source element for this Java source file
394     */

395     public SourceElement getSource() {
396         // return ((JavaParser)getCookie(JavaParser.class)).getSource();
397
if (source == null) {
398             synchronized (lock) {
399                 if (source == null)
400                     source = new SourceElement (new SrcElementImpl (this));
401             }
402         }
403         return source;
404     }
405
406     /** Get the current editor support.
407     * Ought not be subclasses; use {@link #createJavaEditor}.
408     * @return the editor support
409     */

410     public JavaEditor getJavaEditor() {
411         if (editorSupport == null) {
412             synchronized (this) {
413                 editorSupport = createJavaEditor();
414                 if (parserGlue != null)
415                     parserGlue.cloneableSupportCreated(editorSupport);
416                 else
417                     initializeParsingSupport();
418             }
419         }
420         return editorSupport;
421     }
422
423     // =============== The mechanism for regeisteing node factories ==============
424

425     private static NodeFactoryPool explorerFactories;
426     private static NodeFactoryPool browserFactories;
427     private static ElementNodeFactory basicBrowser;
428
429     /**
430      * DO NOT USE THIS METHOD!!! <P>
431      * This method is intended to be called only during initialization of java
432      * module-provided node factories from the installation layer. It won't
433      * be maintained for compatibility reasons.
434      */

435     synchronized static ElementNodeFactory createBasicExplorerFactory() {
436         return JavaElementNodeFactory.DEFAULT;
437     }
438
439     /**
440      * DO NOT USE THIS METHOD!!! <P>
441      * This method is intended to be called only during initialization of java
442      * module-provided node factories from the installation layer. It won't
443      * be maintained for compatibility reasons.
444      */

445     synchronized static ElementNodeFactory createBasicBrowserFactory() {
446         if (basicBrowser == null) {
447             basicBrowser = org.netbeans.modules.java.ui.nodes.SourceNodes.createElementNodeFactory(
448                     org.netbeans.modules.java.ui.nodes.SourceNodes.getBrowserFactory());
449         }
450         return basicBrowser;
451     }
452
453     public static ElementNodeFactory getExplorerFactory() {
454         NodeFactoryPool pool = createExplorerFactory();
455         ElementNodeFactory f = null;
456
457         if (pool != null)
458             f = pool.getHead();
459         if (f == null)
460             f = createBasicExplorerFactory();
461         return f;
462     }
463
464     /**
465      *
466      * @deprecated
467      */

468     public static ElementNodeFactory getBrowserFactory() {
469         ErrorManager.getDefault().notify(
470                 ErrorManager.WARNING,
471                 new IllegalStateException JavaDoc("JavaDataObject.getBrowserFactory is deprecated. Use SourceNodes.getBrowserFactory() instead.") // NOI18N
472
);
473         return createBasicBrowserFactory();
474     }
475
476     static NodeFactoryPool createFactoryPool(String JavaDoc folderName, ElementNodeFactory def) {
477         FileObject f = Repository.getDefault().getDefaultFileSystem().findResource(folderName);
478     if (f == null)
479         return null;
480         try {
481             DataFolder folder = (DataFolder)DataObject.find(f).getCookie(DataFolder.class);
482             return new NodeFactoryPool(folder, def);
483         } catch (DataObjectNotFoundException ex) {
484             return null;
485         }
486     }
487
488     synchronized static NodeFactoryPool createBrowserFactory() {
489         if (browserFactories != null)
490             return browserFactories;
491         browserFactories = createFactoryPool("/NodeFactories/java/objectbrowser", createBasicBrowserFactory()); // NOI18N
492
return browserFactories;
493     }
494
495     synchronized static NodeFactoryPool createExplorerFactory() {
496         if (explorerFactories != null)
497             return explorerFactories;
498         explorerFactories = createFactoryPool("/NodeFactories/java/explorer", createBasicExplorerFactory()); // NOI18N
499
return explorerFactories;
500     }
501
502     /**
503      * @deprecated use installation layer for registering a factory for the the whole
504      * time a module is installed. Note: This feature will be dropped in the next
505      * release.
506      */

507     public static void addExplorerFilterFactory( FilterFactory factory ) {
508         NodeFactoryPool p = createExplorerFactory();
509         if (p != null)
510             p.addFactory(factory);
511     }
512
513     /**
514      * @deprecated use installation layer for registering a factory for the the whole
515      * time a module is installed. Note: This feature will be dropped in the next
516      * release.
517      */

518     public static void removeExplorerFilterFactory( FilterFactory factory ) {
519         NodeFactoryPool p = createExplorerFactory();
520         if (p != null)
521             p.removeFactory(factory);
522     }
523
524     /**
525      * @deprecated use installation layer for registering a factory for the the whole
526      * time a module is installed. Note: This feature will be dropped in the next
527      * release.
528      */

529     public static void addBrowserFilterFactory(FilterFactory factory) {
530         NodeFactoryPool p = createBrowserFactory();
531         if (p != null)
532             p.addFactory(factory);
533     }
534
535     /**
536      * @deprecated use installation layer for registering a factory for the the whole
537      * time a module is installed. Note: This feature will be dropped in the next
538      * release.
539      */

540     public static void removeBrowserFilterFactory( FilterFactory factory ) {
541         NodeFactoryPool p = createBrowserFactory();
542         if (p != null)
543             p.removeFactory(factory);
544     }
545
546     /* ===================== File -> model dependency handling ===================== */
547     protected static boolean isValidPackageName(String JavaDoc str) {
548         StringTokenizer tok = new StringTokenizer(str, "."); // NOI18N
549
while (tok.hasMoreTokens()) {
550             String JavaDoc part = tok.nextToken();
551             if (!org.openide.util.Utilities.isJavaIdentifier(part))
552                 return false;
553         }
554         return true;
555     }
556
557     protected void primaryFileMoved(FileObject oldFile, FileObject newFile) {
558         addSourceChangeListener(oldFile);
559     }
560
561     protected void primaryFileChanged() {
562 // if (!getJavaEditor().isDocumentLoaded()) {
563
// reparseResource(false);
564
// }
565
}
566
567     // =============== Primary file monitoring ============
568
private class PrimaryListener extends FileChangeAdapter implements PropertyChangeListener JavaDoc{
569         public void propertyChange(final PropertyChangeEvent JavaDoc evt) {
570             if (!initialized)
571                 return;
572             String JavaDoc propName = evt.getPropertyName();
573             if (PROP_PRIMARY_FILE.equals(propName)) {
574                 primaryFileMoved((FileObject)evt.getOldValue(), (FileObject)evt.getNewValue());
575             } else if (PROP_NAME.equals(propName)) {
576                 previousFileName = (String JavaDoc)evt.getOldValue();
577                 primaryFileMoved(getPrimaryFile(), getPrimaryFile());
578             }
579         }
580
581         public void fileChanged(FileEvent e) {
582             if (!initialized)
583                 return;
584             primaryFileChanged();
585         }
586     }
587
588
589     /**
590      * Extract the date of last modification of the source file. If the file is opened
591      * in the editor AND marked as modified (in the editor), it returns true.
592      * If the DataObject reports that it was modified, but the editor support knows
593      * nothing about it, just ignore -- other parts of the DataObject are changed.
594      */

595     Date getLastModified() {
596         SaveCookie c = (SaveCookie)getCookie(SaveCookie.class);
597         if (c != null) {
598             EditorCookie ck = (EditorCookie)getCookie(EditorCookie.class);
599             if (ck != null && ck.isModified())
600                 return new Date();
601         }
602         return getPrimaryFile().lastModified();
603     }
604
605     /** Creates a Node.Cookie of given class. The method
606      * may be called more than once.
607      */

608     public Node.Cookie createCookie(Class JavaDoc klass) {
609         // all execution-related services -> getExecSupport
610
if (klass.isAssignableFrom(JavaEditor.class)) {
611             return getJavaEditor();
612         }
613         if (SourceCookie.class.isAssignableFrom(klass) ||
614             JavaParser.class.isAssignableFrom(klass)) {
615             if (initializeParsingSupport() == null)
616                 return null;
617             if (klass.isAssignableFrom(parserGlue.getClass()))
618                 return parserGlue;
619             else
620                 return parserGlue.getParser();
621         }
622         return null;
623     }
624
625
626     /**
627      * @deprecated do not use this method, it will be removed in next release
628      * @return empty Collection. JavaDataObject does not have any secondary entries
629      */

630     public Collection getCompiledClasses() {
631         Thread.dumpStack();
632         return Collections.EMPTY_LIST;
633     }
634
635     /*
636     public String toString() {
637         return "[JDO for " + getPrimaryFile() + "]"; // NOI18N
638     }
639      */

640 }
641
Popular Tags