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 26 package com.sun.jndi.toolkit.ctx; 27 28 import javax.naming.*; 29 import javax.naming.spi.ResolveResult; 30 import java.util.Hashtable; 31 32 /** 33 * This class contains information required to continue 34 * the method (place where it left off, and remaining name to 35 * continue). 36 * 37 * @author Rosanna Lee 38 */ 39 40 public class Continuation extends ResolveResult { 41 /** 42 * The name that we started out with. It is initialized by the constructor 43 * and used to calculate to "resolved name" in NamingException in 44 * fillInException(). 45 * %%% Note that this approach does not always do the calculation 46 * correctly with respect to absence or presence of the trailing slash 47 * for resolved name. 48 */ 49 protected Name starter; 50 51 /** 52 * Whether links were encountered. 53 */ 54 protected Object followingLink = null; 55 56 /** 57 * The environment used by the caller. Initialized by constructor and 58 * used when filling out a CannotProceedException. 59 */ 60 protected Hashtable<?,?> environment = null; 61 62 /** 63 * Indicates whether the Continuation instance indicates that the operation 64 * should be continued using the data in the Continuation. 65 * Typically, this is only false if an error has been encountered or if 66 * the operation has succeeded. 67 */ 68 protected boolean continuing = false; 69 70 /** 71 * The last resolved context. Used to set the "AltNameCtx" in a 72 * CannotProceedException. 73 */ 74 protected Context resolvedContext = null; 75 76 /** 77 * The resolved name relative to resolvedContext. Used to set the 78 * "AltName" in a CannotProceedException. 79 */ 80 protected Name relativeResolvedName = null; 81 82 /** 83 * Constructs a new instance of Continuation. 84 * Used as dummy for contexts that do not do federation (e.g. for schema ops) 85 */ 86 public Continuation() { 87 } 88 89 /** 90 * Constructs a new instance of Continuation. 91 * @param top The name of the object that is to be resolved/operated upon. 92 * This becomes the Continuation's 'starter' and is used to 93 * calculate the "resolved name" when filling in a NamingException. 94 * @param environment The environment used by the caller. It is used 95 * when setting the "environment" of a CannotProceedException. 96 */ 97 @SuppressWarnings("unchecked") // For Hashtable clone: environment.clone() 98 public Continuation(Name top, Hashtable<?,?> environment) { 99 super(); 100 starter = top; 101 this.environment = (Hashtable<?,?>) 102 ((environment == null) ? null : environment.clone()); 103 } 104 105 /** 106 * Determines whether this Continuation contains data that should be 107 * used to continue the operation. 108 * 109 * @return true if operation should continue; false if operation has 110 * completed (successfully or unsuccessfully). 111 */ 112 public boolean isContinue() { 113 return continuing; 114 } 115 116 /** 117 * Sets this Continuation to indicate successful completion. 118 * Subsequent calls to isContinue() will return false. 119 * This method is different from the setError() methods only from 120 * the standpoint that this method does not set any of the other 121 * fields such as resolved object or resolved context. This is because 122 * this method is typically called when the context recognizes that 123 * the operation has successfully completed and that the continuation 124 * already contains the appropriately set fields. 125 * @see setError 126 * @see setErrorNNS 127 */ 128 public void setSuccess() { 129 continuing = false; 130 } 131 132 /** 133 * Fills in an exception's fields using data from this Continuation. 134 * The resolved name is set by subtracting remainingName from starter. 135 * %%% This might not not always produce the correct answer wrt trailing "/". 136 * If the exception is a CannotProceedException, its environment, 137 * altName, and altNameCtx fields are set using this continuation's 138 * environment, relativeResolvedName, and resolvedContext. 139 * 140 * @param e The non-null naming exception to fill. 141 * @return The non-null naming exception with its fields set using 142 * data from this Continuation. 143 */ 144 public NamingException fillInException(NamingException e) { 145 e.setRemainingName(remainingName); 146 e.setResolvedObj(resolvedObj); 147 148 if (starter == null || starter.isEmpty()) 149 e.setResolvedName(null); 150 else if (remainingName == null) 151 e.setResolvedName(starter); 152 else 153 e.setResolvedName( 154 starter.getPrefix(starter.size() - 155 remainingName.size())); 156 157 if ((e instanceof CannotProceedException)) { 158 CannotProceedException cpe = (CannotProceedException)e; 159 Hashtable<?,?> env = (environment == null ? 160 new Hashtable<>(11) : (Hashtable<?,?>)environment.clone()); 161 cpe.setEnvironment(env); 162 cpe.setAltNameCtx(resolvedContext); 163 cpe.setAltName(relativeResolvedName); 164 } 165 166 return e; 167 } 168 169 /** 170 * Sets this Continuation to indicated that an error has occurred, 171 * and that the remaining name is rename + "/". 172 * 173 * This method is typically called by _nns methods that have been 174 * given a name to process. It might process part of that name but 175 * encountered some error. Consequently, it would call setErrorNNS() 176 * with the remaining name. Since the _nns method was expected to 177 * operate upon the "nns" of the original name, the remaining name 178 * must include the "nns". That's why this method adds a trailing "/". 179 *<p> 180 * After this method is called, isContinuing() returns false. 181 * 182 * @param resObj The possibly null object that was resolved to. 183 * @param remain The non-null remaining name. 184 */ 185 public void setErrorNNS(Object resObj, Name remain) { 186 Name nm = (Name)(remain.clone()); 187 try { 188 nm.add(""); 189 } catch (InvalidNameException e) { 190 // ignore; can't happen for composite name 191 } 192 setErrorAux(resObj, nm); 193 } 194 195 /** 196 * Form that accepts a String name instead of a Name name. 197 198 * @param resObj The possibly null object that was resolved to. 199 * @param remain The possibly String remaining name. 200 * 201 * @see #setErrorNNS(java.lang.Object, javax.naming.Name) 202 */ 203 public void setErrorNNS(Object resObj, String remain) { 204 CompositeName rname = new CompositeName(); 205 try { 206 if (remain != null && !remain.equals("")) 207 rname.add(remain); 208 209 rname.add(""); 210 } catch (InvalidNameException e) { 211 // ignore, can't happen for composite name 212 } 213 setErrorAux(resObj, rname); 214 } 215 216 /** 217 * Sets this Continuation to indicated that an error has occurred 218 * and supply resolved information. 219 * 220 * This method is typically called by methods that have been 221 * given a name to process. It might process part of that name but 222 * encountered some error. Consequently, it would call setError() 223 * with the resolved object and the remaining name. 224 *<p> 225 * After this method is called, isContinuing() returns false. 226 * 227 * @param resObj The possibly null object that was resolved to. 228 * @param remain The possibly null remaining name. 229 */ 230 public void setError(Object resObj, Name remain) { 231 if (remain != null) 232 remainingName = (Name)(remain.clone()); 233 else 234 remainingName = null; 235 236 setErrorAux(resObj, remainingName); 237 } 238 239 240 /** 241 * Form that accepts a String name instead of a Name name. 242 243 * @param resObj The possibly null object that was resolved to. 244 * @param remain The possibly String remaining name. 245 * 246 * @see #setError(java.lang.Object, javax.naming.Name) 247 */ 248 public void setError(Object resObj, String remain) { 249 CompositeName rname = new CompositeName(); 250 if (remain != null && !remain.equals("")) { 251 try { 252 rname.add(remain); 253 } catch (InvalidNameException e) { 254 // ignore; can't happen for composite name 255 } 256 } 257 setErrorAux(resObj, rname); 258 } 259 260 private void setErrorAux(Object resObj, Name rname) { 261 remainingName = rname; 262 resolvedObj = resObj; 263 continuing = false; 264 } 265 266 private void setContinueAux(Object resObj, 267 Name relResName, Context currCtx, Name remain) { 268 if (resObj instanceof LinkRef) { 269 setContinueLink(resObj, relResName, currCtx, remain); 270 } else { 271 remainingName = remain; 272 resolvedObj = resObj; 273 274 relativeResolvedName = relResName; 275 resolvedContext = currCtx; 276 277 continuing = true; 278 } 279 } 280 281 /** 282 * Sets this Continuation with the supplied data, and set remaining name 283 * to be "/". 284 * This method is typically called by _nns methods that have been 285 * given a name to process. It might the name (without the nns) and 286 * continue process of the nns elsewhere. 287 * Consequently, it would call this form of the setContinueNNS(). 288 * This method supplies "/" as the remaining name. 289 *<p> 290 * After this method is called, isContinuing() returns true. 291 * 292 * @param resObj The possibly null resolved object. 293 * @param relResName The non-null resolved name relative to currCtx. 294 * @param currCtx The non-null context from which relResName is to be resolved. 295 */ 296 public void setContinueNNS(Object resObj, Name relResName, Context currCtx) { 297 CompositeName rname = new CompositeName(); 298 299 setContinue(resObj, relResName, currCtx, PartialCompositeContext._NNS_NAME); 300 } 301 302 /** 303 * Overloaded form that accesses String names. 304 * 305 * @param resObj The possibly null resolved object. 306 * @param relResName The non-null resolved name relative to currCtx. 307 * @param currCtx The non-null context from which relResName is to be resolved. 308 * @see #setContinueNNS(java.lang.Object, javax.naming.Name, javax.naming.Context) 309 */ 310 public void setContinueNNS(Object resObj, String relResName, Context currCtx) { 311 CompositeName relname = new CompositeName(); 312 try { 313 relname.add(relResName); 314 } catch (NamingException e) {} 315 316 setContinue(resObj, relname, currCtx, PartialCompositeContext._NNS_NAME); 317 } 318 319 320 /** 321 * Sets this Continuation with the supplied data, and set remaining name 322 * to be the empty name. 323 * This method is typically called by list-style methods 324 * in which the target context implementing list() expects an 325 * empty name. For example when c_list() is given a non-empty name to 326 * process, it would resolve that name, and then call setContinue() 327 * with the resolved object so that the target context to be listed 328 * would be called with the empty name (i.e. list the target context itself). 329 *<p> 330 * After this method is called, isContinuing() returns true. 331 * 332 * @param obj The possibly null resolved object. 333 * @param relResName The non-null resolved name relative to currCtx. 334 * @param currCtx The non-null context from which relResName is to be resolved. 335 */ 336 public void setContinue(Object obj, Name relResName, Context currCtx) { 337 setContinueAux(obj, relResName, currCtx, 338 (Name)PartialCompositeContext._EMPTY_NAME.clone()); 339 } 340 341 /** 342 * Sets this Continuation with the supplied data. 343 344 * This method is typically called by a method that has been asked 345 * to operate on a name. The method resolves part of the name 346 * (relResName) to obj and sets the unprocessed part to rename. 347 * It calls setContinue() so that the operation can be continued 348 * using this data. 349 *<p> 350 * After this method is called, isContinuing() returns true. 351 * 352 * @param obj The possibly null resolved object. 353 * @param relResName The non-null resolved name relative to currCtx. 354 * @param currCtx The non-null context from which relResName is to be resolved. 355 * @param remain The non-null remaining name. 356 */ 357 public void setContinue(Object obj, Name relResName, Context currCtx, Name remain) { 358 if (remain != null) 359 this.remainingName = (Name)(remain.clone()); 360 else 361 this.remainingName = new CompositeName(); 362 363 setContinueAux(obj, relResName, currCtx, remainingName); 364 } 365 366 /** 367 * String overload. 368 * 369 * @param obj The possibly null resolved object. 370 * @param relResName The non-null resolved name relative to currCtx. 371 * @param currCtx The non-null context from which relResName is to be resolved. 372 * @param remain The non-null remaining name. 373 * @see #setContinue(java.lang.Object, java.lang.String, javax.naming.Context, java.lang.String) 374 */ 375 public void setContinue(Object obj, String relResName, 376 Context currCtx, String remain) { 377 CompositeName relname = new CompositeName(); 378 if (!relResName.equals("")) { 379 try { 380 relname.add(relResName); 381 } catch (NamingException e){} 382 } 383 384 CompositeName rname = new CompositeName(); 385 if (!remain.equals("")) { 386 try { 387 rname.add(remain); 388 } catch (NamingException e) { 389 } 390 } 391 392 setContinueAux(obj, relname, currCtx, rname); 393 } 394 395 /** 396 * %%% This method is kept only for backward compatibility. Delete when 397 * old implementations updated. 398 * 399 * Replaced by setContinue(obj, relResName, (Context)currCtx); 400 * 401 * @deprecated 402 */ 403 @Deprecated 404 public void setContinue(Object obj, Object currCtx) { 405 setContinue(obj, null, (Context)currCtx); 406 } 407 408 409 /** 410 * Sets this Continuation to process a linkRef. 411 * %%% Not working yet. 412 */ 413 private void setContinueLink(Object linkRef, Name relResName, 414 Context resolvedCtx, Name rname) { 415 this.followingLink = linkRef; 416 417 this.remainingName = rname; 418 this.resolvedObj = resolvedCtx; 419 420 this.relativeResolvedName = PartialCompositeContext._EMPTY_NAME; 421 this.resolvedContext = resolvedCtx; 422 423 this.continuing = true; 424 } 425 426 public String toString() { 427 if (remainingName != null) 428 return starter.toString() + "; remainingName: '" + remainingName + "'"; 429 else 430 return starter.toString(); 431 } 432 433 public String toString(boolean detail) { 434 if (!detail || this.resolvedObj == null) 435 return this.toString(); 436 return this.toString() + "; resolvedObj: " + this.resolvedObj + 437 "; relativeResolvedName: " + relativeResolvedName + 438 "; resolvedContext: " + resolvedContext; 439 } 440 441 private static final long serialVersionUID = 8162530656132624308L; 442 }