View Javadoc
1   /*
2    * Copyright (c) 1999, 2011, 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.naming.internal;
27  
28  import java.util.List;
29  import javax.naming.NamingException;
30  
31  /**
32    * The FactoryEnumeration is used for returning factory instances.
33    *
34    * @author Rosanna Lee
35    * @author Scott Seligman
36   */
37  
38  // no need to implement Enumeration since this is only for internal use
39  public final class FactoryEnumeration {
40      // List<NamedWeakReference<Class | Object>>
41      private List<NamedWeakReference<Object>> factories;
42      private int posn = 0;
43      private ClassLoader loader;
44  
45      /**
46       * Records the input list and uses it directly to satisfy
47       * hasMore()/next() requests. An alternative would have been to use
48       * an enumeration/iterator from the list, but we want to update the
49       * list so we keep the
50       * original list. The list initially contains Class objects.
51       * As each element is used, the Class object is replaced by an
52       * instance of the Class itself; eventually, the list contains
53       * only a list of factory instances and no more updates are required.
54       *
55       * <p> Both Class objects and factories are wrapped in weak
56       * references so as not to prevent GC of the class loader.  Each
57       * weak reference is tagged with the factory's class name so the
58       * class can be reloaded if the reference is cleared.
59       *
60       * @param factories A non-null list
61       * @param loader    The class loader of the list's contents
62       *
63       * This internal method is used with Thread Context Class Loader (TCCL),
64       * please don't expose this method as public.
65       */
66      FactoryEnumeration(List<NamedWeakReference<Object>> factories,
67                         ClassLoader loader) {
68          this.factories = factories;
69          this.loader = loader;
70      }
71  
72      public Object next() throws NamingException {
73          synchronized (factories) {
74  
75              NamedWeakReference<Object> ref = factories.get(posn++);
76              Object answer = ref.get();
77              if ((answer != null) && !(answer instanceof Class)) {
78                  return answer;
79              }
80  
81              String className = ref.getName();
82  
83              try {
84                  if (answer == null) {   // reload class if weak ref cleared
85                      Class<?> cls = Class.forName(className, true, loader);
86                      answer = cls;
87                  }
88                  // Instantiate Class to get factory
89                  answer = ((Class) answer).newInstance();
90                  ref = new NamedWeakReference<>(answer, className);
91                  factories.set(posn-1, ref);  // replace Class object or null
92                  return answer;
93              } catch (ClassNotFoundException e) {
94                  NamingException ne =
95                      new NamingException("No longer able to load " + className);
96                  ne.setRootCause(e);
97                  throw ne;
98              } catch (InstantiationException e) {
99                  NamingException ne =
100                     new NamingException("Cannot instantiate " + answer);
101                 ne.setRootCause(e);
102                 throw ne;
103             } catch (IllegalAccessException e) {
104                 NamingException ne = new NamingException("Cannot access " + answer);
105                 ne.setRootCause(e);
106                 throw ne;
107             }
108         }
109     }
110 
111     public boolean hasMore() {
112         synchronized (factories) {
113             return posn < factories.size();
114         }
115     }
116 }