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, Community Edition. The Initial
 * Developer of the Original Code is Sun Microsystems, Inc. Portions
 * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.looks;

import java.util.*;
import java.lang.ref.WeakReference;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import org.netbeans.spi.looks.Look;

import org.netbeans.spi.looks.LookSelector;
import org.netbeans.spi.looks.LookProvider;
import org.netbeans.spi.looks.ChangeableLookProvider;
import org.netbeans.modules.looks.NamespaceLookProvider;
import org.openide.util.enum.*;

/** Factory for creating all kinds of selectors.
 *
 * @author Petr Hrebejk
 */
public abstract class SelectorImplFactory  {
    
    
    /** It's a static factory */
    private SelectorImplFactory() {}
    
    public static SelectorImpl provider( LookProvider provider ) {
        return new Impl( provider );
    }
        
    public static SelectorImpl singleton( Look delegate ) {
        return new Impl( delegate );
    }
    
    public static SelectorImpl array( Look delegates[] ) {
        return new Impl( delegates );
    }
        
    public static SelectorImpl changeableProvider( ChangeableLookProvider provider ) {
        return new Impl( provider );
    }
    
    public static SelectorImpl namespaceProvider( NamespaceLookProvider provider, String prefix ) {
        return new Impl( provider, null, prefix );
    }
            
    public static SelectorImpl decorator( LookSelector selector, Look look, boolean asLast, boolean excludable ) {        
        SelectorImpl si = Accessor.DEFAULT.getSelectorImpl( selector );         
        return new Impl( (Impl)si, look, asLast ? Boolean.TRUE : Boolean.FALSE );
    }
    
    public static SelectorImpl first( LookSelector selector ) {
        SelectorImpl si = Accessor.DEFAULT.getSelectorImpl( selector );
        return new Impl( (Impl)si );
    }

    public static SelectorImpl namespaceTypes( String prefix ) {
        return new Impl( null, prefix, true );
    }
    
    public static SelectorImpl namespaceTypes( RegistryBridge registryBridge, String prefix ) {
        return new Impl( registryBridge, prefix, true );
    }
    
    public static SelectorImpl context( RegistryBridge registryBridge, String contextName ) {
        return new Impl( registryBridge, contextName, false );
    }
        
    public static SelectorImpl composite( LookSelector selectors[], boolean removeDuplicates ) {
        Impl[] impls = new Impl[selectors.length];
        for ( int i = 0; i < selectors.length; i++ ) {
            impls[i] = (Impl)Accessor.DEFAULT.getSelectorImpl( selectors[i] );            
        }
        return new Impl( impls, removeDuplicates );
    }
    
    // Innerclasses  -----------------------------------------------------------    

    static class Impl implements SelectorImpl, ChangeListener, SelectorListener {
        
        // Types 
        
        // Fixed impls
        private static final int PROVIDER = 0;          // (LookProvider)
        private static final int SINGLETON = 1;         // (Look)
        private static final int ARRAY = 2;             // (Look[])
        private static final int DECORATOR_FIXED = 3;   // (LookSelector-Fixed, Look)
        private static final int COMPOSITE_FIXED = 4;   // (Impl[], boolean)
        private static final int FIRST_FIXED = 5;       // (LookSelector-Fixed, Look)
        
        // Changeable impls
        private static final int CHANGEABLE_PROVIDER = 100;  // (ChangeableProvider)
        private static final int NAMESPACE_PROVIDER = 101;   // (NamespaceProvider, Context) 
        private static final int NAMESPACE_TYPES = 102;      // (Context) - in context by type
        private static final int DECORATOR_CHANGEABLE = 103; // (LookSelctor-Changeable), Look )
        private static final int CONTEXT = 104;              // (Context) - all in context
        private static final int COMPOSITE_CHANGEABLE = 105; // (Impl[], boolean)
        private static final int FIRST_CHANGEABLE = 106;     // (LookSelector-Changeable, Look)
        
        // --- Extra indexes into arrays for various types of Impl
        private static final int DECORATOR_Selector = 0;
        private static final int DECORATOR_Look = 1;
        private static final int DECORATOR_AsLast = 2;
        private static final int DECORATOR_Cache = 3;
        
        private static final int NAMESPACE_PROVIDER_Provider = 0;
        private static final int NAMESPACE_PROVIDER_Prefix = 1;
        
        private static final int NAMESPACE_TYPES_Prefix = 0;
        private static final int CONTEXT_Prefix = NAMESPACE_TYPES_Prefix;
        private static final int NAMESPACE_TYPES_Listener = 1;
        private static final int CONTEXT_Listener = NAMESPACE_TYPES_Listener;
        
        private static final int COMPOSITE_Delegates = 0;
        private static final int COMPOSITE_RemoveDuplicates = 1;
                 
        private int type;                           // Type of the impl        
        private EventListenerList listeners;        // Listeners for changeable impls.        
        private LookSelector selector;              // Selector which uses this impl
        private HashMap looksCache;                 // Cached results for keys 
        
        private Object delegate;                    // Used impl types which delegate                
        private RegistryBridge rb;                  // Used in context based impls.
        
        // Constructrors -------------------------------------------------------
                
        // General constructor for all impls
        
        Impl( int type, boolean cache ) {
            this.type = type;
            
            if ( cache ) {
                this.looksCache = new HashMap();                
            }
        }
        
        // One constructor for each type of impl
        
        public Impl( LookProvider provider ) {
            this( PROVIDER, false );
            this.delegate = provider;
        }
        
        public Impl( Look look ) {
            this( SINGLETON, false );
            this.delegate = look;            
        }
        
        public Impl( Look looks[] ) {
            this( ARRAY, false );
            this.delegate = new Look[looks.length];            
            System.arraycopy( looks, 0, (Look[])this.delegate, 0, looks.length );
        }
        
        public Impl( Impl selectorImpl, Look look, Boolean asLast ) {
            this( selectorImpl.isFixed() ? DECORATOR_FIXED : DECORATOR_CHANGEABLE, 
                  selectorImpl.isFixed() ? false : true );
            this.delegate = new Object[] { selectorImpl, look, asLast, new HashMap() };                        
        }
        
        public Impl( Impl selectorImpl ) {
            this( selectorImpl.isFixed() ? FIRST_FIXED : FIRST_CHANGEABLE,
                  selectorImpl.isFixed() ? false : true );
            this.delegate = selectorImpl;
        }

        public Impl( ChangeableLookProvider provider ) {
            this( CHANGEABLE_PROVIDER, true );
            this.delegate = provider;
        }
        
        public Impl( NamespaceLookProvider provider, RegistryBridge bridge, String prefix ) {
            this( NAMESPACE_PROVIDER, true );
            this.delegate = new Object[]{ provider, prefix };
            this.rb = bridge == null ? RegistryBridge.getDefault( null ) : bridge;
        }
                
        public Impl( RegistryBridge bridge, String prefix, boolean isTypes ) {
            this( isTypes ? NAMESPACE_TYPES : CONTEXT , true );
            this.delegate = new Object[] { prefix, null };
            this.rb = bridge == null ? RegistryBridge.getDefault( null ) : bridge;
        }
        
        public Impl( Impl delegates[], boolean removeDuplicates ) {
            this( allFixed( delegates ) ? COMPOSITE_FIXED : COMPOSITE_CHANGEABLE , !allFixed( delegates ) );
            this.delegate = new Object[] { delegates, removeDuplicates ? Boolean.TRUE : Boolean.FALSE };            
        }
        
        // Implementation of SelectorImpl interface ----------------------------
        
        public synchronized void setLookSelector(LookSelector selector) throws TooManyListenersException {
            if ( this.selector == null ) {
                this.selector = selector;
            }
            else {
                throw new TooManyListenersException();
            }
        }
        
        public Enumeration getLooks(Object representedObject) {
            Object key = getKey4Object( representedObject );
                    
            if ( key == null ) {                    // No key means no looks
                return EmptyEnumeration.EMPTY;
            }            
            else if ( key == SelectorImpl.FIXED ) { // Means no caching
                return getLooks4Key( representedObject );         
            }
            else {                                  // Here we have to cache
                synchronized ( looksCache ) {
            
                    CacheItem ci = (CacheItem)looksCache.get( key );

                    if ( ci == null ) {
                        Enumeration e = getLooks4Key( key );                
                        ci = new CacheItem( e );
                        looksCache.put( key, ci );
                    }

                    return ci.getEnumeration();
                }
            }
        }
                
        public Object getKey4Object(Object representedObject) {
            switch( type ) {
                // Fixed impls
                case PROVIDER:
                case SINGLETON:
                case ARRAY:
                case COMPOSITE_FIXED:
                case DECORATOR_FIXED:
                case FIRST_FIXED:
                    return SelectorImpl.FIXED;
                    
                // Changeable impls    
                case CHANGEABLE_PROVIDER:
                    return ((ChangeableLookProvider)delegate).getKeyForObject( representedObject );
                case NAMESPACE_PROVIDER:
                    return ((NamespaceLookProvider)((Object[])delegate)[NAMESPACE_PROVIDER_Provider]).getKeyForObject( representedObject );
                case NAMESPACE_TYPES:
                    return representedObject.getClass();
                case CONTEXT:
                    return delegate;
                    
                // Extra cases
                    
                case DECORATOR_CHANGEABLE:
                    SelectorImpl si = (SelectorImpl)((Object[])delegate)[DECORATOR_Selector];
                    return si.getKey4Object( representedObject );
                case COMPOSITE_CHANGEABLE:
                    SelectorImpl sis[] = (SelectorImpl[])((Object[])delegate)[COMPOSITE_Delegates];                     
                    Object keys[] = new Object[ sis.length ];
                    for( int i = 0; i < sis.length; i++ ) {
                        Object key = sis[i].getKey4Object( representedObject );
                        keys[i] = key == SelectorImpl.FIXED ? representedObject : key;
                    }    
                    return keys;

                case FIRST_CHANGEABLE:
                    SelectorImpl si2 = (SelectorImpl)delegate;
                    return si2.getKey4Object( representedObject );

                default:
                    throw new IllegalStateException( "Unknown impl type " + type ); //NOI18N
                
            }
            
        }
                
        public Enumeration getLooks4Key(Object key) {
            switch( type ) {
                
                // Fixed impls - here key will be the represented object                
                case PROVIDER:
                    return ((LookProvider)delegate).getLooksForObject( key );
                case SINGLETON:
                    return new SingletonEnumeration( delegate );
                case ARRAY:
                    return new ArrayEnumeration( (Look[])delegate );
                
                    
                // Changeable impls
                case CHANGEABLE_PROVIDER:
                    return ((ChangeableLookProvider)delegate).getLooksForKey( key );
                case NAMESPACE_PROVIDER:
                    Enumeration names = ((NamespaceLookProvider)((Object[])delegate)[NAMESPACE_PROVIDER_Provider]).getNamesForKey( key );
                    return TypesSearch.findLooks ("", names, rb ); // NOI18N
                case NAMESPACE_TYPES:
                    names = TypesSearch.namesForClass( (Class)key );                    
                    return TypesSearch.findLooks ((String)((Object[])delegate)[NAMESPACE_TYPES_Prefix], names, rb ); 
                case CONTEXT:
                    String contextName = (String)((Object[])delegate)[CONTEXT_Prefix];
                    names = rb.getNames( contextName );
                    return TypesSearch.findLooks ( contextName + "/", names, rb ); // NOI18N
                    
                // Extra cases
                case DECORATOR_FIXED:
                case DECORATOR_CHANGEABLE:
                    SelectorImpl si = (SelectorImpl)((Object[])delegate)[DECORATOR_Selector];
                    Enumeration e = si.getLooks4Key( key );

                    return new AlterEnumeration( e ) {
                        public Object alter( Object object ) {
                    return decorateLook( (Look)object );
                    }
                };
                
                case COMPOSITE_FIXED:
                case COMPOSITE_CHANGEABLE:
                    SelectorImpl sis[] = (SelectorImpl[])((Object[])delegate)[COMPOSITE_Delegates];                     
                    boolean removeDups = ((Boolean)((Object[])delegate)[COMPOSITE_RemoveDuplicates]).booleanValue();                     
                    
                    Object keys[] = null;
                    if ( type == COMPOSITE_CHANGEABLE ) {
                        keys = (Object[])key; // Otherwise we have a rep. obj as a key;        
                    }
                    
                    //Object sk[][] = new Object[ sis.length ][2];
                    
                    List sk = new ArrayList();
                    for( int i = 0; i < sis.length; i++ ) {
                        if ( keys != null && keys[i] == null ) {
                            // if not fixed but key is null 
                            continue;
                        }
                        sk.add( new Object[] { sis[i], keys == null ? key : keys[i] } );
                    }

                    QueueEnumeration selEnum = new QueueEnumeration() {
                        protected void process( Object object ) {
                            if (object instanceof Object []) {
                                Object sk[] = (Object[])object;
                                Enumeration looksEnum = ((SelectorImpl)sk[0]).getLooks4Key( sk[1] );
                                put(Collections.list(looksEnum).toArray());
                            }
                        }
                    };                
                    selEnum.put(sk.toArray());
                    
                    Enumeration resEnum = new FilterEnumeration( selEnum ) {
                        protected boolean accept( Object o ) {
                            return o instanceof Look;
                        }
                    };
                    
                    return removeDups ? new RemoveDuplicatesEnumeration( resEnum ) : resEnum;

                case FIRST_FIXED:
                case FIRST_CHANGEABLE:
                    SelectorImpl si2 = (SelectorImpl)delegate;
                    Enumeration e2 = si2.getLooks4Key( key );

                    if (e2.hasMoreElements()) {
                        return new SingletonEnumeration(e2.nextElement());
                    } else {
                        return EmptyEnumeration.EMPTY;
                    }

                default:
                    throw new IllegalStateException( "Unknown impl type " + type ); //NOI18N
            }
        }
                
        public void addSelectorListener( SelectorListener listener) {
            if ( !isFixed() ) {
                if ( listeners == null) {
                    // Someone starts to listen in some cases we need to start 
                    // listening as well
                    
                    switch( type ) {
                        case CHANGEABLE_PROVIDER:
                            try {
                                ((ChangeableLookProvider)delegate).addChangeListener( this );   
                            }
                            catch ( TooManyListenersException e ) {
                                throw new IllegalStateException ( "Too many listeners on provider " + delegate );                                
                            }
                            break;
                        case NAMESPACE_PROVIDER:
                            try {
                                ((NamespaceLookProvider)((Object[])delegate)[NAMESPACE_PROVIDER_Provider]).addChangeListener( this );
                            }
                            catch ( TooManyListenersException e ) {
                                throw new IllegalStateException ( "Too many listeners on provider " + delegate );                                
                            }
                            break;
                        case DECORATOR_CHANGEABLE:
                            ((Impl)((Object[])delegate)[DECORATOR_Selector]).addSelectorListener( this );
                            break;
                        case NAMESPACE_TYPES:
                        case CONTEXT:
                            RbEventTranslator l = new RbEventTranslator();
                            rb.addListener( ((String)((Object[])delegate)[NAMESPACE_TYPES_Prefix]), l  );
                            ((Object[])delegate)[NAMESPACE_TYPES_Listener] = l;
                            break;                            
                        case COMPOSITE_CHANGEABLE:
                            // PENDING
                        default:
                            // Do nothing for other types
                    }
                    
                }
        
                synchronized ( Impl.class ) {
                    if (listeners == null) {
                        listeners = new EventListenerList ();
                    }            
                }
                listeners.add( SelectorListener.class, listener );
            }
        }
        
        public void removeSelectorListener( SelectorListener listener) {
            
            if ( !isFixed() ) {
                synchronized( Impl.class ) {
                    if (listeners != null) {
                        listeners.remove( SelectorListener.class, listener);
                    }
                }
        
                if ( listeners.getListenerCount() == 0 ) {
                    // Nobody listens so stop listeneing
                    switch( type ) {
                        case NAMESPACE_TYPES:
                        case CONTEXT:
                            rb.removeListener( (String)((Object[])delegate)[NAMESPACE_TYPES_Prefix],
                                               (RbEventTranslator)((Object[])delegate)[NAMESPACE_TYPES_Listener] );
                            break;
                        case DECORATOR_CHANGEABLE:
                            ((Impl)((Object[])delegate)[DECORATOR_Selector]).removeSelectorListener( this );
                            break;
                        case COMPOSITE_CHANGEABLE:
                            // PENDING
                        default:
                            // Do nothing for other types
                    }
                    // Delete the listeners list in order to recreate on new add
                    listeners = null;
                }
                               
            }
        }
        
        public HashMap getCache() {
            return looksCache;
        }
        
        
        // Implementation of change listener -----------------------------------
        
        public void stateChanged(javax.swing.event.ChangeEvent e) {
            fireChange( new SelectorEvent( selector ) );            
        }
        
        // Implementation of selector listener
        
        public void contentsChanged( SelectorEvent event ) {
            fireChange( new SelectorEvent( selector ) );
        }
        
        // Private methods -----------------------------------------------------
                
        
        private boolean isFixed() {
            return type < CHANGEABLE_PROVIDER;
        }
        
        private static boolean allFixed( Impl[] impls ) {
            for( int i = 0; i < impls.length; i++ ) {
                if ( !impls[i].isFixed() ) {
                    return false;
                }
            }
            return true;
        }
        
        protected void fireChange( SelectorEvent event ) {
            
            Object[] arr;
                        
            synchronized( this ) { // If something changed we need to reset thec cache
                if ( looksCache != null ) {
                    looksCache = new HashMap();
                }
            }
            
            synchronized( Impl.class ) {
               if (listeners == null) {
                   return;
               }
               arr = listeners.getListenerList();
            }

            if ( arr.length == 0 ) {
                return;
            }

            for (int i = arr.length - 1; i >= 0; i -= 2) {
                SelectorListener l = (SelectorListener)arr[i];
                l.contentsChanged( event );
            }            
        }
        
        
        /** Used in DECORATOR_FIXED and DECORATOR_CHANGEABLE
         */
        private Look decorateLook( Look original ) {
            
            HashMap decorationCache = (HashMap)((Object[])delegate)[DECORATOR_Cache];
            boolean asLast = ((Boolean)((Object[])delegate)[DECORATOR_AsLast]).booleanValue();
            Look decorator = (Look)((Object[])delegate)[DECORATOR_Look];
            
            synchronized ( decorationCache ) {
                WeakReference ref = (WeakReference) decorationCache.get( original );
                Look decoratedLook = ref == null ? null : (Look) ref.get();

                if ( decoratedLook == null ) {

                    // Compute the decorated look
                    decoratedLook = new CompositeLook(
                                            "Decorated[" + original.getName(),
                                             asLast ? new Look[] { original, decorator } :
                                                      new Look[] { decorator, original } );

                    /*
                    // Compute decorated selector if necessary
                    LookSelector decoratedSelector = LookNode.findLookSelector (original, null); 
                    if ( !excludable && decoratedSelector != null ) {
                        decoratedSelector = new DecoratorSelector ( decoratedSelector, look, asLast, false );
                    }

                    // Join
                    decoratedLook = Looks.childrenSelectorProvider( "Decorated[" + original.getName(),
                                                                 decoratedLook, decoratedSelector );
                    */
                    decorationCache.put( original, new WeakReference( decoratedLook ) );
                }
                return decoratedLook;
            }
        }
        
        
        private class RbEventTranslator extends RegistryBridge.Listener {
        
            public void selectorChanged() {
                Impl.this.fireChange( new SelectorEvent( selector ) );
            }
        
    }
                        
    }
    
    /** An item in the cache consist of list of already asked for Looks
     * and rest of the enumeration. This class is used in the SelectorEvent
     * class.
     */        
    static class CacheItem {

        private Enumeration enumeration;
        private List list;

        public CacheItem( Enumeration enumeration ) {
            this.enumeration = enumeration;
            list = new ArrayList();
        }

        /** Return enumeration which caches */
        public Enumeration getEnumeration() {
            return new CacheEnumeration( this );
        }

        public Object get( int index ) {
            if ( index >= list.size() ) {
                for( int i = list.size(); i <= index; i++ ) {

                    if ( !enumeration.hasMoreElements() ) {
                        return null;
                    }

                    list.add( enumeration.nextElement() );
                }
            }

            return list.get( index );
        }

        boolean has( int index ) {
            if ( index < list.size() ) {
                return true;
            }
            else if ( index == list.size() )  {
                return enumeration.hasMoreElements();                
            }
            else {
                return get( index + 1 ) != null;
            }
        }
        
        /** Returns looks in the cache 
         * @param all Should really all looks be returned (i.e. iterate through
         *            the enum or should we only return content of the list
         */
        Collection getCachedLooks( boolean all ) {
            List result = new ArrayList();
            if ( all ) {
                for( Enumeration e = getEnumeration(); e.hasMoreElements(); ) {
                    result.add( e.nextElement() );
                }
                
                
            }
            else {
                result.addAll( list );
            }
            
            return result;
        }
        
        
        /** Enumeration over the CacheItem. First iterates the List then the
         * enumaration and adds the items into the list
         */
        private static class CacheEnumeration implements Enumeration {

            private CacheItem cacheItem;
            int index;

            public CacheEnumeration( CacheItem cacheItem ) {
                this.cacheItem = cacheItem;
                index = -1;            
            }

            public boolean hasMoreElements() {
                return cacheItem.has( index + 1 );
            }

            public Object nextElement() {            
                return cacheItem.get( ++index );            
            }

        }

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

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 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.