001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.api;
038:
039: import com.sun.istack.Nullable;
040:
041: import javax.xml.ws.WebServiceException;
042: import java.io.IOException;
043: import java.net.MalformedURLException;
044: import java.net.Proxy;
045: import java.net.ProxySelector;
046: import java.net.URI;
047: import java.net.URISyntaxException;
048: import java.net.URL;
049: import java.net.URLConnection;
050: import java.net.URLStreamHandler;
051: import java.util.Iterator;
052:
053: /**
054: * Represents the endpoint address URI.
055: *
056: * <p>
057: * Conceptually this can be really thought of as an {@link URI},
058: * but it hides some of the details that improve the performance.
059: *
060: * <p>
061: * Being an {@link URI} allows this class to represent custom made-up URIs
062: * (like "jms" for example.) Whenever possible, this object
063: * also creates an {@link URL} (this is only possible when the address
064: * has a registered {@link URLStreamHandler}), so that if the clients
065: * of this code wants to use it, it can do so.
066: *
067: *
068: * <h3>How it improves the performance</h3>
069: * <ol>
070: * <li>
071: * Endpoint address is often eventually turned into an {@link URLConnection},
072: * and given that generally this value is read more often than being set,
073: * it makes sense to eagerly turn it into an {@link URL},
074: * thereby avoiding a repeated conversion.
075: *
076: * <li>
077: * JDK spends a lot of time choosing a list of {@link Proxy}
078: * to connect to an {@link URL}. Since the default proxy selector
079: * implementation always return the same proxy for the same URL,
080: * we can determine the proxy by ourselves to let JDK skip its
081: * proxy-discovery step.
082: *
083: * (That said, user-defined proxy selector can do a lot of interesting things
084: * --- like doing a round-robin, or pick one from a proxy farm randomly,
085: * and so it's dangerous to stick to one proxy. For this case,
086: * we still let JDK decide the proxy. This shouldn't be that much of an
087: * disappointment, since most people only mess with system properties,
088: * and never with {@link ProxySelector}. Also, avoiding optimization
089: * with non-standard proxy selector allows people to effectively disable
090: * this optimization, which may come in handy for a trouble-shooting.)
091: * </ol>
092: *
093: * @author Kohsuke Kawaguchi
094: */
095: public final class EndpointAddress {
096: @Nullable
097: private URL url;
098: private final URI uri;
099: private final String stringForm;
100: /**
101: * Pre-selected proxy.
102: *
103: * If {@link #url} is null, this field is null.
104: * Otherwise, this field could still be null if the proxy couldn't be chosen
105: * upfront.
106: */
107: private Proxy proxy;
108:
109: public EndpointAddress(URI uri) {
110: this .uri = uri;
111: this .stringForm = uri.toString();
112: try {
113: this .url = uri.toURL();
114: proxy = chooseProxy();
115: } catch (MalformedURLException e) {
116: // ignore
117: }
118: }
119:
120: /**
121: *
122: * @see #create(String)
123: */
124: public EndpointAddress(String url) throws URISyntaxException {
125: this .uri = new URI(url);
126: this .stringForm = url;
127: try {
128: this .url = new URL(url);
129: proxy = chooseProxy();
130: } catch (MalformedURLException e) {
131: // ignore
132: }
133: }
134:
135: /**
136: * Creates a new {@link EndpointAddress} with a reasonably
137: * generic error handling.
138: */
139: public static EndpointAddress create(String url) {
140: try {
141: return new EndpointAddress(url);
142: } catch (URISyntaxException e) {
143: throw new WebServiceException("Illegal endpoint address: "
144: + url, e);
145: }
146: }
147:
148: private Proxy chooseProxy() {
149: ProxySelector sel = java.security.AccessController
150: .doPrivileged(new java.security.PrivilegedAction<ProxySelector>() {
151: public ProxySelector run() {
152: return ProxySelector.getDefault();
153: }
154: });
155:
156: if (sel == null)
157: return Proxy.NO_PROXY;
158:
159: if (!sel.getClass().getName().equals(
160: "sun.net.spi.DefaultProxySelector"))
161: // user-defined proxy. may return a different proxy for each invocation
162: return null;
163:
164: Iterator<Proxy> it = sel.select(uri).iterator();
165: if (it.hasNext())
166: return it.next();
167:
168: return Proxy.NO_PROXY;
169: }
170:
171: /**
172: * Returns an URL of this endpoint adress.
173: *
174: * @return
175: * null if this endpoint address doesn't have a registered {@link URLStreamHandler}.
176: */
177: public URL getURL() {
178: return url;
179: }
180:
181: /**
182: * Returns an URI of the endpoint address.
183: *
184: * @return
185: * always non-null.
186: */
187: public URI getURI() {
188: return uri;
189: }
190:
191: /**
192: * Tries to open {@link URLConnection} for this endpoint.
193: *
194: * <p>
195: * This is possible only when an endpoint address has
196: * the corresponding {@link URLStreamHandler}.
197: *
198: * @throws IOException
199: * if {@link URL#openConnection()} reports an error.
200: * @throws AssertionError
201: * if this endpoint doesn't have an associated URL.
202: * if the code is written correctly this shall never happen.
203: */
204: public URLConnection openConnection() throws IOException {
205: assert url != null : uri
206: + " doesn't have the corresponding URL";
207: if (proxy != null)
208: return url.openConnection(proxy);
209: else
210: return url.openConnection();
211: }
212:
213: public String toString() {
214: return stringForm;
215: }
216: }
|