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