KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > core > registry > ContextImpl


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.core.registry;
21
22 import org.netbeans.api.registry.*;
23 import org.netbeans.spi.registry.BasicContext;
24 import org.netbeans.spi.registry.ResettableContext;
25 import org.netbeans.spi.registry.SpiUtils;
26 import org.openide.ErrorManager;
27 import org.openide.filesystems.FileChangeListener;
28 import org.openide.filesystems.FileObject;
29 import org.openide.filesystems.FileStateInvalidException;
30 import org.openide.filesystems.FileSystem;
31 import org.openide.filesystems.FileUtil;
32 import org.openide.util.Mutex;
33
34 import javax.swing.event.EventListenerList JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.lang.ref.WeakReference JavaDoc;
37 import java.net.URL JavaDoc;
38 import java.util.*;
39
40 public class ContextImpl implements BasicContext{
41     /** Folder of the context */
42     private final FileObject folder;
43     
44     /** Event listener support */
45     private final EventListenerList JavaDoc listeners = new EventListenerList JavaDoc ();
46     
47     private static final String JavaDoc DEFAULT_SORTING = "default.context.sorting";
48     public static final String JavaDoc PRIMITIVE_BINDING_ATTR_PREFIX = "BINDINGATTR:";
49     
50     
51
52     /** Class wrapping bindings in this context.
53      */

54     private ContextBindings objectBindings;
55
56     /** Reference to root context of hierarchy to which this context belongs.
57      */

58     private final ContextImpl rootContext;
59
60     private final ContextCache contextCache;
61     /** FileChange listener registered on the Filesystem. It notifies
62      * root context and all its subcontexts about changes.
63      */

64     private FileChangeListener listener;
65     
66     
67     public ContextImpl (FileObject folder) {
68         this (folder, null);
69     }
70
71     ContextImpl(FileObject folder, ContextImpl rootContext) {
72         this.folder = folder;
73         if (rootContext != null) {
74             this.rootContext = rootContext;
75             contextCache = null;
76         } else {
77             this.rootContext = this;
78             contextCache = new ContextCache();
79             initialize();
80         }
81         // this method must be overriden on root context and cache all
82
// its descendant contexts
83
getContextCache().cacheContext(folder, this);
84     }
85
86     // install listeners
87
private void initialize() {
88         listener = new FileSystemListener(this);
89         try {
90             getFolder().getFileSystem().addFileChangeListener(FileUtil.weakFileChangeListener(
91                     listener, getFolder()));
92         } catch (FileStateInvalidException ex) {
93             RuntimeException JavaDoc e = new RuntimeException JavaDoc();
94             ErrorManager.getDefault().annotate(e, ex);
95             throw e;
96         }
97
98         // register this context for events about module/convertor enable/disable
99
StateUpdater.getDefault().registerRootContext(this);
100     }
101             
102     
103     public synchronized ContextBindings getContextBindings() {
104         if (objectBindings == null) {
105             objectBindings = ContextBindings.createContextBindings(folder, this);
106         }
107         return objectBindings;
108     }
109     
110     public FileObject getFolder() {
111         return folder;
112     }
113
114     ContextImpl getCtx(FileObject fo) {
115         // this method must be overriden on root context and must
116
// retrieve context if it already exists
117
ContextImpl ctx = getContextCache().retrieveContextFromCache(fo);
118         if (ctx == null) {
119             if (!fo.isFolder()) {
120                 throw new RuntimeException JavaDoc("Cannot create context for fileobject "+fo+". It must be folder.");
121             }
122             ctx = new ContextImpl(fo, getRootContextImpl());
123         }
124         return ctx;
125     }
126     
127     
128     private boolean isRoot() {
129         return getRootContextImpl() == this;
130     }
131
132     public BasicContext getRootContext() {
133         return getRootContextImpl();
134     }
135     
136     public String JavaDoc getContextName() {
137         if (isRoot()) {
138             return "/"; // NOI18N
139
}
140         return folder.getName();
141
142     }
143     
144     public BasicContext getParentContext() {
145         if (isRoot()) {
146             return null;
147         }
148         FileObject parent = folder.getParent();
149         if (parent != null) {
150             return getCtx(parent);
151         } else {
152             throw new RuntimeException JavaDoc("Cannot happen! File bug against openide/settings!!"); //NOI18N
153
}
154     }
155     
156     public BasicContext getSubcontext(String JavaDoc subcontextName) {
157         FileObject targetFolder = folder.getFileObject(subcontextName);
158         if (targetFolder == null || !targetFolder.isFolder()) {
159             return null;
160         }
161         return getCtx(targetFolder);
162     }
163     
164     public BasicContext createSubcontext(final String JavaDoc subcontextName) throws ContextException {
165         if (!isValidName(subcontextName)) {
166             throw SpiUtils.createContextException(this, "Cannot create subcontext with name '"+subcontextName+"'. It is invalid name."); //NOI18N
167
}
168         FileObject fo = folder.getFileObject(subcontextName);
169         if (fo != null && fo.isFolder ()) {
170             throw SpiUtils.createContextException(this, "Subcontext '"+subcontextName+"' already exist"); //NOI18N
171
}
172
173         try {
174             fo = folder.createFolder(subcontextName);
175         } catch (IOException JavaDoc ex) {
176             ContextException ce = SpiUtils.createContextException(this, "Error on underlaying filesystem occured.");
177             ErrorManager.getDefault().annotate(ce, ex);
178             throw ce;
179         }
180         return getCtx(fo);
181     }
182     
183     public void destroySubcontext(String JavaDoc subcontextName) throws ContextException {
184         final FileObject fo = folder.getFileObject(subcontextName);
185         if (fo == null || !fo.isFolder()) {
186             throw SpiUtils.createContextException(this, "Subcontext '"+subcontextName+"' does not exist."); //NOI18N
187
}
188
189         try {
190             fo.delete();
191         } catch (IOException JavaDoc ex) {
192             ContextException ce = SpiUtils.createContextException(this, "Error on underlaying filesystem occured.");
193             ErrorManager.getDefault().annotate(ce, ex);
194             throw ce;
195         }
196     }
197     
198     
199     // operation is blocking now
200
public void bindObject(final String JavaDoc name, final Object JavaDoc object) throws ContextException {
201         
202         // check name validity
203
if (!isValidName(name)) {
204             throw SpiUtils.createContextException(this, "Cannot bind object with name '"+name+"'. It is invalid binding name."); //NOI18N
205
}
206
207         getContextBindings().bindObject(name, object);
208     }
209     
210     public Object JavaDoc lookupObject(String JavaDoc name) throws ContextException {
211         Object JavaDoc value = getContextBindings().lookupObject(name);
212         return value;
213     }
214     
215     public String JavaDoc getAttribute(String JavaDoc bindingName, String JavaDoc attributeName) throws ContextException {
216         Object JavaDoc attr = null;
217         if (bindingName == null) {
218             attr = folder.getAttribute(attributeName);
219         } else {
220             FileObject fo = getContextBindings().getBindingFile(bindingName);
221             if (fo == null) {
222                 attr = folder.getAttribute(PRIMITIVE_BINDING_ATTR_PREFIX + bindingName + '/' + attributeName);
223             } else {
224                 attr = fo.getAttribute(attributeName);
225             }
226         }
227         
228         if (attr != null) {
229             if (attr instanceof String JavaDoc) {
230                 return (String JavaDoc)attr;
231             } else if (attr instanceof Long JavaDoc || attr instanceof Boolean JavaDoc ||
232                     attr instanceof Float JavaDoc || attr instanceof Integer JavaDoc) {
233                 return attr.toString();
234             } else if (attr instanceof URL JavaDoc) {
235                 return ((URL JavaDoc)attr).toExternalForm();
236             } else {
237                 throw SpiUtils.createContextException(this, "Type of attribute value is not not supported - "+attr.getClass().getName());
238             }
239         } else {
240             return null;
241         }
242     }
243     
244     public void setAttribute(String JavaDoc bindingName, String JavaDoc attributeName, final String JavaDoc value) throws ContextException {
245         if (bindingName != null && !isValidName(bindingName)) {
246             throw SpiUtils.createContextException(this, "Cannot set attribute for binding with name '"+bindingName+"'. It is invalid name."); //NOI18N
247
}
248         if (!isValidName(attributeName)) {
249             throw SpiUtils.createContextException(this, "Cannot set attribute with name '"+attributeName+"'. It is invalid name."); //NOI18N
250
}
251         FileObject fo;
252         if (bindingName == null) {
253             fo = folder;
254         } else {
255             if (!getContextBindings().existBinding(bindingName)) {
256                 throw SpiUtils.createContextException(this, "Cannot set attribute for non-existing binding (binding="+bindingName+" attribute="+attributeName+").");
257             }
258             // if the binding is primitive binding then its attribute have to
259
// be attached to folder, but is prefixed with binding name.
260
fo = getContextBindings().getBindingFile(bindingName);
261             if (fo == null) {
262                 fo = folder;
263                 attributeName = PRIMITIVE_BINDING_ATTR_PREFIX + bindingName + '/' + attributeName;
264             }
265         }
266         try {
267             fo.setAttribute(attributeName, value);
268         } catch (IOException JavaDoc ex) {
269             ContextException ce = SpiUtils.createContextException(this, "Error on underlaying filesystem occured.");
270             ErrorManager.getDefault().annotate(ce, ex);
271             throw ce;
272         }
273     }
274     
275     public final synchronized void addContextListener(ContextListener listener) {
276         listeners.add(ContextListener.class, listener);
277     }
278     
279     public final synchronized void removeContextListener(ContextListener listener) {
280         listeners.remove(ContextListener.class, listener);
281     }
282     
283     void fireAttributeEvent(final AttributeEvent ae) {
284         final Object JavaDoc[] l;
285         
286         synchronized (this) {
287             if (listeners.getListenerCount() == 0) {
288                 return;
289             }
290             l = listeners.getListenerList();
291         }
292         // this method must be override on root context and must
293
// return one mutex shared by all its descendant contexts
294
Context.getMutex().readAccess(new Runnable JavaDoc() {
295             public void run() {
296                 for (int i = l.length-2; i>=0; i-=2) {
297                     ((ContextListener)l[i+1]).attributeChanged(ae);
298                 }
299             }
300         });
301     }
302     
303     void fireBindingEvent(final BindingEvent be) {
304         final Object JavaDoc[] l;
305
306         synchronized (this) {
307             if (listeners.getListenerCount() == 0) {
308                 return;
309             }
310             l = listeners.getListenerList();
311         }
312         // this method must be override on root context and must
313
// return one mutex shared by all its descendant contexts
314
Context.getMutex().readAccess(new Runnable JavaDoc() {
315             public void run() {
316                 for (int i = l.length-2; i>=0; i-=2) {
317                     ((ContextListener)l[i+1]).bindingChanged(be);
318                 }
319             }
320         });
321     }
322     
323     void fireSubcontextEvent(final SubcontextEvent se) {
324         final Object JavaDoc[] l;
325
326         synchronized (this) {
327             if (listeners.getListenerCount() == 0) {
328                 return;
329             }
330             l = listeners.getListenerList();
331         }
332         // this method must be override on root context and must
333
// return one mutex shared by all its descendant contexts
334
Context.getMutex().readAccess(new Runnable JavaDoc() {
335             public void run() {
336                 for (int i = l.length-2; i>=0; i-=2) {
337                     ((ContextListener)l[i+1]).subcontextChanged(se);
338                 }
339             }
340         });
341     }
342     
343     
344     
345     private static boolean isValidName(String JavaDoc name) {
346         if (name.length() == 0 || name.indexOf('/') != -1) {
347             return false;
348         }
349         return true;
350     }
351
352     public String JavaDoc toString() {
353         return super.toString() + "[ctx="+getContextName()+", folder="+folder+"]";
354     }
355     
356     public java.util.Collection JavaDoc getAttributeNames(String JavaDoc bindingName) {
357         ArrayList list = new ArrayList();
358         if (bindingName == null) {
359             addAttrs(list, folder, null, PRIMITIVE_BINDING_ATTR_PREFIX);
360             if (!(list.contains(DEFAULT_SORTING))) {
361                 // #36156 - report DEFAULT_SORTING attribute always and
362
// not only for non-empty contexts
363
list.add(DEFAULT_SORTING);
364             }
365         } else {
366             FileObject fo = getContextBindings().getBindingFile(bindingName);
367             String JavaDoc attributePrefix = null;
368             if (fo == null) {
369                 fo = folder;
370                 attributePrefix = PRIMITIVE_BINDING_ATTR_PREFIX + bindingName + '/';
371             }
372             if (fo != null) {
373                 addAttrs(list, fo, attributePrefix, null);
374             }
375         }
376         return list;
377     }
378     
379     private static void addAttrs(ArrayList list, FileObject fo, String JavaDoc prefix, String JavaDoc ignore) {
380         Enumeration en = fo.getAttributes();
381         while (en.hasMoreElements()) {
382             String JavaDoc attrName = (String JavaDoc)en.nextElement();
383             
384             if (attrName.startsWith(ContextBindings.PRIMITIVE_BINDING_PREFIX)) {
385                 continue;
386             }
387             
388             if (ignore != null && attrName.startsWith(ignore)) {
389                 continue;
390             }
391
392 /*
393                 next condition was added as
394                 workaround for #16761, and this fo.getAttribute call
395                 brings performance problem and should be deleted.
396 */

397             if (fo.getAttribute(attrName) == null) continue;
398             
399             if (prefix != null) {
400                 if (!(attrName.startsWith(prefix))) {
401                     continue;
402                 } else {
403                     attrName = attrName.substring(prefix.length());
404                 }
405             }
406
407             list.add(attrName);
408         }
409     }
410
411     public java.util.Collection JavaDoc getBindingNames() {
412         return new HashSet(getContextBindings().getNames());
413     }
414     
415     public java.util.Collection JavaDoc getSubcontextNames() {
416         FileObject[] children = folder.getChildren();
417         ArrayList list = new ArrayList(children.length);
418         for (int i=0; i<children.length; i++) {
419             if (children[i].isFolder()) {
420                 list.add(children[i].getNameExt());
421             }
422         }
423         return list;
424     }
425
426
427     ContextCache getContextCache() {
428         return getRootContextImpl().contextCache;
429     }
430
431
432     ContextImpl getRootContextImpl() {
433         return rootContext;
434     }
435
436     static final class ContextCache {
437
438         /** Cache of the contexts. This property is initialized in root context
439          * and is just referenced from all descendant contexts.
440          */

441         WeakHashMap contextsCache;
442     
443     
444         private ContextCache() {
445         }
446     
447         // here are four methods defined on ContextImpl which
448
// must be properly override on rootcontext. all what ContextImpl
449
// impl does is that it delagates calls to its rootContext.
450

451         void cacheContext(FileObject folder, ContextImpl context) {
452             getContextsCache().put(folder, new WeakReference JavaDoc(context));
453         }
454     
455         public ContextImpl retrieveContextFromCache(FileObject folder) {
456             WeakReference JavaDoc ref = (WeakReference JavaDoc)getContextsCache().get(folder);
457             if (ref != null) {
458                 return (ContextImpl)ref.get();
459             } else {
460                 return null;
461             }
462         }
463         
464         // iterate all existing contexts and give them chance to update list of
465
// available bindings after convertors list has changed
466
void modulesChanged(Collection added, Collection removed) {
467             Iterator it = getContextsCache().values().iterator();
468             while (it.hasNext()) {
469                 WeakReference JavaDoc ref = (WeakReference JavaDoc)it.next();
470                 ContextImpl ctx = (ContextImpl)ref.get();
471                 if (ctx == null) {
472                     continue;
473                 }
474                 ctx.getContextBindings().modulesChanged(added, removed);
475             }
476         }
477
478
479         private synchronized WeakHashMap getContextsCache() {
480             if (contextsCache == null) {
481                 contextsCache = new WeakHashMap();
482             }
483             return contextsCache;
484         }
485     }
486     
487 }
488
Popular Tags