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: *
  1. 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: *
  2. 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: }