1/*
2 * Copyright 2009 Mike Cumings
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *   http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.kenai.jbosh;
18
19import java.util.ArrayList;
20import java.util.Collections;
21import java.util.EventObject;
22import java.util.List;
23
24/**
25 * Client connection event, notifying of changes in connection state.
26 * <p/>
27 * This class is immutable and thread-safe.
28 */
29public final class BOSHClientConnEvent extends EventObject {
30
31    /**
32     * Serialized version.
33     */
34    private static final long serialVersionUID = 1L;
35
36    /**
37     * Boolean flag indicating whether or not a session has been established
38     * and is currently active.
39     */
40    private final boolean connected;
41
42    /**
43     * List of outstanding requests which may not have been sent and/or
44     * acknowledged by the remote CM.
45     */
46    private final List<ComposableBody> requests;
47
48    /**
49     * Cause of the session termination, or {@code null}.
50     */
51    private final Throwable cause;
52
53    /**
54     * Creates a new connection event instance.
55     *
56     * @param source event source
57     * @param cConnected flag indicating whether or not the session is
58     *  currently active
59     * @param cRequests outstanding requests when an error condition is
60     *  detected, or {@code null} when not an error condition
61     * @param cCause cause of the error condition, or {@code null} when no
62     *  error condition is present
63     */
64    private BOSHClientConnEvent(
65            final BOSHClient source,
66            final boolean cConnected,
67            final List<ComposableBody> cRequests,
68            final Throwable cCause) {
69        super(source);
70        connected = cConnected;
71        cause = cCause;
72
73        if (connected) {
74            if (cCause != null) {
75                throw(new IllegalStateException(
76                        "Cannot be connected and have a cause"));
77            }
78            if (cRequests != null && cRequests.size() > 0) {
79                throw(new IllegalStateException(
80                        "Cannot be connected and have outstanding requests"));
81            }
82        }
83
84        if (cRequests == null) {
85            requests = Collections.emptyList();
86        } else {
87            // Defensive copy:
88            requests = Collections.unmodifiableList(
89                    new ArrayList<ComposableBody>(cRequests));
90        }
91    }
92
93    /**
94     * Creates a new connection establishment event.
95     *
96     * @param source client which has become connected
97     * @return event instance
98     */
99    static BOSHClientConnEvent createConnectionEstablishedEvent(
100            final BOSHClient source) {
101        return new BOSHClientConnEvent(source, true, null, null);
102    }
103
104    /**
105     * Creates a new successful connection closed event.  This represents
106     * a clean termination of the client session.
107     *
108     * @param source client which has been disconnected
109     * @return event instance
110     */
111    static BOSHClientConnEvent createConnectionClosedEvent(
112            final BOSHClient source) {
113        return new BOSHClientConnEvent(source, false, null, null);
114    }
115
116    /**
117     * Creates a connection closed on error event.  This represents
118     * an unexpected termination of the client session.
119     *
120     * @param source client which has been disconnected
121     * @param outstanding list of requests which may not have been received
122     *  by the remote connection manager
123     * @param cause cause of termination
124     * @return event instance
125     */
126    static BOSHClientConnEvent createConnectionClosedOnErrorEvent(
127            final BOSHClient source,
128            final List<ComposableBody> outstanding,
129            final Throwable cause) {
130        return new BOSHClientConnEvent(source, false, outstanding, cause);
131    }
132
133    /**
134     * Gets the client from which this event originated.
135     *
136     * @return client instance
137     */
138    public BOSHClient getBOSHClient() {
139        return (BOSHClient) getSource();
140    }
141
142    /**
143     * Returns whether or not the session has been successfully established
144     * and is currently active.
145     *
146     * @return {@code true} if a session is active, {@code false} otherwise
147     */
148    public boolean isConnected() {
149        return connected;
150    }
151
152    /**
153     * Returns whether or not this event indicates an error condition.  This
154     * will never return {@code true} when {@code isConnected()} returns
155     * {@code true}.
156     *
157     * @return {@code true} if the event indicates a terminal error has
158     *  occurred, {@code false} otherwise.
159     */
160    public boolean isError() {
161        return cause != null;
162    }
163
164    /**
165     * Returns the underlying cause of the error condition.  This method is
166     * guaranteed to return {@code null} when @{code isError()} returns
167     * {@code false}.  Similarly, this method is guaranteed to return
168     * non-@{code null} if {@code isError()} returns {@code true}.
169     *
170     * @return underlying cause of the error condition, or {@code null} if
171     *  this event does not represent an error condition
172     */
173    public Throwable getCause() {
174        return cause;
175    }
176
177    /**
178     * Get the list of requests which may not have been sent or were not
179     * acknowledged by the remote connection manager prior to session
180     * termination.
181     *
182     * @return list of messages which may not have been received by the remote
183     *  connection manager, or an empty list if the session is still connected
184     */
185    public List<ComposableBody> getOutstandingRequests() {
186        return requests;
187    }
188
189}
190