1 /* 2 * Copyright (c) 1999, 2013, 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 package com.sun.jndi.toolkit.dir; 26 27 import javax.naming.*; 28 import javax.naming.directory.SearchControls; 29 import java.util.*; 30 31 /** 32 * A class for recursively enumerating the contents of a Context; 33 * 34 * @author Jon Ruiz 35 */ 36 public class ContextEnumerator implements NamingEnumeration<Binding> { 37 38 private static boolean debug = false; 39 private NamingEnumeration<Binding> children = null; 40 private Binding currentChild = null; 41 private boolean currentReturned = false; 42 private Context root; 43 private ContextEnumerator currentChildEnum = null; 44 private boolean currentChildExpanded = false; 45 private boolean rootProcessed = false; 46 private int scope = SearchControls.SUBTREE_SCOPE; 47 private String contextName = ""; 48 49 public ContextEnumerator(Context context) throws NamingException { 50 this(context, SearchControls.SUBTREE_SCOPE); 51 } 52 53 public ContextEnumerator(Context context, int scope) 54 throws NamingException { 55 // return this object except when searching single-level 56 this(context, scope, "", scope != SearchControls.ONELEVEL_SCOPE); 57 } 58 59 protected ContextEnumerator(Context context, int scope, String contextName, 60 boolean returnSelf) 61 throws NamingException { 62 if(context == null) { 63 throw new IllegalArgumentException("null context passed"); 64 } 65 66 root = context; 67 68 // No need to list children if we're only searching object 69 if (scope != SearchControls.OBJECT_SCOPE) { 70 children = getImmediateChildren(context); 71 } 72 this.scope = scope; 73 this.contextName = contextName; 74 // pretend root is processed, if we're not supposed to return ourself 75 rootProcessed = !returnSelf; 76 prepNextChild(); 77 } 78 79 // Subclass should override if it wants to avoid calling obj factory 80 protected NamingEnumeration<Binding> getImmediateChildren(Context ctx) 81 throws NamingException { 82 return ctx.listBindings(""); 83 } 84 85 // Subclass should override so that instance is of same type as subclass 86 protected ContextEnumerator newEnumerator(Context ctx, int scope, 87 String contextName, boolean returnSelf) throws NamingException { 88 return new ContextEnumerator(ctx, scope, contextName, returnSelf); 89 } 90 91 public boolean hasMore() throws NamingException { 92 return !rootProcessed || 93 (scope != SearchControls.OBJECT_SCOPE && hasMoreDescendants()); 94 } 95 96 public boolean hasMoreElements() { 97 try { 98 return hasMore(); 99 } catch (NamingException e) { 100 return false; 101 } 102 } 103 104 public Binding nextElement() { 105 try { 106 return next(); 107 } catch (NamingException e) { 108 throw new NoSuchElementException(e.toString()); 109 } 110 } 111 112 public Binding next() throws NamingException { 113 if (!rootProcessed) { 114 rootProcessed = true; 115 return new Binding("", root.getClass().getName(), 116 root, true); 117 } 118 119 if (scope != SearchControls.OBJECT_SCOPE && hasMoreDescendants()) { 120 return getNextDescendant(); 121 } 122 123 throw new NoSuchElementException(); 124 } 125 126 public void close() throws NamingException { 127 root = null; 128 } 129 130 private boolean hasMoreChildren() throws NamingException { 131 return children != null && children.hasMore(); 132 } 133 134 private Binding getNextChild() throws NamingException { 135 Binding oldBinding = children.next(); 136 Binding newBinding = null; 137 138 // if the name is relative, we need to add it to the name of this 139 // context to keep it relative w.r.t. the root context we are 140 // enumerating 141 if(oldBinding.isRelative() && !contextName.equals("")) { 142 NameParser parser = root.getNameParser(""); 143 Name newName = parser.parse(contextName); 144 newName.add(oldBinding.getName()); 145 if(debug) { 146 System.out.println("ContextEnumerator: adding " + newName); 147 } 148 newBinding = new Binding(newName.toString(), 149 oldBinding.getClassName(), 150 oldBinding.getObject(), 151 oldBinding.isRelative()); 152 } else { 153 if(debug) { 154 System.out.println("ContextEnumerator: using old binding"); 155 } 156 newBinding = oldBinding; 157 } 158 159 return newBinding; 160 } 161 162 private boolean hasMoreDescendants() throws NamingException { 163 // if the current child is expanded, see if it has more elements 164 if (!currentReturned) { 165 if(debug) {System.out.println("hasMoreDescendants returning " + 166 (currentChild != null) ); } 167 return currentChild != null; 168 } else if (currentChildExpanded && currentChildEnum.hasMore()) { 169 170 if(debug) {System.out.println("hasMoreDescendants returning " + 171 "true");} 172 173 return true; 174 } else { 175 if(debug) {System.out.println("hasMoreDescendants returning " + 176 "hasMoreChildren");} 177 return hasMoreChildren(); 178 } 179 } 180 181 private Binding getNextDescendant() throws NamingException { 182 183 if (!currentReturned) { 184 // returning parent 185 if(debug) {System.out.println("getNextDescendant: simple case");} 186 187 currentReturned = true; 188 return currentChild; 189 190 } else if (currentChildExpanded && currentChildEnum.hasMore()) { 191 192 if(debug) {System.out.println("getNextDescendant: expanded case");} 193 194 // if the current child is expanded, use it's enumerator 195 return currentChildEnum.next(); 196 197 } else { 198 199 // Ready to go onto next child 200 if(debug) {System.out.println("getNextDescendant: next case");} 201 202 prepNextChild(); 203 return getNextDescendant(); 204 } 205 } 206 207 private void prepNextChild() throws NamingException { 208 if(hasMoreChildren()) { 209 try { 210 currentChild = getNextChild(); 211 currentReturned = false; 212 } catch (NamingException e){ 213 if (debug) System.out.println(e); 214 if (debug) e.printStackTrace(); 215 } 216 } else { 217 currentChild = null; 218 return; 219 } 220 221 if(scope == SearchControls.SUBTREE_SCOPE && 222 currentChild.getObject() instanceof Context) { 223 currentChildEnum = newEnumerator( 224 (Context)(currentChild.getObject()), 225 scope, currentChild.getName(), 226 false); 227 currentChildExpanded = true; 228 if(debug) {System.out.println("prepNextChild: expanded");} 229 } else { 230 currentChildExpanded = false; 231 currentChildEnum = null; 232 if(debug) {System.out.println("prepNextChild: normal");} 233 } 234 } 235 }