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.transport.http;
27
28import com.oracle.webservices.internal.api.message.BasePropertySet;
29import com.oracle.webservices.internal.api.message.PropertySet;
30import com.sun.istack.internal.NotNull;
31import com.sun.istack.internal.Nullable;
32import com.sun.xml.internal.ws.api.message.Packet;
33import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate;
34
35import javax.xml.ws.WebServiceContext;
36import java.io.IOException;
37import java.io.InputStream;
38import java.io.OutputStream;
39import java.net.HttpURLConnection;
40import java.security.Principal;
41import java.util.Collections;
42import java.util.List;
43import java.util.Map;
44import java.util.Set;
45
46
47/**
48 * The view of an HTTP exchange from the point of view of JAX-WS.
49 *
50 * <p>
51 * Different HTTP server layer uses different implementations of this class
52 * so that JAX-WS can be shielded from individuality of such layers.
53 * This is an interface implemented as an abstract class, so that
54 * future versions of the JAX-WS RI can add new methods.
55 *
56 * <p>
57 * This class extends {@link PropertySet} so that a transport can
58 * expose its properties to the application and pipes. (This object
59 * will be added to {@link Packet#addSatellite(PropertySet)}.)
60 *
61 * @author Jitendra Kotamraju
62 */
63public abstract class WSHTTPConnection extends BasePropertySet {
64
65    public static final int OK=200;
66    public static final int ONEWAY=202;
67    public static final int UNSUPPORTED_MEDIA=415;
68    public static final int MALFORMED_XML=400;
69    public static final int INTERNAL_ERR=500;
70
71    /**
72     * Overwrites all the HTTP response headers written thus far.
73     *
74     * <p>
75     * The implementation should copy the contents of the {@link Map},
76     * rather than retaining a reference. The {@link Map} passed as a
77     * parameter may change after this method is invoked.
78     *
79     * <p>
80     * This method may be called repeatedly, although in normal use
81     * case that's rare (so the implementation is encourage to take
82     * advantage of this usage pattern to improve performance, if possible.)
83     *
84     * <p>
85     * Initially, no header is set.
86     *
87     * <p>
88     * This parameter is usually exposed to {@link WebServiceContext}
89     * as {@link Packet#OUTBOUND_TRANSPORT_HEADERS}, and thus it
90     * should ignore {@code Content-Type} and {@code Content-Length} headers.
91     *
92     * @param headers
93     *      See {@link HttpURLConnection#getHeaderFields()} for the format.
94     *      This parameter may not be null, but since the user application
95     *      code may invoke this method, a graceful error checking with
96     *      an helpful error message should be provided if it's actually null.
97     * @see #setContentTypeResponseHeader(String)
98     */
99    public abstract void setResponseHeaders(@NotNull Map<String,List<String>> headers);
100
101    public void setResponseHeader(String key, String value) {
102        setResponseHeader(key, Collections.singletonList(value));
103    }
104
105    public abstract void setResponseHeader(String key, List<String> value);
106
107    /**
108     * Sets the {@code "Content-Type"} header.
109     *
110     * <p>
111     * If the Content-Type header has already been set, this method will overwrite
112     * the previously set value. If not, this method adds it.
113     *
114     * <p>
115     * Note that this method and {@link #setResponseHeaders(java.util.Map)}
116     * may be invoked in any arbitrary order.
117     *
118     * @param value
119     *      strings like {@code "application/xml; charset=UTF-8"} or
120     *      {@code "image/jpeg"}.
121     */
122    public abstract void setContentTypeResponseHeader(@NotNull String value);
123
124    /**
125     * Sets the HTTP response code like {@link #OK}.
126     *
127     * <p>
128     * While JAX-WS processes a {@link WSHTTPConnection}, it
129     * will at least call this method once to set a valid HTTP response code.
130     * Note that this method may be invoked multiple times (from user code),
131     * so do not consider the value to be final until {@link #getOutput()}
132     * is invoked.
133     */
134
135    public abstract void setStatus(int status);
136
137    /**
138     * Gets the last value set by {@link #setStatus(int)}.
139     *
140     * @return
141     *      if {@link #setStatus(int)} has not been invoked yet,
142     *      return 0.
143     */
144    // I know this is ugly method!
145    public abstract int getStatus();
146
147    /**
148     * Transport's underlying input stream.
149     *
150     * <p>
151     * This method will be invoked at most once by the JAX-WS RI to
152     * read the request body. If there's no request body, this method
153     * should return an empty {@link InputStream}.
154     *
155     * @return
156     *      the stream from which the request body will be read.
157     */
158    public abstract @NotNull InputStream getInput() throws IOException;
159
160    /**
161     * Transport's underlying output stream
162     *
163     * <p>
164     * This method will be invoked exactly once by the JAX-WS RI
165     * to start writing the response body (unless the processing aborts abnormally.)
166     * Even if there's no response body to write, this method will
167     * still be invoked only to be closed immediately.
168     *
169     * <p>
170     * Once this method is called, the status code and response
171     * headers will never change (IOW {@link #setStatus(int)},
172     * {@link #setResponseHeaders}, and {@link #setContentTypeResponseHeader(String)}
173     * will never be invoked.
174     */
175    public abstract @NotNull OutputStream getOutput() throws IOException;
176
177    /**
178     * Returns the {@link WebServiceContextDelegate} for this connection.
179     */
180    public abstract @NotNull WebServiceContextDelegate getWebServiceContextDelegate();
181
182    /**
183     * HTTP request method, such as "GET" or "POST".
184     */
185    public abstract @NotNull String getRequestMethod();
186
187    /**
188     * HTTP request headers.
189     *
190     * @deprecated
191     *      This is a potentially expensive operation.
192     *      Programs that want to access HTTP headers should consider using
193     *      other methods such as {@link #getRequestHeader(String)}.
194     *
195     * @return
196     *      can be empty but never null.
197     */
198    public abstract @NotNull Map<String,List<String>> getRequestHeaders();
199
200    /**
201     * HTTP request header names.
202     *
203     * @deprecated
204     *      This is a potentially expensive operation.
205     *      Programs that want to access HTTP headers should consider using
206     *      other methods such as {@link #getRequestHeader(String)}.
207     *
208     * @return
209     *      can be empty but never null.
210     */
211    public abstract @NotNull Set<String> getRequestHeaderNames();
212
213    /**
214     * @return
215     *      HTTP response headers.
216     */
217    public abstract Map<String,List<String>> getResponseHeaders();
218
219    /**
220     * Gets an HTTP request header.
221     *
222     * <p>
223     * if multiple headers are present, this method returns one of them.
224     * (The implementation is free to choose which one it returns.)
225     *
226     * @return
227     *      null if no header exists.
228     */
229    public abstract @Nullable String getRequestHeader(@NotNull String headerName);
230
231    /**
232     * Gets an HTTP request header.
233     *
234     * @return
235     *      null if no header exists.
236     */
237    public abstract @Nullable List<String> getRequestHeaderValues(@NotNull String headerName);
238
239    /**
240     * HTTP Query string, such as "foo=bar", or null if none exists.
241     */
242    public abstract @Nullable String getQueryString();
243
244    /**
245     * Extra portion of the request URI after the end of the expected address of the service
246     * but before the query string
247     */
248    public abstract @Nullable String getPathInfo();
249
250    /**
251     * Requested path. A string like "/foo/bar/baz"
252     */
253    public abstract @NotNull String getRequestURI();
254
255    /**
256     * Requested scheme, e.g. "http" or "https"
257     */
258    public abstract @NotNull String getRequestScheme();
259
260    /**
261     * Server name
262     */
263    public abstract @NotNull String getServerName();
264
265    /**
266     * Server port
267     */
268    public abstract int getServerPort();
269
270    /**
271     * Portion of the request URI that groups related service addresses.  The value, if non-empty, will
272     * always begin with '/', but will never end with '/'.  Environments that do not support
273     * context paths must return an empty string.
274     */
275    public @NotNull String getContextPath() {
276        return "";
277    }
278
279    /**
280     * Environment specific context , if available
281     */
282    public Object getContext() {
283        return null;
284    }
285
286    /**
287     * Gets the absolute URL up to the context path.
288     * @return
289     *      String like "http://myhost/myapp"
290     * @since 2.1.2
291     */
292    public @NotNull String getBaseAddress() {
293        throw new UnsupportedOperationException();
294    }
295
296    /**
297     * Whether connection is HTTPS or not
298     *
299     * @return if the received request is on HTTPS, return true
300     *         else false
301     */
302    public abstract boolean isSecure();
303
304    /**
305     * User principal associated with the request
306     *
307     * @return user principal
308     */
309    public Principal getUserPrincipal() {
310        return null;
311    }
312
313    /**
314     * Whether user associated with the request holds the given role
315     *
316     * @param role Role to check
317     * @return if the caller holds the role
318     */
319    public boolean isUserInRole(String role) {
320        return false;
321    }
322
323    /**
324     * Gets request metadata attribute
325     * @param key Request metadata key
326     * @return Value of metadata attribute or null, if no value present
327     */
328    public Object getRequestAttribute(String key) {
329        return null;
330    }
331
332    private volatile boolean closed;
333
334    /**
335     * Close the connection
336     */
337    public void close() {
338        this.closed = true;
339    }
340
341    /**
342     * Retuns whether connection is closed or not.
343     */
344    public boolean isClosed() {
345        return closed;
346    }
347
348    /**
349     * Subclasses are expected to override
350     *
351     * @return a {@link String} containing the protocol name and version number
352     */
353    public String getProtocol() {
354        return "HTTP/1.1";
355    }
356
357    /**
358     * Subclasses are expected to override
359     *
360     * @since JAX-WS RI 2.2.2
361     * @return value of given cookie
362     */
363    public String getCookie(String name) {
364        return null;
365    }
366
367    /**
368     * Subclasses are expected to override
369     *
370     *
371     * @since JAX-WS RI 2.2.2
372     */
373    public void setCookie(String name, String value) {
374    }
375
376    /**
377     * Subclasses are expected to override
378     */
379    public void setContentLengthResponseHeader(int value) {
380    }
381
382}
383