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.server;
27
28import com.sun.istack.internal.NotNull;
29import com.sun.xml.internal.ws.api.message.Packet;
30import com.sun.xml.internal.ws.api.server.WSEndpoint;
31import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate;
32import com.sun.xml.internal.ws.api.server.PortAddressResolver;
33import com.sun.xml.internal.ws.transport.http.HttpAdapter;
34import com.sun.xml.internal.ws.transport.http.WSHTTPConnection;
35import com.sun.xml.internal.ws.developer.JAXWSProperties;
36import com.sun.xml.internal.ws.resources.WsservletMessages;
37
38import javax.xml.ws.handler.MessageContext;
39import javax.xml.ws.WebServiceException;
40import javax.xml.ws.spi.http.HttpExchange;
41import java.io.IOException;
42import java.io.InputStream;
43import java.io.OutputStream;
44import java.security.Principal;
45import java.util.ArrayList;
46import java.util.List;
47import java.util.Map;
48import java.util.Set;
49
50/**
51 * {@link WSHTTPConnection} used with Java SE endpoints. It provides connection
52 * implementation using {@link HttpExchange} object.
53 *
54 * @author Jitendra Kotamraju
55 */
56final class PortableConnectionImpl extends WSHTTPConnection implements WebServiceContextDelegate {
57
58    private final HttpExchange httpExchange;
59    private int status;
60    private final HttpAdapter adapter;
61    private boolean outputWritten;
62
63    public PortableConnectionImpl(@NotNull HttpAdapter adapter, @NotNull HttpExchange httpExchange) {
64        this.adapter = adapter;
65        this.httpExchange = httpExchange;
66    }
67
68    @Override
69    @Property(value = {MessageContext.HTTP_REQUEST_HEADERS, Packet.INBOUND_TRANSPORT_HEADERS})
70    public @NotNull Map<String,List<String>> getRequestHeaders() {
71        return httpExchange.getRequestHeaders();
72    }
73
74    @Override
75    public String getRequestHeader(String headerName) {
76        return httpExchange.getRequestHeader(headerName);
77    }
78
79    @Override
80    public void setResponseHeaders(Map<String,List<String>> headers) {
81        Map<String, List<String>> r = httpExchange.getResponseHeaders();
82        r.clear();
83        for(Map.Entry <String, List<String>> entry : headers.entrySet()) {
84            String name = entry.getKey();
85            List<String> values = entry.getValue();
86            // ignore headers that interfere with our correct operations
87            if (!name.equalsIgnoreCase("Content-Length") && !name.equalsIgnoreCase("Content-Type")) {
88                r.put(name,new ArrayList<String>(values));
89            }
90        }
91    }
92
93    @Override
94    public void setResponseHeader(String key, List<String> value) {
95        httpExchange.getResponseHeaders().put(key, value);
96    }
97
98    @Override
99    public Set<String> getRequestHeaderNames() {
100        return httpExchange.getRequestHeaders().keySet();
101    }
102
103    @Override
104    public List<String> getRequestHeaderValues(String headerName) {
105        return httpExchange.getRequestHeaders().get(headerName);
106    }
107
108    @Override
109    @Property({MessageContext.HTTP_RESPONSE_HEADERS,Packet.OUTBOUND_TRANSPORT_HEADERS})
110    public Map<String,List<String>> getResponseHeaders() {
111        return httpExchange.getResponseHeaders();
112    }
113
114    @Override
115    public void setContentTypeResponseHeader(@NotNull String value) {
116        httpExchange.addResponseHeader("Content-Type", value);
117    }
118
119    @Override
120    public void setStatus(int status) {
121        this.status = status;
122    }
123
124    @Override
125    @Property(MessageContext.HTTP_RESPONSE_CODE)
126    public int getStatus() {
127        return status;
128    }
129
130    public @Override @NotNull InputStream getInput() throws IOException {
131        return httpExchange.getRequestBody();
132    }
133
134    public @Override @NotNull OutputStream getOutput() throws IOException {
135        assert !outputWritten;
136        outputWritten = true;
137
138        httpExchange.setStatus(getStatus());
139        return httpExchange.getResponseBody();
140    }
141
142    public @Override @NotNull WebServiceContextDelegate getWebServiceContextDelegate() {
143        return this;
144    }
145
146    @Override
147    public Principal getUserPrincipal(Packet request) {
148        return httpExchange.getUserPrincipal();
149    }
150
151    @Override
152    public boolean isUserInRole(Packet request, String role) {
153        return httpExchange.isUserInRole(role);
154    }
155
156    public @Override @NotNull String getEPRAddress(Packet request, WSEndpoint endpoint) {
157        PortAddressResolver resolver = adapter.owner.createPortAddressResolver(getBaseAddress(), endpoint.getImplementationClass());
158        String address = resolver.getAddressFor(endpoint.getServiceName(), endpoint.getPortName().getLocalPart());
159        if(address==null) {
160            throw new WebServiceException(WsservletMessages.SERVLET_NO_ADDRESS_AVAILABLE(endpoint.getPortName()));
161        }
162        return address;
163    }
164
165    @Property(MessageContext.SERVLET_CONTEXT)
166    public Object getServletContext() {
167        return httpExchange.getAttribute(MessageContext.SERVLET_CONTEXT);
168    }
169
170    @Property(MessageContext.SERVLET_RESPONSE)
171    public Object getServletResponse() {
172        return httpExchange.getAttribute(MessageContext.SERVLET_RESPONSE);
173    }
174
175    @Property(MessageContext.SERVLET_REQUEST)
176    public Object getServletRequest() {
177        return httpExchange.getAttribute(MessageContext.SERVLET_REQUEST);
178    }
179
180    @Override
181    public String getWSDLAddress(@NotNull Packet request, @NotNull WSEndpoint endpoint) {
182        String eprAddress = getEPRAddress(request,endpoint);
183        if(adapter.getEndpoint().getPort() != null) {
184            return eprAddress+"?wsdl";
185        } else {
186            return null;
187        }
188    }
189
190    @Override
191    public boolean isSecure() {
192        return httpExchange.getScheme().equals("https");
193    }
194
195    @Override
196    @Property(MessageContext.HTTP_REQUEST_METHOD)
197    public @NotNull String getRequestMethod() {
198        return httpExchange.getRequestMethod();
199    }
200
201    @Override
202    @Property(MessageContext.QUERY_STRING)
203    public String getQueryString() {
204        return httpExchange.getQueryString();
205    }
206
207    @Override
208    @Property(MessageContext.PATH_INFO)
209    public String getPathInfo() {
210        return httpExchange.getPathInfo();
211    }
212
213    @Property(JAXWSProperties.HTTP_EXCHANGE)
214    public HttpExchange getExchange() {
215        return httpExchange;
216    }
217
218    @Override @NotNull
219    public String getBaseAddress() {
220        StringBuilder sb = new StringBuilder();
221        sb.append(httpExchange.getScheme());
222        sb.append("://");
223        sb.append(httpExchange.getLocalAddress().getHostName());
224        sb.append(":");
225        sb.append(httpExchange.getLocalAddress().getPort());
226        sb.append(httpExchange.getContextPath());
227        return sb.toString();
228    }
229
230    @Override
231    public String getProtocol() {
232        return httpExchange.getProtocol();
233    }
234
235    @Override
236    public void setContentLengthResponseHeader(int value) {
237        httpExchange.addResponseHeader("Content-Length", ""+value);
238    }
239
240    @Override
241    public String getRequestURI() {
242        return httpExchange.getRequestURI().toString();
243    }
244
245    @Override
246    public String getRequestScheme() {
247        return httpExchange.getScheme();
248    }
249
250    @Override
251    public String getServerName() {
252        return httpExchange.getLocalAddress().getHostName();
253    }
254
255    @Override
256    public int getServerPort() {
257        return httpExchange.getLocalAddress().getPort();
258    }
259
260    @Override
261    protected PropertyMap getPropertyMap() {
262        return model;
263    }
264
265    private static final PropertyMap model;
266
267    static {
268        model = parse(PortableConnectionImpl.class);
269    }
270}
271