alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.nodes;

import java.util.*;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.EventListenerList;

/** Support class for storing cookies and
* retriving them by representation class.
* Provides simple notifications about changes
* in cookies.
*
* @author Jaroslav Tulach
*/
public final class CookieSet extends Object {
    /** variable to allow effecient communication with NodeLookup */
    private static ThreadLocal QUERY_MODE = new ThreadLocal ();
    
    /** list of cookies (Class, Node.Cookie) */
    private HashMap map = new HashMap (31);

    /** set of listeners */
    private EventListenerList listeners = new EventListenerList ();

    /** Default constructor. */
    public CookieSet() {}
    
    /** Add a new cookie to the set. If a cookie of the same
    * actual (not representation!) class is already there,
    * it is replaced.
    * 

Cookies inserted earlier are given preference during lookup, * in case a supplied representation class matches more than one cookie * in the set. * * @param cookie cookie to add */ public void add (Node.Cookie cookie) { synchronized (this) { registerCookie (cookie.getClass (), cookie); } fireChangeEvent (); } /** Remove a cookie from the set. * @param cookie the cookie to remove */ public void remove (Node.Cookie cookie) { synchronized (this) { unregisterCookie (cookie.getClass (), cookie); } fireChangeEvent (); } /** Get a cookie. * * @param clazz the representation class * @return a cookie assignable to the representation class, or null if there is none */ public Node.Cookie getCookie (Class clazz) { Node.Cookie ret = null; synchronized (this) { R r = findR (clazz); if (r == null) { return null; } ret = r.cookie (); } if (ret instanceof CookieEntry) { if (clazz == QUERY_MODE.get ()) { // we expected to be asked for this class // set cookie entry as a result QUERY_MODE.set (ret); ret = null; } else { // unwrap the cookie ret = ((CookieEntry) ret).getCookie(true); } } return ret; } /** Add a listener to changes in the cookie set. * @param l the listener to add */ public void addChangeListener (ChangeListener l) { listeners.add (ChangeListener.class, l); } /** Remove a listener to changes in the cookie set. * @param l the listener to remove */ public void removeChangeListener (ChangeListener l) { listeners.remove (ChangeListener.class, l); } /** Node lookup starts its non-important query. */ static Object entryQueryMode (Class c) { Object prev = QUERY_MODE.get (); QUERY_MODE.set (c); return prev; } /** Exits query mode. */ static org.openide.util.lookup.AbstractLookup.Pair exitQueryMode (Object prev) { Object cookie = QUERY_MODE.get (); QUERY_MODE.set (prev); if (cookie instanceof CookieSet.CookieEntry) { return new CookieEntryPair ((CookieSet.CookieEntry)cookie); } else { return null; } } /** Fires change event */ private void fireChangeEvent () { Object[] arr = listeners.getListenerList(); if (arr.length > 0) { ChangeEvent ev = null; // Process the listeners last to first, notifying // those that are interested in this event for (int i = arr.length-2; i>=0; i-=2) { if (arr[i] == ChangeListener.class) { if (ev == null) { ev = new ChangeEvent (this); } ((ChangeListener)arr[i + 1]).stateChanged (ev); } } } } /** Attaches cookie to given class and all its superclasses and * superinterfaces. * * @param c class or null * @param cookie cookie to attach */ private void registerCookie (Class c, Node.Cookie cookie) { if ((c == null) || !Node.Cookie.class.isAssignableFrom(c)) return; R r = findR (c); if (r == null) { r = new R (); map.put (c, r); } r.add (cookie); registerCookie (c.getSuperclass (), cookie); Class[] inter = c.getInterfaces (); for (int i = 0; i < inter.length; i++) { registerCookie (inter[i], cookie); } } /** Removes cookie from the class and all its superclasses and * superinterfaces. * * @param c class or null * @param cookie cookie to attach */ private void unregisterCookie (Class c, Node.Cookie cookie) { if ( c == null || !Node.Cookie.class.isAssignableFrom(c) ) return; // if different cookie is attached to class c stop removing R r = findR (c); if (r != null) { // remove the cookie r.remove (cookie); } unregisterCookie (c.getSuperclass (), cookie); Class[] inter = c.getInterfaces (); for (int i = 0; i < inter.length; i++) { unregisterCookie (inter[i], cookie); } } /** Registers a Factory for given cookie class */ public void add(Class cookieClass, Factory factory) { if (factory == null) { throw new IllegalArgumentException(); } synchronized (this) { registerCookie (cookieClass, new CookieEntry(factory, cookieClass)); } fireChangeEvent (); } /** Registers a Factory for given cookie classes */ public void add(Class[] cookieClass, Factory factory) { if (factory == null) { throw new IllegalArgumentException(); } synchronized (this) { for (int i = 0; i < cookieClass.length; i++) { registerCookie (cookieClass[i], new CookieEntry(factory, cookieClass[i])); } } fireChangeEvent (); } /** * Unregisters a Factory for given cookie class * @since 2.6 */ public void remove(Class cookieClass, Factory factory) { if (factory == null) { throw new IllegalArgumentException(); } synchronized (this) { R r = findR(cookieClass); if (r != null) { Node.Cookie c = r.cookie(); if (c instanceof CookieEntry) { CookieEntry ce = (CookieEntry)c; if (ce.factory == factory) { unregisterCookie (cookieClass, c); } } } } fireChangeEvent (); } /** * Unregisters a Factory for given cookie classes * @since 2.6 */ public void remove(Class[] cookieClass, Factory factory) { if (factory == null) { throw new IllegalArgumentException(); } synchronized (this) { for (int i = 0; i < cookieClass.length; i++) { R r = findR(cookieClass[i]); if (r != null) { Node.Cookie c = r.cookie(); if (c instanceof CookieEntry) { CookieEntry ce = (CookieEntry)c; if (ce.factory == factory) { unregisterCookie (cookieClass[i], c); } } } } } fireChangeEvent (); } /** Finds a result in a map. */ private R findR (Class c) { return (R)map.get (c); } /** Finds base class for a cookie. * @param c cookie * @return base class */ private static Class baseForCookie (Node.Cookie c) { if (c instanceof CookieEntry) { return ((CookieEntry)c).klass; } return c.getClass (); } /** Factory for creating cookies of given Class */ public static interface Factory { /** Creates a Node.Cookie of given class. The method * may be called more than once. */ public Node.Cookie createCookie(Class klass); } /** Entry for one Cookie */ private static class CookieEntry implements Node.Cookie { /** Factory for the cookie */ final Factory factory; /** Class of the cookie */ private final Class klass; /** A Referenec to the cookie */ private Reference cookie; /** Constructs new FactoryEntry */ public CookieEntry(Factory factory, Class klass) { this.factory = factory; this.klass = klass; } /** Getter for the cookie. * Synchronized because we don't want to run factory.createCookie * symultaneously from two threads. */ public synchronized Node.Cookie getCookie(boolean create) { Node.Cookie ret; if (create) { if ((cookie == null) || ((ret = (Node.Cookie) cookie.get()) == null)) { ret = factory.createCookie(klass); if (ret == null) return null; cookie = new WeakReference(ret); } } else { ret = (Node.Cookie) (cookie == null ? null : cookie.get ()); } return ret; } } // end of CookieEntry /** Pair that represents an entry. */ private static final class CookieEntryPair extends org.openide.util.lookup.AbstractLookup.Pair { private CookieEntry entry; public CookieEntryPair (CookieEntry e) { this.entry = e; } protected boolean creatorOf(Object obj) { return obj == entry.getCookie (false); } public String getDisplayName() { return getId (); } public String getId() { return entry.klass.getName (); } public Object getInstance() { return entry.getCookie (true); } public Class getType() { return entry.klass; } protected boolean instanceOf(Class c) { return c.isAssignableFrom(entry.klass); } public int hashCode () { return entry.hashCode () + 5; } public boolean equals (Object obj) { if (obj instanceof CookieEntryPair) { return ((CookieEntryPair)obj).entry == entry; } return false; } } // end of CookieEntryPair /** Implementation of the result. */ private static final class R extends Object { /** list of registered cookies */ public List cookies; /** base class of the first cookie registered here */ public Class base; R() {} /** Adds a cookie. * @return true if adding should continue on superclasses should continue */ public void add (Node.Cookie cookie) { if (cookies == null) { cookies = new ArrayList (1); cookies.add (cookie); base = baseForCookie (cookie); return; } Class newBase = baseForCookie (cookie); if (base == null || newBase.isAssignableFrom (base)) { cookies.set (0, cookie); base = newBase; } else { cookies.add (cookie); } } /** Removes a cookie. * @return true if empty */ public boolean remove (Node.Cookie cookie) { if (cookies == null) { return true; } if (cookies.remove (cookie) && cookies.size () == 0) { base = null; cookies = null; return true; } base = baseForCookie ((Node.Cookie)cookies.get (0)); return false; } /** @return the cookie for this result or null */ public Node.Cookie cookie () { return cookies == null || cookies.isEmpty () ? null : (Node.Cookie)cookies.get (0); } } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.