001    package org.apache.commons.ognl.internal;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    /*
023     * $Id: ClassCacheImpl.java 1194946 2011-10-29 17:47:02Z mcucchiara $
024     */
025    
026    import org.apache.commons.ognl.ClassCacheInspector;
027    
028    import java.util.Arrays;
029    
030    /**
031     * Implementation of {@link ClassCache}.
032     */
033    public class ClassCacheImpl<V>
034        implements ClassCache<V>
035    {
036    
037        /* this MUST be a power of 2 */
038        private static final int TABLE_SIZE = 512;
039    
040        /* ...and now you see why. The table size is used as a mask for generating hashes */
041        private static final int TABLE_SIZE_MASK = TABLE_SIZE - 1;
042    
043        private Entry<Class<?>, V>[] table = new Entry[TABLE_SIZE];
044    
045        private ClassCacheInspector classInspector;
046    
047        private int size = 0;
048    
049        /**
050         * {@inheritDoc}
051         */
052        public void setClassInspector( ClassCacheInspector inspector )
053        {
054            classInspector = inspector;
055        }
056    
057        /**
058         * {@inheritDoc}
059         */
060        public void clear()
061        {
062            for ( int i = 0; i < table.length; i++ )
063            {
064                table[i] = null;
065            }
066    
067            size = 0;
068        }
069    
070        /**
071         * {@inheritDoc}
072         */
073        public int getSize()
074        {
075            return size;
076        }
077    
078        /**
079         * {@inheritDoc}
080         */
081        public final V get( Class<?> key )
082            throws CacheException
083        {
084            int i = key.hashCode() & TABLE_SIZE_MASK;
085    
086            Entry<Class<?>, V> entry = table[i];
087    
088            while ( entry != null )
089            {
090                if ( key == entry.getKey() )
091                {
092                    return entry.getValue();
093                }
094    
095                entry = entry.getNext();
096            }
097            return null;
098        }
099    
100        /**
101         * {@inheritDoc}
102         */
103        public final V put( Class<?> key, V value )
104        {
105            if ( classInspector != null && !classInspector.shouldCache( key ) )
106            {
107                return value;
108            }
109    
110            V result = null;
111            int i = key.hashCode() & TABLE_SIZE_MASK;
112    
113            Entry<Class<?>, V> entry = table[i];
114    
115            if ( entry == null )
116            {
117                table[i] = new Entry<Class<?>, V>( key, value );
118                size++;
119            }
120            else
121            {
122                if ( key == entry.getKey() )
123                {
124                    result = entry.getValue();
125                    entry.setValue( value );
126                }
127                else
128                {
129                    while ( true )
130                    {
131                        if ( key == entry.getKey() )
132                        {
133                            /* replace value */
134                            result = entry.getValue();
135                            entry.setValue( value );
136                            break;
137                        }
138    
139                        if ( entry.getNext() == null )
140                        {
141                            /* add value */
142                            entry.setNext( new Entry<Class<?>, V>( key, value ) );
143                            break;
144                        }
145    
146                        entry = entry.getNext();
147                    }
148                }
149            }
150    
151            return result;
152        }
153    
154        /**
155         * {@inheritDoc}
156         */
157        @Override
158        public String toString()
159        {
160            return "ClassCacheImpl[" + "_table=" + ( table == null ? null : Arrays.asList( table ) ) + '\n'
161                + ", _classInspector=" + classInspector + '\n' + ", _size=" + size + '\n' + ']';
162        }
163    
164    }