1 /*
2  * Copyright (c) 1997, 2012, 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.xml.internal.ws.api.pipe;
27 
28 import com.sun.xml.internal.ws.api.message.Packet;
29 import java.util.concurrent.Executor;
30 
31 /**
32  * Indicates what shall happen after {@link Tube#processRequest(Packet)} or
33  * {@link Tube#processResponse(Packet)} returns.
34  *
35  * <p>
36  * To allow reuse of this object, this class is mutable.
37  *
38  * @author Kohsuke Kawaguchi
39  */
40 public final class NextAction {
41     int kind;
42     Tube next;
43     Packet packet;
44     /**
45      * Really either {@link RuntimeException} or {@link Error}.
46      */
47     Throwable throwable;
48     Runnable onExitRunnable;
49 
50     // public enum Kind { INVOKE, INVOKE_AND_FORGET, RETURN, SUSPEND }
51 
52     static final int INVOKE = 0;
53     static final int INVOKE_AND_FORGET = 1;
54     static final int RETURN = 2;
55     static final int THROW = 3;
56     static final int SUSPEND = 4;
57     // Used to abort processResponse chain if a fatal exception is encountered
58     static final int THROW_ABORT_RESPONSE = 5;
59     // Used to abort processResponse chain if a response should be aborted
60     static final int ABORT_RESPONSE = 6;
61     // Used to switch a tubeline from synchronous to asynchronous execution
62     // with respect to the thread that started this tubeline.
63     static final int INVOKE_ASYNC = 7;
64 
set(int k, Tube v, Packet p, Throwable t)65   private void set(int k, Tube v, Packet p, Throwable t) {
66         this.kind = k;
67         this.next = v;
68         this.packet = p;
69         this.throwable = t;
70     }
71 
72     /**
73      * Indicates that the next action should be to
74      * invoke the next tube's {@link Tube#processRequest(Packet)},
75      * then later invoke the current tube's {@link Tube#processResponse(Packet)}
76      * with the response packet.
77      */
invoke(Tube next, Packet p)78     public void invoke(Tube next, Packet p) {
79         set(INVOKE, next, p, null);
80     }
81 
82     /**
83      * Indicates that the next action should be to
84      * invoke the next tube's {@link Tube#processRequest(Packet)},
85      * but the current tube doesn't want to receive the response packet to
86      * its {@link Tube#processResponse(Packet)}.
87      */
invokeAndForget(Tube next, Packet p)88     public void invokeAndForget(Tube next, Packet p) {
89         set(INVOKE_AND_FORGET, next, p, null);
90     }
91 
92     /**
93      * Indicates that the next action is to flip the processing direction
94      * and starts response processing.
95      */
returnWith( Packet response )96     public void returnWith( Packet response ) {
97         set(RETURN, null, response, null);
98     }
99 
100     /**
101      * Indicates that the next action is to flip the processing direction
102      * and starts exception processing, but with the indicated context.
103      *
104      * @param t
105      *      Either {@link RuntimeException} or {@link Error}, but defined to
106      *      take {@link Throwable} because {@link Tube#processException(Throwable)}
107      *      takes {@link Throwable}.
108      */
throwException( Packet response, Throwable t )109     public void throwException( Packet response, Throwable t ) {
110         // Use of RETURN is correct -- Fiber processing does not set packet for type of THROW
111         set(RETURN, null, response, t);
112     }
113 
114     /**
115      * Indicates that the next action is to flip the processing direction
116      * and starts exception processing.
117      *
118      * @param t
119      *      Either {@link RuntimeException} or {@link Error}, but defined to
120      *      take {@link Throwable} because {@link Tube#processException(Throwable)}
121      *      takes {@link Throwable}.
122      */
throwException(Throwable t)123     public void throwException(Throwable t) {
124         assert t instanceof RuntimeException || t instanceof Error;
125         set(THROW,null,null,t);
126     }
127 
128     /**
129      * Indicates that the next action is to abort the processResponse chain
130      * because of an exception. How that exception is processed is not
131      * defined.
132      *
133      * @param t
134      *      Either {@link RuntimeException} or {@link Error}
135      */
throwExceptionAbortResponse(Throwable t)136     public void throwExceptionAbortResponse(Throwable t) {
137         set(THROW_ABORT_RESPONSE,null,null,t);
138     }
139 
140     /**
141      * Indicates that the next action is to abort the processResponse chain
142      * because of some non-exception condition.
143      *
144      * @param response The response that is being aborted
145      */
abortResponse(Packet response)146     public void abortResponse(Packet response) {
147         set(ABORT_RESPONSE,null,response,null);
148     }
149 
150     /**
151      * Indicates that the next action is to invoke the next tube in the
152      * tubeline async from the thread that started the tubeline. Only fibers
153      * that were started using startSync should use this next action kind.
154      * @param next The next tube in the tubeline
155      * @param p The request to pass to the next tube
156      */
invokeAsync(Tube next, Packet p)157     public void invokeAsync(Tube next, Packet p) {
158         set(INVOKE_ASYNC,next,p,null);
159     }
160 
161     /**
162      * Indicates that the fiber should be suspended.
163      * Once {@link Fiber#resume(Packet) resumed}, return the response processing.
164      * @deprecated Use variants that pass {@link Runnable}
165      */
suspend()166     public void suspend() {
167         suspend(null, null);
168     }
169 
170     /**
171      * Indicates that the fiber should be suspended.  Once the current {@link Thread}
172      * exits the fiber's control loop, the onExitRunnable will be invoked.  This {@link Runnable}
173      * may call {@link Fiber#resume(Packet)}; however it is still guaranteed that the current
174      * Thread will return control, therefore, further processing will be handled on a {@link Thread}
175      * from the {@link Executor}.  For synchronous cases, the Thread invoking this fiber cannot return
176      * until fiber processing is complete; therefore, the guarantee is only that the onExitRunnable
177      * will be invoked prior to completing the suspension.
178      * @since 2.2.7
179      */
suspend(Runnable onExitRunnable)180     public void suspend(Runnable onExitRunnable) {
181         suspend(null, onExitRunnable);
182     }
183 
184     /**
185      * Indicates that the fiber should be suspended.
186      * Once {@link Fiber#resume(Packet) resumed}, resume with the
187      * {@link Tube#processRequest(Packet)} on the given next tube.
188      * @deprecated Use variants that pass {@link Runnable}
189      */
suspend(Tube next)190     public void suspend(Tube next) {
191         suspend(next, null);
192     }
193 
194     /**
195      * Indicates that the fiber should be suspended.  Once the current {@link Thread}
196      * exits the fiber's control loop, the onExitRunnable will be invoked.  This {@link Runnable}
197      * may call {@link Fiber#resume(Packet)}; however it is still guaranteed that the current
198      * fiber will return control, therefore, further processing will be handled on a {@link Thread}
199      * from the {@link Executor}.  For synchronous cases, the Thread invoking this fiber cannot return
200      * until fiber processing is complete; therefore, the guarantee is only that the onExitRunnable
201      * will be invoked prior to completing the suspension.
202      * <p>
203      * Once {@link Fiber#resume(Packet) resumed}, resume with the
204      * {@link Tube#processRequest(Packet)} on the given next tube.
205      * @since 2.2.7
206      */
suspend(Tube next, Runnable onExitRunnable)207     public void suspend(Tube next, Runnable onExitRunnable) {
208         set(SUSPEND, next, null, null);
209         this.onExitRunnable = onExitRunnable;
210     }
211 
212     /** Returns the next tube
213      * @return Next tube
214      */
getNext()215     public Tube getNext() {
216         return next;
217     }
218 
219     /** Sets the next tube
220      * @param next Next tube
221      */
setNext(Tube next)222     public void setNext(Tube next) {
223         this.next = next;
224     }
225 
226     /**
227      * Returns the last Packet
228      * @return Packet
229      */
getPacket()230     public Packet getPacket() {
231         return packet;
232     }
233 
234     /**
235      * Returns the Throwable generated by the last Tube
236      * @return the Throwable
237      */
getThrowable()238     public Throwable getThrowable() {
239         return throwable;
240     }
241 
242     /**
243      * Dumps the contents to assist debugging.
244      */
245     @Override
toString()246     public String toString() {
247         StringBuilder buf = new StringBuilder();
248         buf.append(super.toString()).append(" [");
249         buf.append("kind=").append(getKindString()).append(',');
250         buf.append("next=").append(next).append(',');
251         buf.append("packet=").append(packet != null ? packet.toShortString() : null).append(',');
252         buf.append("throwable=").append(throwable).append(']');
253         return buf.toString();
254     }
255 
256     /**
257      * Returns {@link #kind} in a human readable string, to assist debugging.
258      */
getKindString()259     public String getKindString() {
260         switch(kind) {
261         case INVOKE:            return "INVOKE";
262         case INVOKE_AND_FORGET: return "INVOKE_AND_FORGET";
263         case RETURN:            return "RETURN";
264         case THROW:             return "THROW";
265         case SUSPEND:           return "SUSPEND";
266         case THROW_ABORT_RESPONSE: return "THROW_ABORT_RESPONSE";
267         case ABORT_RESPONSE:    return "ABORT_RESPONSE";
268         case INVOKE_ASYNC:      return "INVOKE_ASYNC";
269         default:                throw new AssertionError(kind);
270         }
271     }
272 }
273