1 /* 2 * Copyright (c) 1997, 2010, 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 26 package com.sun.xml.internal.ws.api; 27 28 29 import com.sun.istack.internal.Nullable; 30 31 import javax.xml.ws.WebServiceException; 32 import java.io.IOException; 33 import java.net.MalformedURLException; 34 import java.net.Proxy; 35 import java.net.ProxySelector; 36 import java.net.URI; 37 import java.net.URISyntaxException; 38 import java.net.URL; 39 import java.net.URLConnection; 40 import java.net.URLStreamHandler; 41 import java.util.Iterator; 42 43 /** 44 * Represents the endpoint address URI. 45 * 46 * <p> 47 * Conceptually this can be really thought of as an {@link URI}, 48 * but it hides some of the details that improve the performance. 49 * 50 * <p> 51 * Being an {@link URI} allows this class to represent custom made-up URIs 52 * (like "jms" for example.) Whenever possible, this object 53 * also creates an {@link URL} (this is only possible when the address 54 * has a registered {@link URLStreamHandler}), so that if the clients 55 * of this code wants to use it, it can do so. 56 * 57 * 58 * <h3>How it improves the performance</h3> 59 * <ol> 60 * <li> 61 * Endpoint address is often eventually turned into an {@link URLConnection}, 62 * and given that generally this value is read more often than being set, 63 * it makes sense to eagerly turn it into an {@link URL}, 64 * thereby avoiding a repeated conversion. 65 * 66 * <li> 67 * JDK spends a lot of time choosing a list of {@link Proxy} 68 * to connect to an {@link URL}. Since the default proxy selector 69 * implementation always return the same proxy for the same URL, 70 * we can determine the proxy by ourselves to let JDK skip its 71 * proxy-discovery step. 72 * 73 * (That said, user-defined proxy selector can do a lot of interesting things 74 * --- like doing a round-robin, or pick one from a proxy farm randomly, 75 * and so it's dangerous to stick to one proxy. For this case, 76 * we still let JDK decide the proxy. This shouldn't be that much of an 77 * disappointment, since most people only mess with system properties, 78 * and never with {@link ProxySelector}. Also, avoiding optimization 79 * with non-standard proxy selector allows people to effectively disable 80 * this optimization, which may come in handy for a trouble-shooting.) 81 * </ol> 82 * 83 * @author Kohsuke Kawaguchi 84 */ 85 public final class EndpointAddress { 86 @Nullable 87 private URL url; 88 private final URI uri; 89 private final String stringForm; 90 private volatile boolean dontUseProxyMethod; 91 /** 92 * Pre-selected proxy. 93 * 94 * If {@link #url} is null, this field is null. 95 * Otherwise, this field could still be null if the proxy couldn't be chosen 96 * upfront. 97 */ 98 private Proxy proxy; 99 100 public EndpointAddress(URI uri) { 101 this.uri = uri; 102 this.stringForm = uri.toString(); 103 try { 104 initURL(); 105 proxy = chooseProxy(); 106 } catch (MalformedURLException e) { 107 // ignore 108 } 109 } 110 111 /** 112 * 113 * @see #create(String) 114 */ 115 public EndpointAddress(String url) throws URISyntaxException { 116 this.uri = new URI(url); 117 this.stringForm = url; 118 try { 119 initURL(); 120 proxy = chooseProxy(); 121 } catch (MalformedURLException e) { 122 // ignore 123 } 124 } 125 126 127 private void initURL() throws MalformedURLException { 128 String scheme = uri.getScheme(); 129 //URI.toURL() only works when scheme is not null. 130 if (scheme == null) { 131 this.url = new URL(uri.toString()); 132 return; 133 } 134 scheme =scheme.toLowerCase(); 135 if ("http".equals(scheme) || "https".equals(scheme)) { 136 url = new URL(uri.toASCIIString()); 137 } else { 138 this.url = uri.toURL(); 139 } 140 } 141 142 /** 143 * Creates a new {@link EndpointAddress} with a reasonably 144 * generic error handling. 145 */ 146 public static EndpointAddress create(String url) { 147 try { 148 return new EndpointAddress(url); 149 } catch(URISyntaxException e) { 150 throw new WebServiceException("Illegal endpoint address: "+url,e); 151 } 152 } 153 154 private Proxy chooseProxy() { 155 ProxySelector sel = 156 java.security.AccessController.doPrivileged( 157 new java.security.PrivilegedAction<ProxySelector>() { 158 public ProxySelector run() { 159 return ProxySelector.getDefault(); 160 } 161 }); 162 163 if(sel==null) 164 return Proxy.NO_PROXY; 165 166 167 if(!sel.getClass().getName().equals("sun.net.spi.DefaultProxySelector")) 168 // user-defined proxy. may return a different proxy for each invocation 169 return null; 170 171 Iterator<Proxy> it = sel.select(uri).iterator(); 172 if(it.hasNext()) 173 return it.next(); 174 175 return Proxy.NO_PROXY; 176 } 177 178 /** 179 * Returns an URL of this endpoint adress. 180 * 181 * @return 182 * null if this endpoint address doesn't have a registered {@link URLStreamHandler}. 183 */ 184 public URL getURL() { 185 return url; 186 } 187 188 /** 189 * Returns an URI of the endpoint address. 190 * 191 * @return 192 * always non-null. 193 */ 194 public URI getURI() { 195 return uri; 196 } 197 198 /** 199 * Tries to open {@link URLConnection} for this endpoint. 200 * 201 * <p> 202 * This is possible only when an endpoint address has 203 * the corresponding {@link URLStreamHandler}. 204 * 205 * @throws IOException 206 * if {@link URL#openConnection()} reports an error. 207 * @throws AssertionError 208 * if this endpoint doesn't have an associated URL. 209 * if the code is written correctly this shall never happen. 210 */ 211 public URLConnection openConnection() throws IOException { 212 assert url!=null : uri+" doesn't have the corresponding URL"; 213 if (url == null) { 214 throw new WebServiceException("URI="+uri+" doesn't have the corresponding URL"); 215 } 216 if(proxy!=null && !dontUseProxyMethod) { 217 try { 218 return url.openConnection(proxy); 219 } catch(UnsupportedOperationException e) { 220 // Some OSGi and app server environments donot 221 // override URLStreamHandler.openConnection(URL, Proxy) as it 222 // is introduced in Java SE 5 API. Fallback to the other method. 223 dontUseProxyMethod = true; 224 } 225 } 226 return url.openConnection(); 227 } 228 229 public String toString() { 230 return stringForm; 231 } 232 }