1/*
2 * Copyright (c) 1997, 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
26package com.sun.xml.internal.ws.api.pipe;
27
28import com.sun.xml.internal.ws.api.message.Packet;
29import 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 */
40public 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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
215    public Tube getNext() {
216        return next;
217    }
218
219    /** Sets the next tube
220     * @param next Next tube
221     */
222    public void setNext(Tube next) {
223        this.next = next;
224    }
225
226    /**
227     * Returns the last Packet
228     * @return Packet
229     */
230    public Packet getPacket() {
231        return packet;
232    }
233
234    /**
235     * Returns the Throwable generated by the last Tube
236     * @return the Throwable
237     */
238    public Throwable getThrowable() {
239        return throwable;
240    }
241
242    /**
243     * Dumps the contents to assist debugging.
244     */
245    @Override
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     */
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