1 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 ; 35 import java.io.IOException ; 36 import java.lang.ref.WeakReference ; 37 import java.net.URL ; 38 import java.util.*; 39 40 public class ContextImpl implements BasicContext{ 41 42 private final FileObject folder; 43 44 45 private final EventListenerList listeners = new EventListenerList (); 46 47 private static final String DEFAULT_SORTING = "default.context.sorting"; 48 public static final String PRIMITIVE_BINDING_ATTR_PREFIX = "BINDINGATTR:"; 49 50 51 52 54 private ContextBindings objectBindings; 55 56 58 private final ContextImpl rootContext; 59 60 private final ContextCache contextCache; 61 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 getContextCache().cacheContext(folder, this); 84 } 85 86 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 e = new RuntimeException (); 94 ErrorManager.getDefault().annotate(e, ex); 95 throw e; 96 } 97 98 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 ContextImpl ctx = getContextCache().retrieveContextFromCache(fo); 118 if (ctx == null) { 119 if (!fo.isFolder()) { 120 throw new RuntimeException ("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 getContextName() { 137 if (isRoot()) { 138 return "/"; } 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 ("Cannot happen! File bug against openide/settings!!"); } 154 } 155 156 public BasicContext getSubcontext(String 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 subcontextName) throws ContextException { 165 if (!isValidName(subcontextName)) { 166 throw SpiUtils.createContextException(this, "Cannot create subcontext with name '"+subcontextName+"'. It is invalid name."); } 168 FileObject fo = folder.getFileObject(subcontextName); 169 if (fo != null && fo.isFolder ()) { 170 throw SpiUtils.createContextException(this, "Subcontext '"+subcontextName+"' already exist"); } 172 173 try { 174 fo = folder.createFolder(subcontextName); 175 } catch (IOException 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 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."); } 188 189 try { 190 fo.delete(); 191 } catch (IOException 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 public void bindObject(final String name, final Object object) throws ContextException { 201 202 if (!isValidName(name)) { 204 throw SpiUtils.createContextException(this, "Cannot bind object with name '"+name+"'. It is invalid binding name."); } 206 207 getContextBindings().bindObject(name, object); 208 } 209 210 public Object lookupObject(String name) throws ContextException { 211 Object value = getContextBindings().lookupObject(name); 212 return value; 213 } 214 215 public String getAttribute(String bindingName, String attributeName) throws ContextException { 216 Object 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 ) { 230 return (String )attr; 231 } else if (attr instanceof Long || attr instanceof Boolean || 232 attr instanceof Float || attr instanceof Integer ) { 233 return attr.toString(); 234 } else if (attr instanceof URL ) { 235 return ((URL )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 bindingName, String attributeName, final String 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."); } 248 if (!isValidName(attributeName)) { 249 throw SpiUtils.createContextException(this, "Cannot set attribute with name '"+attributeName+"'. It is invalid name."); } 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 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 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 [] l; 285 286 synchronized (this) { 287 if (listeners.getListenerCount() == 0) { 288 return; 289 } 290 l = listeners.getListenerList(); 291 } 292 Context.getMutex().readAccess(new Runnable () { 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 [] l; 305 306 synchronized (this) { 307 if (listeners.getListenerCount() == 0) { 308 return; 309 } 310 l = listeners.getListenerList(); 311 } 312 Context.getMutex().readAccess(new Runnable () { 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 [] l; 325 326 synchronized (this) { 327 if (listeners.getListenerCount() == 0) { 328 return; 329 } 330 l = listeners.getListenerList(); 331 } 332 Context.getMutex().readAccess(new Runnable () { 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 name) { 346 if (name.length() == 0 || name.indexOf('/') != -1) { 347 return false; 348 } 349 return true; 350 } 351 352 public String toString() { 353 return super.toString() + "[ctx="+getContextName()+", folder="+folder+"]"; 354 } 355 356 public java.util.Collection getAttributeNames(String 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 list.add(DEFAULT_SORTING); 364 } 365 } else { 366 FileObject fo = getContextBindings().getBindingFile(bindingName); 367 String 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 prefix, String ignore) { 380 Enumeration en = fo.getAttributes(); 381 while (en.hasMoreElements()) { 382 String attrName = (String )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 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 getBindingNames() { 412 return new HashSet(getContextBindings().getNames()); 413 } 414 415 public java.util.Collection 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 441 WeakHashMap contextsCache; 442 443 444 private ContextCache() { 445 } 446 447 451 void cacheContext(FileObject folder, ContextImpl context) { 452 getContextsCache().put(folder, new WeakReference (context)); 453 } 454 455 public ContextImpl retrieveContextFromCache(FileObject folder) { 456 WeakReference ref = (WeakReference )getContextsCache().get(folder); 457 if (ref != null) { 458 return (ContextImpl)ref.get(); 459 } else { 460 return null; 461 } 462 } 463 464 void modulesChanged(Collection added, Collection removed) { 467 Iterator it = getContextsCache().values().iterator(); 468 while (it.hasNext()) { 469 WeakReference ref = (WeakReference )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 |