KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > j2ee > sun > share > config > ConfigDataObject


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.j2ee.sun.share.config;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Set JavaDoc;
30
31 import javax.swing.text.BadLocationException JavaDoc;
32 import javax.swing.text.StyledDocument JavaDoc;
33 import javax.enterprise.deploy.spi.exceptions.InvalidModuleException JavaDoc;
34 import javax.enterprise.deploy.spi.exceptions.ConfigurationException JavaDoc;
35
36 import org.xml.sax.InputSource JavaDoc;
37
38 import org.openide.DialogDisplayer;
39 import org.openide.ErrorManager;
40 import org.openide.NotifyDescriptor;
41 import org.openide.filesystems.FileObject;
42 import org.openide.filesystems.FileUtil;
43 import org.openide.filesystems.FileChangeListener;
44 import org.openide.filesystems.FileLock;
45 import org.openide.cookies.CloseCookie;
46 import org.openide.cookies.EditCookie;
47 import org.openide.cookies.EditorCookie;
48 import org.openide.cookies.OpenCookie;
49 import org.openide.cookies.PrintCookie;
50 import org.openide.cookies.SaveCookie;
51 import org.openide.loaders.DataFolder;
52 import org.openide.loaders.DataObject;
53 import org.openide.loaders.DataObjectExistsException;
54 import org.openide.loaders.MultiFileLoader;
55 import org.openide.loaders.XMLDataObject;
56 import org.openide.nodes.CookieSet;
57 import org.openide.nodes.Node;
58 import org.openide.text.DataEditorSupport;
59 import org.openide.text.NbDocument;
60 import org.openide.util.HelpCtx;
61 import org.openide.util.Mutex;
62 import org.openide.util.NbBundle;
63 import org.openide.util.WeakListeners;
64 import org.openide.windows.CloneableTopComponent;
65 import org.openide.windows.CloneableOpenSupport;
66 import org.openide.windows.TopComponent;
67
68 import org.netbeans.api.project.FileOwnerQuery;
69 import org.netbeans.api.project.Project;
70 import org.netbeans.api.xml.cookies.CheckXMLCookie;
71 import org.netbeans.api.xml.cookies.ValidateXMLCookie;
72 import org.netbeans.spi.xml.cookies.CheckXMLSupport;
73 import org.netbeans.spi.xml.cookies.DataObjectAdapters;
74 import org.netbeans.spi.xml.cookies.ValidateXMLSupport;
75 import org.netbeans.modules.xml.api.EncodingUtil;
76 import org.netbeans.modules.j2ee.deployment.devmodules.spi.J2eeModuleProvider;
77 import org.netbeans.modules.j2ee.deployment.plugins.api.ConfigurationSupport;
78 import org.netbeans.modules.j2ee.sun.share.config.ui.*;
79 import org.netbeans.modules.j2ee.sun.share.configbean.SunONEDeploymentConfiguration;
80
81
82 /** Data object representing a deployment plan file.
83  * Only interesting feature is the {@link OpenCookie}
84  * which lets you open it in graphical editor.
85  * @author Pavel Buzek
86  */

87 public class ConfigDataObject extends XMLDataObject implements ConfigurationSaver, FileChangeListener {
88
89     //PENDING: create serialVersionUID
90
// private static final long serialVersionUID = -1073885636989804140L;
91

92     public static final String JavaDoc SERVER_ID = "J2EE"; //NOI18N
93

94     private final File JavaDoc configKey;
95     private HashSet JavaDoc secondaries = null; //SecondaryConfigDataObject
96
private boolean isEdited = false;
97     private boolean isEditedChecked = false;
98     private ValidateXMLCookie validateCookie = null;
99     private CheckXMLCookie checkCookie = null;
100     private XMLEditorSupport xmlEditorSupport = null;
101     private XMLOpenSupport xmlOpenSupport = null;
102
103     /** Whether the reload dialog is currently opened. Prevents poping of multiple
104      * reload dialogs if there is more external saves.
105      */

106     private boolean reloadDialogOpened;
107     
108     
109     public ConfigDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException {
110         super(pf, loader);
111         configKey = FileUtil.toFile(pf);
112 // System.out.println("Configuration Key: " + configKey.getPath());
113
pf.addFileChangeListener((FileChangeListener) WeakListeners.create(FileChangeListener.class, this, pf));
114         initCookies();
115     }
116     
117     private void initCookies() {
118         // Need to provide null factory for these four cookies to override what
119
// XMLDataObject installed. Otherwise a duplicate XMLEditorSupport object
120
// will be created and cause bizarre problems. Real cookie cleanup can wait
121
// until we migrate to multiview framework.
122
CookieSet.Factory factory = new CookieSet.Factory() {
123             public Node.Cookie createCookie(Class JavaDoc klass) {
124                 return null;
125             }
126         };
127                 
128         // !PW This comment inherited from XMLDataObject. I'm not exactly sure what it means.
129
// EditorCookie.class must be synchronized with XMLEditor.Env->findCloneableOpenSupport
130
CookieSet cookies = getCookieSet();
131         cookies.add(EditorCookie.class, factory);
132         cookies.add(OpenCookie.class, factory);
133         cookies.add(CloseCookie.class, factory);
134         cookies.add(PrintCookie.class, factory);
135     }
136     
137     public HelpCtx getHelpCtx() {
138         return new HelpCtx(getPrimaryFile().getName()+"_help"); //NOI18N
139
}
140     
141     public boolean isRenameAllowed() {
142         return false;
143     }
144     
145     protected Node createNodeDelegate() {
146         return new ConfigDataNode(this);
147     }
148     
149     protected DataObject handleCopy(DataFolder f) throws IOException JavaDoc {
150         DataObject newDo = super.handleCopy(f);
151         try {
152             FileObject primary = newDo.getPrimaryFile();
153             newDo.setValid(false);
154             newDo = DataObject.find(primary);
155         } catch (java.beans.PropertyVetoException JavaDoc pve) {
156             //nothing
157
}
158         return newDo;
159     }
160
161     public SunONEDeploymentConfiguration getDeploymentConfiguration() throws ConfigurationException JavaDoc {
162         // Look up configuration bound to this object.
163
SunONEDeploymentConfiguration config = SunONEDeploymentConfiguration.getConfiguration(configKey);
164
165         if(config == null) {
166             // Request deployment configuration for SJSAS from j2eeserver module
167
FileObject configFO = FileUtil.toFileObject(configKey);
168             ConfigurationSupport.requestCreateConfiguration(configFO, SERVER_ID); // NOI18N
169
config = SunONEDeploymentConfiguration.getConfiguration(configKey);
170             if(config == null) {
171                 // If config is still null here, there is some kind of initialization
172
// problem (or bug).
173
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, new IllegalStateException JavaDoc(
174                         "Unable to initialize DeploymentConfiguration for " + configKey.getPath() + " on server " + SERVER_ID));
175             }
176         }
177
178         return config;
179     }
180     
181     /** This is really just "has sun-cmp-mappings.xml", but since this area is still
182      * written generally, this method is too.
183      */

184     public boolean hasSecondaries() {
185         return getSecondaries().size() > 0;
186     }
187     
188     protected void addSecondary(SecondaryConfigDataObject secondary) {
189         getSecondaries().add(secondary);
190     }
191     
192     protected void removeSecondary(SecondaryConfigDataObject secondary) {
193         getSecondaries().remove(secondary);
194     }
195     
196     protected Set JavaDoc getSecondaries() {
197         if (secondaries != null) {
198             return secondaries;
199         }
200         secondaries = new HashSet JavaDoc();
201         String JavaDoc [] paths = this.getProvider().getConfigSupport().getDeploymentConfigurationFileNames();
202         for (int i=0; i<paths.length; i++) {
203             File JavaDoc path = new File JavaDoc(paths[i]);
204             FileObject fo = getProvider().findDeploymentConfigurationFile(path.getName());
205             if (fo == null) {
206                 continue;
207             }
208             try {
209                 SecondaryConfigDataObject second = (SecondaryConfigDataObject) DataObject.find(fo);
210                 secondaries.add(second);
211             } catch (Exception JavaDoc ex) {
212                 continue;
213             }
214         }
215         return secondaries;
216     }
217     
218     protected boolean isConfigEditorOpened() {
219         Boolean JavaDoc result = (Boolean JavaDoc) Mutex.EVENT.readAccess(new Mutex.Action() {
220             public Object JavaDoc run() {
221                 ConfigBeanTopComponent configEditor = findOpenedConfigEditor();
222                 boolean isOpen = (configEditor != null) ? configEditor.isOpened() : false;
223                 return isOpen ? Boolean.TRUE : Boolean.FALSE;
224             }
225         });
226         return result.booleanValue();
227     }
228     
229     private OpenCookie _getOpenCookie() {
230         OpenCookie myOpen = getOpenCookie();
231         for (Iterator JavaDoc i=getSecondaries().iterator(); i.hasNext();) {
232             SecondaryConfigDataObject secondary = (SecondaryConfigDataObject) i.next();
233             if (secondary.getOpenCookie() == null) {
234                 return null;
235             }
236         }
237         return myOpen;
238     }
239     
240     protected OpenCookie getOpenCookie() {
241         // !PW Only enable configuration editor if SJSAS is the current target
242
// server.
243
if (!Utils.isSunServer(getProvider().getServerID())) {
244             return null;
245         }
246         if (!isEditedChecked) {
247             isEdited = checkIsEdited();
248         }
249         if (!isEdited) {
250             if (xmlOpenSupport == null) {
251                 xmlOpenSupport = new XMLOpenSupport(this);
252             }
253             return xmlOpenSupport;
254         } else {
255             return null;
256         }
257     }
258     
259     private EditCookie _getEditCookie() {
260         EditCookie myEdit = getEditCookie();
261         for (Iterator JavaDoc i=getSecondaries().iterator(); i.hasNext();) {
262             SecondaryConfigDataObject secondary = (SecondaryConfigDataObject) i.next();
263             if (secondary.getEditCookie() == null) {
264                 return null;
265             }
266         }
267         return myEdit;
268     }
269
270     protected EditCookie getEditCookie() {
271         if (!isConfigEditorOpened()) {
272             if (xmlEditorSupport == null) {
273                 xmlEditorSupport = new XMLEditorSupport(this);
274             }
275             return xmlEditorSupport;
276         } else {
277             return null;
278         }
279     }
280     
281     public org.openide.nodes.Node.Cookie getCookie(Class JavaDoc c) {
282         Node.Cookie retValue = null;
283         if (OpenCookie.class.isAssignableFrom(c)) {
284             return _getOpenCookie();
285         } else if (EditCookie.class.isAssignableFrom(c)
286                 || EditorCookie.class.isAssignableFrom(c)
287                 || CloseCookie.class.isAssignableFrom(c)
288                 || PrintCookie.class.isAssignableFrom(c)) {
289             return _getEditCookie();
290         } else if (ConfigurationStorage.class.isAssignableFrom(c)) {
291             retValue = getStorage();
292         } else if (ValidateXMLCookie.class.isAssignableFrom(c)) {
293             if (validateCookie == null) {
294                 InputSource JavaDoc in = DataObjectAdapters.inputSource(this);
295                 validateCookie = new ValidateXMLSupport(in);
296             }
297             return validateCookie;
298         } else if (CheckXMLCookie.class.isAssignableFrom(c)) {
299             if (checkCookie == null) {
300                 InputSource JavaDoc in = DataObjectAdapters.inputSource(this);
301                 checkCookie = new CheckXMLSupport(in);
302             }
303             return checkCookie;
304         }
305         
306         if (retValue == null) {
307             retValue = super.getCookie(c);
308         }
309         return retValue;
310     }
311     
312     private boolean checkIsEdited() {
313         if (xmlEditorSupport != null) {
314             isEditedChecked = true;
315             return (xmlEditorSupport.getOpenedPanes() != null);
316         }
317         return false;
318     }
319     
320     public void editorClosed(ConfigBeanTopComponent tc) {
321         if (xmlOpenSupport != null) {
322             xmlOpenSupport.reset();
323         }
324         
325         tc.reset();
326         fireCookieChange();
327     }
328     
329     protected J2eeModuleProvider getProvider() {
330         FileObject f = getPrimaryFile();
331         J2eeModuleProvider provider = null;
332         Project p = FileOwnerQuery.getOwner(f);
333         if (p != null) {
334             provider = (J2eeModuleProvider) p.getLookup().lookup(J2eeModuleProvider.class);
335         }
336         if (provider == null) {
337             throw new RuntimeException JavaDoc("Project " + p + " does not provide J2eeModuleProvider in its lookup"); // NOI18N
338
}
339         return provider;
340     }
341     
342     protected ConfigurationStorage getStorage() {
343         ConfigurationStorage storage = null;
344         
345         try {
346             SunONEDeploymentConfiguration config = getDeploymentConfiguration();
347             if(config != null) {
348                 storage = config.getStorage();
349             }
350         } catch (ConfigurationException JavaDoc ex) {
351             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
352         }
353         
354         return storage;
355     }
356     
357     public static FileObject getRelative(FileObject from, String JavaDoc path) throws IOException JavaDoc {
358         FileObject step = from;
359         //up
360
while (path.startsWith("..")) {
361             step = step.getParent();
362             path = path.substring(2);
363             if (path.startsWith("/")) {
364                 path = path.substring(1);
365             }
366         }
367         //down
368
if (path.length() > 0) {
369             step = step.getFileObject(path);
370         }
371         return step;
372     }
373     
374     public static String JavaDoc getRelativePath(FileObject from, FileObject to) {
375         String JavaDoc path = "";
376         //up
377
while (!FileUtil.isParentOf(from, to) || from.equals(to)) {
378             if (from.equals(to)) {
379                 break;
380             }
381             path = path + "../";
382             from = from.getParent();
383         }
384         //down
385
if (!from.equals(to)) {
386             path = path + FileUtil.getRelativePath(from, to);
387         }
388         return path;
389     }
390     
391     public void resetChanged() {
392         removeSaveCookie();
393     }
394     
395     public void removeEditorChanges() {
396         if (xmlEditorSupport != null) {
397             xmlEditorSupport.notifyUnmodified();
398         }
399     }
400     
401     public void removeAllEditorChanges() {
402         removeEditorChanges();
403         for (Iterator JavaDoc i = getSecondaries().iterator(); i.hasNext(); ) {
404             SecondaryConfigDataObject second = (SecondaryConfigDataObject) i.next();
405             second.removeEditorChanges();
406         }
407     }
408     
409     /** Check whether the data object or any of its secondary data objects are modified */
410     public boolean areModified() {
411         if (isModified()) {
412             return true;
413         }
414         for (Iterator JavaDoc i = getSecondaries().iterator(); i.hasNext(); ) {
415             SecondaryConfigDataObject second = (SecondaryConfigDataObject) i.next();
416             if (second.isModified()) {
417                 return true;
418             }
419         }
420         return false;
421     }
422     
423     
424     public void resetAllChanged() {
425         resetChanged();
426         for (Iterator JavaDoc i=getSecondaries().iterator(); i.hasNext();) {
427             SecondaryConfigDataObject second = (SecondaryConfigDataObject) i.next();
428             second.resetChanged();
429         }
430     }
431     
432     public void setChanged() {
433         addSaveCookie(new S());
434     }
435     
436     public boolean isModified() {
437         return super.isModified();
438     }
439     
440     private void handleReload(FileObject fo) throws IOException JavaDoc, InvalidModuleException JavaDoc, ConfigurationException JavaDoc {
441         ConfigurationStorage cs = getStorage();
442         if (cs != null && !cs.saveInProgress()) {
443             // check for reload
444
boolean doReload = true;
445             boolean doReopen = false;
446
447             if(isConfigEditorOpened()) {
448                 if(isModified()) {
449                     doReload = false;
450                     if(!reloadDialogOpened) {
451                         String JavaDoc message = NbBundle.getMessage(ConfigDataObject.class, "MSG_ExternalChange", fo.getName());
452                         NotifyDescriptor nd = new NotifyDescriptor.Confirmation(message, NotifyDescriptor.YES_NO_OPTION);
453                         reloadDialogOpened = true;
454
455                         try {
456                             Object JavaDoc ret = DialogDisplayer.getDefault().notify(nd);
457                             if(NotifyDescriptor.YES_OPTION.equals(ret)) {
458                                 resetChanged();
459                                 closeConfigEditors();
460                                 doReload = true;
461                                 doReopen = true;
462                             } else {
463                                 doReload = false;
464                             }
465                         } finally {
466                             reloadDialogOpened = false;
467                         }
468                     }
469                 } else {
470                     closeConfigEditors();
471                     doReopen = true;
472                 }
473             }
474
475             // reload configuration
476
if(doReload) {
477                 cs.load();
478             }
479
480             // restart config editor if necessary
481
if(doReopen) {
482                 Mutex.EVENT.readAccess(new Runnable JavaDoc() {
483                     public void run() {
484                         // reopen editor
485
OpenCookie opener = (OpenCookie) ConfigDataObject.this.getCookie(OpenCookie.class);
486                         if(opener != null) {
487                             opener.open();
488                         }
489                     }
490                 });
491             }
492         }
493     }
494     
495     public void fileAttributeChanged(org.openide.filesystems.FileAttributeEvent fe) {
496 // System.out.println("ConfigDataObject.fileAttributeChanged: " + fe);
497
}
498     
499     public void fileChanged(org.openide.filesystems.FileEvent fe) {
500 // System.out.println("ConfigDataObject.fileChanged: " + fe);
501
try {
502             if(isValid() && fe.getFile().equals(getPrimaryFile())) {
503                 handleReload(fe.getFile());
504             }
505         } catch (Exception JavaDoc e) {
506             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
507         }
508     }
509     
510     public void fileDataCreated(org.openide.filesystems.FileEvent fe) {
511 // System.out.println("ConfigDataObject.fileDataCreated: " + fe);
512
}
513     
514     public void fileDeleted(org.openide.filesystems.FileEvent fe) {
515 // System.out.println("ConfigDataObject.fileDeleted: " + fe);
516
}
517     
518     public void fileFolderCreated(org.openide.filesystems.FileEvent fe) {
519 // System.out.println("ConfigDataObject.fileFolderCreated: " + fe);
520
}
521     
522     public void fileRenamed(org.openide.filesystems.FileRenameEvent fe) {
523 // System.out.println("ConfigDataObject.fileRenamed: " + fe);
524
}
525     
526     protected void fireCookieChange() {
527         fireLimitedCookieChange();
528         for (Iterator JavaDoc i=getSecondaries().iterator(); i.hasNext();) {
529             SecondaryConfigDataObject secondary = (SecondaryConfigDataObject) i.next();
530             secondary.fireLimitedCookieChange();
531         }
532     }
533     
534     protected void fireLimitedCookieChange() {
535         firePropertyChange(PROP_COOKIE, null, null);
536     }
537     
538     private class S implements SaveCookie {
539         public void save() throws java.io.IOException JavaDoc {
540             // Do not clean up the editor's modified flags here, as there may have
541
// been an exception during save and if so, the flags are still correct.
542
// If the save is completed properly, the save code will remove the SaveCookie
543
// and clean up the flags for us.
544
ConfigurationStorage cs = getStorage();
545             if (cs != null) {
546                 cs.save();
547             }
548         }
549     }
550     
551     protected final void addSaveCookie(SaveCookie save) {
552         getCookieSet().add(save);
553         setModified(true);
554     }
555     
556     protected final void removeSaveCookie() {
557         SaveCookie sc = null;
558         while ((sc = (SaveCookie) getCookie(SaveCookie.class)) != null) {
559             getCookieSet().remove(sc);
560         }
561         this.setModified(false);
562     }
563     
564     private static class XMLOpenSupport extends DataEditorSupport implements OpenCookie, PropertyChangeListener JavaDoc {
565         
566         public XMLOpenSupport(ConfigDataObject obj) {
567             super(obj, new XMLEditorEnv(obj, OpenCookie.class));
568             setMIMEType("text/xml"); // NOI18N
569

570 // System.out.println("SunCfg GUI Open Support @ " + System.currentTimeMillis());
571
// Thread.currentThread().dumpStack();
572
}
573         
574         public void open() {
575             ConfigDataObject cdo = (ConfigDataObject) getDataObject();
576             cdo.addPropertyChangeListener(this);
577             cdo.getPrimaryFile().refresh(); //check for external changes
578
ConfigurationStorage configStorage = (ConfigurationStorage) cdo.getCookie(ConfigurationStorage.class);
579             if (configStorage == null) {
580                 EditCookie editor = (EditCookie) cdo.getCookie(EditCookie.class);
581                 if (editor != null) {
582                     editor.edit();
583                 }
584                 return;
585             }
586             
587 // calling super.open() causes the correct data structures to be created by the underlying
588
// DataEditorSupport & lower subclasses which fixes some bugs related to how the editor behaves
589
// when the underlying file/dataobject is deleted while the editor is open. However, it also
590
// creates some other more obnoxious bugs related to the fact that this code doesn't want
591
// DataEditorSupport performing some of the things it would otherwise do if these data structures
592
// are updated. Stay with old system for now while I investigate options.
593
// super.open();
594
cdo.openConfigEditor();
595         }
596         
597         protected CloneableTopComponent createCloneableTopComponent() {
598             ConfigDataObject cdo = (ConfigDataObject) getDataObject();
599             ConfigurationStorage storage = (ConfigurationStorage)
600                     cdo.getCookie(ConfigurationStorage.class);
601             return new ConfigBeanTopComponent(storage);
602         }
603         
604         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
605             if (DataObject.PROP_MODIFIED.equals(evt.getPropertyName())) {
606                 // mark/unmark editor as modified
607
final ConfigDataObject cdo = (ConfigDataObject) getDataObject();
608                 if(cdo.isValid()) {
609                     final ConfigurationStorage storage = cdo.getStorage();
610                     final String JavaDoc newDisplayName = messageName();
611                     Mutex.EVENT.readAccess(new Runnable JavaDoc() {
612                         public void run() {
613                             Iterator JavaDoc it = TopComponent.getRegistry().getOpened().iterator();
614                             while (it.hasNext()) {
615                                 TopComponent tc = (TopComponent) it.next();
616                                 if (tc instanceof ConfigBeanTopComponent) {
617                                     ConfigBeanTopComponent configEditor = (ConfigBeanTopComponent) tc;
618                                     if (configEditor.isFor(storage)) {
619                                         configEditor.setDisplayName(newDisplayName);
620                                     }
621                                 }
622                             }
623                         }
624                     });
625                 } else {
626 // System.out.println("Display name change for editor w/ invalid dataobject.");
627
}
628             }
629         }
630         
631         public void reset() {
632             ((ConfigDataObject)getDataObject()).removePropertyChangeListener(this);
633         }
634     }
635
636     protected void openConfigEditor() {
637         ConfigurationStorage storage = getStorage();
638         ConfigBeanTopComponent tc = findOpenedConfigEditor(storage);
639         if (tc == null) {
640             tc = new ConfigBeanTopComponent(storage);
641         }
642         
643         tc.open();
644         tc.requestActive();
645         fireCookieChange();
646     }
647     
648     /** will not open new one, can return null */
649     protected ConfigBeanTopComponent findOpenedConfigEditor() {
650         return findOpenedConfigEditor(getStorage());
651     }
652     
653     public static ConfigBeanTopComponent findOpenedConfigEditor(final ConfigurationStorage storage) {
654         // This code must run synchronously on the AWT thread, so issue blocking call.
655
// If this causes a deadlock, find a way not to call this method from a background
656
// thread or reimplement (which probably would involve cacheing the list of open
657
// editors and clones and clearing the cache as they are closed.
658
ConfigBeanTopComponent result = (ConfigBeanTopComponent) Mutex.EVENT.readAccess(new Mutex.Action() {
659             public Object JavaDoc run() {
660                 Iterator JavaDoc it = TopComponent.getRegistry().getOpened().iterator();
661                 while (it.hasNext()) {
662                     TopComponent tc = (TopComponent) it.next();
663                     if (tc instanceof ConfigBeanTopComponent) {
664                         ConfigBeanTopComponent beanTC = (ConfigBeanTopComponent) tc;
665                         if (beanTC.isFor(storage)) {
666                             return beanTC;
667                         }
668                     }
669                 }
670                 return null;
671             }
672         });
673         
674         return result;
675     }
676     
677 // private static class OpenEditorFinder implements Runnable {
678
//
679
// private ConfigurationStorage storage;
680
// private ConfigBeanTopComponent openEditor;
681
//
682
// public OpenEditorFinder(ConfigurationStorage storage) {
683
// this.storage = storage;
684
// this.openEditor = null;
685
// }
686
//
687
// public void run() {
688
// Iterator it = TopComponent.getRegistry().getOpened().iterator();
689
// while (it.hasNext()) {
690
// TopComponent tc = (TopComponent) it.next();
691
// if (tc instanceof ConfigBeanTopComponent) {
692
// ConfigBeanTopComponent beanTC = (ConfigBeanTopComponent) tc;
693
// if (beanTC.isFor(storage)) {
694
// openEditor = beanTC;
695
// break;
696
// }
697
// }
698
// }
699
// }
700
//
701
// public ConfigBeanTopComponent getOpenEditor() {
702
// return openEditor;
703
// }
704
// }
705

706     /** Closes all open config editors on this dataobject.
707      *
708      * @result true if the editors were all closed (or none were open). false if
709      * there was an open editor that failed to close.
710      */

711     public boolean closeConfigEditors() {
712         final ArrayList JavaDoc editorList = new ArrayList JavaDoc();
713         ConfigurationStorage storage = getStorage();
714         
715         // Can't close the editors as we find them or we'll get a ConcurrentModificationException.
716
Iterator JavaDoc iter = TopComponent.getRegistry().getOpened().iterator();
717         while(iter.hasNext()) {
718             Object JavaDoc tc = iter.next();
719             if(tc instanceof ConfigBeanTopComponent && ((ConfigBeanTopComponent) tc).isFor(storage)) {
720                 editorList.add(tc);
721             }
722         }
723         
724         Boolean JavaDoc result = (Boolean JavaDoc) Mutex.EVENT.readAccess(new Mutex.Action() {
725             public Object JavaDoc run() {
726                 Boolean JavaDoc result = Boolean.TRUE;
727                 Iterator JavaDoc iter = editorList.iterator();
728                 while(iter.hasNext()) {
729                     ConfigBeanTopComponent configTC = (ConfigBeanTopComponent) iter.next();
730                     result = (configTC.close() && result.booleanValue()) ? Boolean.TRUE : Boolean.FALSE;
731                 }
732                 return result;
733             }
734         });
735         
736         return result.booleanValue();
737     }
738
739     private static class XMLEditorSupport extends DataEditorSupport implements EditCookie, EditorCookie.Observable, PrintCookie, CloseCookie {
740         
741         public XMLEditorSupport(ConfigDataObject obj) {
742             super(obj, new XMLEditorEnv(obj, EditCookie.class));
743             setMIMEType("text/xml"); // NOI18N
744
// System.out.println("SunCfg XML Open Support @ " + System.currentTimeMillis());
745
// Thread.currentThread().dumpStack();
746
}
747         
748         protected boolean canClose() {
749             boolean result = super.canClose();
750             return result;
751         }
752         
753         class Save implements SaveCookie {
754             public void save() throws IOException JavaDoc {
755                 saveDocument();
756             }
757         }
758         
759         /* Save document using encoding declared in XML prolog if possible otherwise
760          * at UTF-8 (in such case it updates the prolog).
761          */

762         public void saveDocument() throws java.io.IOException JavaDoc {
763             final String JavaDoc defaultEncoding = "UTF8"; // NOI18N
764
final StyledDocument JavaDoc doc = getDocument();
765             String JavaDoc enc = EncodingUtil.detectEncoding(doc); // api in xml/core
766

767             if (enc == null) {
768                 enc = defaultEncoding;
769             }
770
771             try {
772                 //test encoding on dummy stream
773
new java.io.OutputStreamWriter JavaDoc(new java.io.ByteArrayOutputStream JavaDoc(1), enc);
774                 if(queryCanEncode(doc, enc)) {
775                     super.saveDocument();
776                     getDataObject().setModified(false);
777                 }
778             } catch(java.io.UnsupportedEncodingException JavaDoc ex) {
779                 if(queryUpdateProlog(doc, enc, defaultEncoding)) {
780                     super.saveDocument();
781                     getDataObject().setModified(false);
782                 }
783             }
784         }
785         
786         private boolean queryCanEncode(final StyledDocument JavaDoc doc, final String JavaDoc enc) {
787             boolean result = true;
788             // is it possible to save the document in the encoding?
789
try {
790                 java.nio.charset.CharsetEncoder JavaDoc coder = java.nio.charset.Charset.forName(enc).newEncoder();
791                 if(!coder.canEncode(doc.getText(0, doc.getLength()))){
792                     NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
793                             NbBundle.getMessage (XMLEditorSupport.class, "MSG_BadCharConversion", //NOI18N
794
new Object JavaDoc [] { getDataObject().getPrimaryFile().getNameExt(), enc}),
795                             NotifyDescriptor.YES_NO_OPTION,
796                             NotifyDescriptor.WARNING_MESSAGE);
797                     nd.setValue(NotifyDescriptor.NO_OPTION);
798                     DialogDisplayer.getDefault().notify(nd);
799                     
800                     if(nd.getValue() != NotifyDescriptor.YES_OPTION) {
801                         result = false;
802                     }
803                 }
804             } catch (javax.swing.text.BadLocationException JavaDoc e){
805                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
806             }
807             return result;
808         }
809         
810         private boolean queryUpdateProlog(final StyledDocument JavaDoc doc, final String JavaDoc enc, final String JavaDoc defaultEncoding) {
811             boolean needsSave = false;
812             
813             // ask user what next?
814
NotifyDescriptor nd = new NotifyDescriptor.Confirmation(
815                     NbBundle.getMessage(XMLEditorSupport.class, "MSG_BadEncodingDuringSave", //NOI18N
816
new Object JavaDoc [] { getDataObject().getPrimaryFile().getNameExt(), enc, defaultEncoding}),
817                     NotifyDescriptor.YES_NO_OPTION,
818                     NotifyDescriptor.WARNING_MESSAGE);
819             nd.setValue(NotifyDescriptor.NO_OPTION);
820             DialogDisplayer.getDefault().notify(nd);
821
822             if(nd.getValue() == NotifyDescriptor.YES_OPTION) {
823
824                 // update prolog to new valid encoding
825
try {
826                     final int MAX_PROLOG = 1000;
827                     int maxPrologLen = Math.min(MAX_PROLOG, doc.getLength());
828                     final char prolog[] = doc.getText(0, maxPrologLen).toCharArray();
829                     int prologLen = 0; // actual prolog length
830

831                     //parse prolog and get prolog end
832
if (prolog[0] == '<' && prolog[1] == '?' && prolog[2] == 'x') {
833
834                         // look for delimitting ?>
835
for (int i = 3; i<maxPrologLen; i++) {
836                             if (prolog[i] == '?' && prolog[i+1] == '>') {
837                                 prologLen = i + 1;
838                                 break;
839                             }
840                         }
841                     }
842
843                     final int passPrologLen = prologLen;
844                     
845                     Runnable JavaDoc edit = new Runnable JavaDoc() {
846                          public void run() {
847                              try {
848                                 doc.remove(0, passPrologLen + 1); // +1 it removes exclusive
849
doc.insertString(0, "<?xml version='1.0' encoding='" + defaultEncoding + "' ?> \n<!-- was: " + new String JavaDoc(prolog, 0, passPrologLen + 1) + " -->", null); // NOI18N
850
} catch (BadLocationException JavaDoc e) {
851                                  if (System.getProperty("netbeans.debug.exceptions") != null) { // NOI18N
852
e.printStackTrace();
853                                  }
854                              }
855                          }
856                     };
857
858                     NbDocument.runAtomic(doc, edit);
859                     
860                     // Mark for saving on return
861
needsSave = true;
862                 } catch (BadLocationException JavaDoc lex) {
863                     org.openide.ErrorManager.getDefault().notify(lex);
864                 }
865             }
866
867             return needsSave;
868         }
869
870 // In case we want to rely on java.io.UnsupportedEncodingException in saveDocument(), above.
871
//
872
// private boolean isSupportedEncoding(String encoding){
873
// boolean supported;
874
// try {
875
// supported = java.nio.charset.Charset.isSupported(encoding);
876
// } catch (java.nio.charset.IllegalCharsetNameException e){
877
// supported = false;
878
// }
879
// return supported;
880
// }
881

882         protected boolean notifyModified() {
883             if (! super.notifyModified()) {
884                 return false;
885             }
886             ((ConfigDataObject) getDataObject()).addSaveCookie(new Save());
887             return true;
888         }
889         
890         protected void notifyUnmodified() {
891             super.notifyUnmodified();
892             ((ConfigDataObject) getDataObject()).resetChanged();
893         }
894         
895         public void edit() {
896             ConfigDataObject cdo = (ConfigDataObject) getDataObject();
897             cdo.isEdited = true;
898             open();
899             cdo.fireCookieChange();
900         }
901         
902         protected void notifyClosed() {
903             super.notifyClosed();
904             ConfigDataObject cdo = (ConfigDataObject) getDataObject();
905             cdo.isEdited = false;
906             cdo.fireCookieChange();
907         }
908         
909         public void refreshDocument() {
910             super.reloadDocument();
911         }
912     }
913     
914     //!!! it also stays for SaveCookie however does not understand
915
// encoding declared in XML header => need to be rewritten.
916
private static class XMLEditorEnv extends DataEditorSupport.Env {
917         private static final long serialVersionUID = 6593415381104273008L;
918         
919         private final Class JavaDoc openSupportCookieClass;
920         
921         public XMLEditorEnv(ConfigDataObject dobj, Class JavaDoc cookieClass) {
922             super(dobj);
923             openSupportCookieClass = cookieClass;
924         }
925         protected FileObject getFile() {
926             return getDataObject().getPrimaryFile();
927         }
928         protected FileLock takeLock() throws IOException JavaDoc {
929             return ((ConfigDataObject) getDataObject()).getPrimaryEntry().takeLock();
930         }
931         public CloneableOpenSupport findCloneableOpenSupport() {
932             // must be sync with cookies.add(EditorCookie.class, factory);
933
// #12938 XML files do not persist in Source editor
934
return (CloneableOpenSupport) getDataObject().getCookie(openSupportCookieClass);
935         }
936     }
937 }
938
Popular Tags