View Javadoc
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. Consequenetly, 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. Consequenetly, 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 resObj 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 resObj 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 resObj 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 }