1 /*
   2  * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.corba.se.impl.interceptors;
  27 
  28 import org.omg.PortableInterceptor.Interceptor;
  29 import org.omg.PortableInterceptor.ORBInitInfo;
  30 import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName;
  31 
  32 import org.omg.CORBA.INTERNAL;
  33 
  34 import java.util.ArrayList;
  35 import java.util.Collection;
  36 import java.util.Collections;
  37 import java.util.Iterator;
  38 import java.util.List;
  39 import java.lang.reflect.Array;
  40 
  41 import com.sun.corba.se.impl.logging.InterceptorsSystemException ;
  42 
  43 /**
  44  * Provides a repository of registered Portable Interceptors, organized
  45  * by type.  This list is designed to be accessed as efficiently as
  46  * possible during runtime, with the expense of added complexity during
  47  * initialization and interceptor registration.  The class is designed
  48  * to easily allow for the addition of new interceptor types.
  49  */
  50 public class InterceptorList {
  51 
  52     // Interceptor type list.  If additional interceptors are needed,
  53     // add additional types in numerical order (do not skip numbers),
  54     // and update NUM_INTERCEPTOR_TYPES and classTypes accordingly.
  55     // NUM_INTERCEPTOR_TYPES represents the number of interceptor
  56     // types, so we know how many lists to maintain.
  57     static final int INTERCEPTOR_TYPE_CLIENT            = 0;
  58     static final int INTERCEPTOR_TYPE_SERVER            = 1;
  59     static final int INTERCEPTOR_TYPE_IOR               = 2;
  60 
  61     static final int NUM_INTERCEPTOR_TYPES              = 3;
  62 
  63     // Array of class types for interceptors.  This is used to create the
  64     // appropriate array type for each interceptor type.  These must
  65     // match the indices of the constants declared above.
  66     static final Class[] classTypes = {
  67         org.omg.PortableInterceptor.ClientRequestInterceptor.class,
  68         org.omg.PortableInterceptor.ServerRequestInterceptor.class,
  69         org.omg.PortableInterceptor.IORInterceptor.class
  70     };
  71 
  72     // True if no further interceptors may be registered with this list.
  73     private boolean locked = false;
  74     private InterceptorsSystemException wrapper ;
  75 
  76     // List of interceptors currently registered.  There are
  77     // NUM_INTERCEPTOR_TYPES lists of registered interceptors.
  78     // For example, interceptors[INTERCEPTOR_TYPE_CLIENT] contains an array
  79     // of objects of type ClientRequestInterceptor.
  80     private Interceptor[][] interceptors =
  81         new Interceptor[NUM_INTERCEPTOR_TYPES][];
  82 
  83     /**
  84      * Creates a new Interceptor List.  Constructor is package scope so
  85      * only the ORB can create it.
  86      */
  87     InterceptorList( InterceptorsSystemException wrapper ) {
  88         this.wrapper = wrapper ;
  89         // Create empty interceptors arrays for each type:
  90         initInterceptorArrays();
  91     }
  92 
  93     /**
  94      * Registers an interceptor of the given type into the interceptor list.
  95      * The type is one of:
  96      * <ul>
  97      *   <li>INTERCEPTOR_TYPE_CLIENT - ClientRequestInterceptor
  98      *   <li>INTERCEPTOR_TYPE_SERVER - ServerRequestInterceptor
  99      *   <li>INTERCEPTOR_TYPE_IOR - IORInterceptor
 100      * </ul>
 101      *
 102      * @exception DuplicateName Thrown if an interceptor of the given
 103      *     name already exists for the given type.
 104      */
 105     void register_interceptor( Interceptor interceptor, int type )
 106         throws DuplicateName
 107     {
 108         // If locked, deny any further addition of interceptors.
 109         if( locked ) {
 110             throw wrapper.interceptorListLocked() ;
 111         }
 112 
 113         // Cache interceptor name:
 114         String interceptorName = interceptor.name();
 115         boolean anonymous = interceptorName.equals( "" );
 116         boolean foundDuplicate = false;
 117         Interceptor[] interceptorList = interceptors[type];
 118 
 119         // If this is not an anonymous interceptor,
 120         // search for an interceptor of the same name in this category:
 121         if( !anonymous ) {
 122             int size = interceptorList.length;
 123 
 124             // An O(n) search will suffice because register_interceptor is not
 125             // likely to be called often.
 126             for( int i = 0; i < size; i++ ) {
 127                 Interceptor in = (Interceptor)interceptorList[i];
 128                 if( in.name().equals( interceptorName ) ) {
 129                     foundDuplicate = true;
 130                     break;
 131                 }
 132             }
 133         }
 134 
 135         if( !foundDuplicate ) {
 136             growInterceptorArray( type );
 137             interceptors[type][interceptors[type].length-1] = interceptor;
 138         }
 139         else {
 140             throw new DuplicateName( interceptorName );
 141         }
 142     }
 143 
 144     /**
 145      * Locks this interceptor list so that no more interceptors may be
 146      * registered.  This method is called after all interceptors are
 147      * registered for security reasons.
 148      */
 149     void lock() {
 150         locked = true;
 151     }
 152 
 153     /**
 154      * Retrieves an array of interceptors of the given type.  For efficiency,
 155      * the type parameter is assumed to be valid.
 156      */
 157     Interceptor[] getInterceptors( int type ) {
 158         return interceptors[type];
 159     }
 160 
 161     /**
 162      * Returns true if there is at least one interceptor of the given type,
 163      * or false if not.
 164      */
 165     boolean hasInterceptorsOfType( int type ) {
 166         return interceptors[type].length > 0;
 167     }
 168 
 169     /**
 170      * Initializes all interceptors arrays to zero-length arrays of the
 171      * correct type, based on the classTypes list.
 172      */
 173     private void initInterceptorArrays() {
 174         for( int type = 0; type < NUM_INTERCEPTOR_TYPES; type++ ) {
 175             Class classType = classTypes[type];
 176 
 177             // Create a zero-length array for each type:
 178             interceptors[type] =
 179                 (Interceptor[])Array.newInstance( classType, 0 );
 180         }
 181     }
 182 
 183     /**
 184      * Grows the given interceptor array by one:
 185      */
 186     private void growInterceptorArray( int type ) {
 187         Class classType = classTypes[type];
 188         int currentLength = interceptors[type].length;
 189         Interceptor[] replacementArray;
 190 
 191         // Create new array to replace the old one.  The new array will be
 192         // one element larger but have the same type as the old one.
 193         replacementArray = (Interceptor[])
 194             Array.newInstance( classType, currentLength + 1 );
 195         System.arraycopy( interceptors[type], 0,
 196                           replacementArray, 0, currentLength );
 197         interceptors[type] = replacementArray;
 198     }
 199 
 200     /**
 201      * Destroys all interceptors in this list by invoking their destroy()
 202      * method.
 203      */
 204     void destroyAll() {
 205         int numTypes = interceptors.length;
 206 
 207         for( int i = 0; i < numTypes; i++ ) {
 208             int numInterceptors = interceptors[i].length;
 209             for( int j = 0; j < numInterceptors; j++ ) {
 210                 interceptors[i][j].destroy();
 211             }
 212         }
 213     }
 214 
 215     /**
 216      * Sort interceptors.
 217      */
 218     void sortInterceptors() {
 219         List sorted = null;
 220         List unsorted = null;
 221 
 222         int numTypes = interceptors.length;
 223 
 224         for( int i = 0; i < numTypes; i++ ) {
 225             int numInterceptors = interceptors[i].length;
 226             if (numInterceptors > 0) {
 227                 // Get fresh sorting bins for each non empty type.
 228                 sorted = new ArrayList(); // not synchronized like we want.
 229                 unsorted = new ArrayList();
 230             }
 231             for( int j = 0; j < numInterceptors; j++ ) {
 232                 Interceptor interceptor = interceptors[i][j];
 233                 if (interceptor instanceof Comparable) {
 234                     sorted.add(interceptor);
 235                 } else {
 236                     unsorted.add(interceptor);
 237                 }
 238             }
 239             if (numInterceptors > 0 && sorted.size() > 0) {
 240                 // Let the RuntimeExceptions thrown by sort
 241                 // (i.e., ClassCastException and UnsupportedOperationException)
 242                 // flow back to the user.
 243                 Collections.sort(sorted);
 244                 Iterator sortedIterator = sorted.iterator();
 245                 Iterator unsortedIterator = unsorted.iterator();
 246                 for( int j = 0; j < numInterceptors; j++ ) {
 247                     if (sortedIterator.hasNext()) {
 248                         interceptors[i][j] =
 249                             (Interceptor) sortedIterator.next();
 250                     } else if (unsortedIterator.hasNext()) {
 251                         interceptors[i][j] =
 252                             (Interceptor) unsortedIterator.next();
 253                     } else {
 254                         throw wrapper.sortSizeMismatch() ;
 255                     }
 256                 }
 257             }
 258         }
 259     }
 260 }