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      */
Continuation()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()
Continuation(Name top, Hashtable<?,?> environment)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      */
isContinue()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      */
setSuccess()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      */
fillInException(NamingException e)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      */
setErrorNNS(Object resObj, Name remain)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      */
setErrorNNS(Object resObj, String remain)203     public void setErrorNNS(Object resObj, String remain) {
204         CompositeName rname = new CompositeName();
205         try {
206             if (remain != null && !remain.isEmpty())
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      */
setError(Object resObj, Name remain)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      */
setError(Object resObj, String remain)248     public void setError(Object resObj, String remain) {
249         CompositeName rname = new CompositeName();
250         if (remain != null && !remain.isEmpty()) {
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 
setErrorAux(Object resObj, Name rname)260     private void setErrorAux(Object resObj, Name rname) {
261         remainingName = rname;
262         resolvedObj = resObj;
263         continuing = false;
264     }
265 
setContinueAux(Object resObj, Name relResName, Context currCtx, Name remain)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      */
setContinueNNS(Object resObj, Name relResName, Context currCtx)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      */
setContinueNNS(Object resObj, String relResName, Context currCtx)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      */
setContinue(Object obj, Name relResName, Context currCtx)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      */
setContinue(Object obj, Name relResName, Context currCtx, Name remain)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      */
setContinue(Object obj, String relResName, Context currCtx, String remain)375     public void setContinue(Object obj, String relResName,
376         Context currCtx, String remain) {
377         CompositeName relname = new CompositeName();
378         if (!relResName.isEmpty()) {
379             try {
380                 relname.add(relResName);
381             } catch (NamingException e){}
382         }
383 
384         CompositeName rname = new CompositeName();
385         if (!remain.isEmpty()) {
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
setContinue(Object obj, Object currCtx)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      */
setContinueLink(Object linkRef, Name relResName, Context resolvedCtx, Name rname)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 
toString()426     public String toString() {
427         if (remainingName != null)
428             return starter.toString() + "; remainingName: '" + remainingName + "'";
429         else
430             return starter.toString();
431     }
432 
toString(boolean detail)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 }
443