ohair@286: /*
alanb@368: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ohair@286: *
ohair@286: * This code is free software; you can redistribute it and/or modify it
ohair@286: * under the terms of the GNU General Public License version 2 only, as
ohair@286: * published by the Free Software Foundation. Oracle designates this
ohair@286: * particular file as subject to the "Classpath" exception as provided
ohair@286: * by Oracle in the LICENSE file that accompanied this code.
ohair@286: *
ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT
ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ohair@286: * version 2 for more details (a copy is included in the LICENSE file that
ohair@286: * accompanied this code).
ohair@286: *
ohair@286: * You should have received a copy of the GNU General Public License version
ohair@286: * 2 along with this work; if not, write to the Free Software Foundation,
ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ohair@286: *
ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@286: * or visit www.oracle.com if you need additional information or have any
ohair@286: * questions.
ohair@286: */
ohair@286:
ohair@286: package com.sun.xml.internal.ws.api;
ohair@286:
ohair@286: import com.sun.istack.internal.Nullable;
ohair@286:
ohair@286: import javax.xml.ws.WebServiceException;
ohair@286: import java.io.IOException;
ohair@286: import java.net.MalformedURLException;
ohair@286: import java.net.Proxy;
ohair@286: import java.net.ProxySelector;
ohair@286: import java.net.URI;
ohair@286: import java.net.URISyntaxException;
ohair@286: import java.net.URL;
ohair@286: import java.net.URLConnection;
ohair@286: import java.net.URLStreamHandler;
ohair@286: import java.util.Iterator;
ohair@286:
ohair@286: /**
ohair@286: * Represents the endpoint address URI.
ohair@286: *
ohair@286: *
ohair@286: * Conceptually this can be really thought of as an {@link URI},
ohair@286: * but it hides some of the details that improve the performance.
ohair@286: *
ohair@286: *
ohair@286: * Being an {@link URI} allows this class to represent custom made-up URIs
ohair@286: * (like "jms" for example.) Whenever possible, this object
ohair@286: * also creates an {@link URL} (this is only possible when the address
ohair@286: * has a registered {@link URLStreamHandler}), so that if the clients
ohair@286: * of this code wants to use it, it can do so.
ohair@286: *
ohair@286: *
ohair@286: *
How it improves the performance
ohair@286: *
ohair@286: * -
ohair@286: * Endpoint address is often eventually turned into an {@link URLConnection},
ohair@286: * and given that generally this value is read more often than being set,
ohair@286: * it makes sense to eagerly turn it into an {@link URL},
ohair@286: * thereby avoiding a repeated conversion.
ohair@286: *
ohair@286: *
-
ohair@286: * JDK spends a lot of time choosing a list of {@link Proxy}
ohair@286: * to connect to an {@link URL}. Since the default proxy selector
ohair@286: * implementation always return the same proxy for the same URL,
ohair@286: * we can determine the proxy by ourselves to let JDK skip its
ohair@286: * proxy-discovery step.
ohair@286: *
ohair@286: * (That said, user-defined proxy selector can do a lot of interesting things
ohair@286: * --- like doing a round-robin, or pick one from a proxy farm randomly,
ohair@286: * and so it's dangerous to stick to one proxy. For this case,
ohair@286: * we still let JDK decide the proxy. This shouldn't be that much of an
ohair@286: * disappointment, since most people only mess with system properties,
ohair@286: * and never with {@link ProxySelector}. Also, avoiding optimization
ohair@286: * with non-standard proxy selector allows people to effectively disable
ohair@286: * this optimization, which may come in handy for a trouble-shooting.)
ohair@286: *
ohair@286: *
ohair@286: * @author Kohsuke Kawaguchi
ohair@286: */
ohair@286: public final class EndpointAddress {
ohair@286: @Nullable
ohair@286: private URL url;
ohair@286: private final URI uri;
ohair@286: private final String stringForm;
ohair@286: private volatile boolean dontUseProxyMethod;
ohair@286: /**
ohair@286: * Pre-selected proxy.
ohair@286: *
ohair@286: * If {@link #url} is null, this field is null.
ohair@286: * Otherwise, this field could still be null if the proxy couldn't be chosen
ohair@286: * upfront.
ohair@286: */
ohair@286: private Proxy proxy;
ohair@286:
ohair@286: public EndpointAddress(URI uri) {
ohair@286: this.uri = uri;
ohair@286: this.stringForm = uri.toString();
ohair@286: try {
ohair@286: initURL();
ohair@286: proxy = chooseProxy();
ohair@286: } catch (MalformedURLException e) {
ohair@286: // ignore
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: /**
ohair@286: *
ohair@286: * @see #create(String)
ohair@286: */
ohair@286: public EndpointAddress(String url) throws URISyntaxException {
ohair@286: this.uri = new URI(url);
ohair@286: this.stringForm = url;
ohair@286: try {
ohair@286: initURL();
ohair@286: proxy = chooseProxy();
ohair@286: } catch (MalformedURLException e) {
ohair@286: // ignore
ohair@286: }
ohair@286: }
ohair@286:
ohair@286:
ohair@286: private void initURL() throws MalformedURLException {
ohair@286: String scheme = uri.getScheme();
ohair@286: //URI.toURL() only works when scheme is not null.
ohair@286: if (scheme == null) {
ohair@286: this.url = new URL(uri.toString());
ohair@286: return;
ohair@286: }
ohair@286: scheme =scheme.toLowerCase();
ohair@286: if ("http".equals(scheme) || "https".equals(scheme)) {
ohair@286: url = new URL(uri.toASCIIString());
ohair@286: } else {
ohair@286: this.url = uri.toURL();
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: /**
ohair@286: * Creates a new {@link EndpointAddress} with a reasonably
ohair@286: * generic error handling.
ohair@286: */
ohair@286: public static EndpointAddress create(String url) {
ohair@286: try {
ohair@286: return new EndpointAddress(url);
ohair@286: } catch(URISyntaxException e) {
ohair@286: throw new WebServiceException("Illegal endpoint address: "+url,e);
ohair@286: }
ohair@286: }
ohair@286:
ohair@286: private Proxy chooseProxy() {
ohair@286: ProxySelector sel =
ohair@286: java.security.AccessController.doPrivileged(
ohair@286: new java.security.PrivilegedAction() {
alanb@368: @Override
ohair@286: public ProxySelector run() {
ohair@286: return ProxySelector.getDefault();
ohair@286: }
ohair@286: });
ohair@286:
ohair@286: if(sel==null)
ohair@286: return Proxy.NO_PROXY;
ohair@286:
ohair@286:
ohair@286: if(!sel.getClass().getName().equals("sun.net.spi.DefaultProxySelector"))
ohair@286: // user-defined proxy. may return a different proxy for each invocation
ohair@286: return null;
ohair@286:
ohair@286: Iterator it = sel.select(uri).iterator();
ohair@286: if(it.hasNext())
ohair@286: return it.next();
ohair@286:
ohair@286: return Proxy.NO_PROXY;
ohair@286: }
ohair@286:
ohair@286: /**
ohair@286: * Returns an URL of this endpoint adress.
ohair@286: *
ohair@286: * @return
ohair@286: * null if this endpoint address doesn't have a registered {@link URLStreamHandler}.
ohair@286: */
ohair@286: public URL getURL() {
ohair@286: return url;
ohair@286: }
ohair@286:
ohair@286: /**
ohair@286: * Returns an URI of the endpoint address.
ohair@286: *
ohair@286: * @return
ohair@286: * always non-null.
ohair@286: */
ohair@286: public URI getURI() {
ohair@286: return uri;
ohair@286: }
ohair@286:
ohair@286: /**
ohair@286: * Tries to open {@link URLConnection} for this endpoint.
ohair@286: *
ohair@286: *
ohair@286: * This is possible only when an endpoint address has
ohair@286: * the corresponding {@link URLStreamHandler}.
ohair@286: *
ohair@286: * @throws IOException
ohair@286: * if {@link URL#openConnection()} reports an error.
ohair@286: * @throws AssertionError
ohair@286: * if this endpoint doesn't have an associated URL.
ohair@286: * if the code is written correctly this shall never happen.
ohair@286: */
ohair@286: public URLConnection openConnection() throws IOException {
ohair@286: if (url == null) {
ohair@286: throw new WebServiceException("URI="+uri+" doesn't have the corresponding URL");
ohair@286: }
ohair@286: if(proxy!=null && !dontUseProxyMethod) {
ohair@286: try {
ohair@286: return url.openConnection(proxy);
ohair@286: } catch(UnsupportedOperationException e) {
ohair@286: // Some OSGi and app server environments donot
ohair@286: // override URLStreamHandler.openConnection(URL, Proxy) as it
ohair@286: // is introduced in Java SE 5 API. Fallback to the other method.
ohair@286: dontUseProxyMethod = true;
ohair@286: }
ohair@286: }
ohair@286: return url.openConnection();
ohair@286: }
ohair@286:
alanb@368: @Override
ohair@286: public String toString() {
ohair@286: return stringForm;
ohair@286: }
ohair@286: }