1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package java.net;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.ObjectOutputStream;
23 import java.security.AccessController;
24 import java.util.Hashtable;
25 import java.util.StringTokenizer;
26
27 import org.apache.harmony.luni.internal.nls.Messages;
28 import org.apache.harmony.luni.util.PriviAction;
29 import org.apache.harmony.luni.util.Util;
30
31 /**
32 * A URL instance specifies the location of a resource on the internet as
33 * specified by RFC 1738. Such a resource can be a simple file or a service
34 * which generates the output dynamically. A URL is divided in its parts
35 * protocol, host name, port, path, file, user-info, query, reference and
36 * authority. However, not each of this parts has to be defined.
37 */
38 public final class URL implements java.io.Serializable {
39 private static final long serialVersionUID = -7627629688361524110L;
40
41 private static final NetPermission specifyStreamHandlerPermission = new NetPermission(
42 "specifyStreamHandler"); //$NON-NLS-1$
43
44 private int hashCode;
45
46 /**
47 * The receiver's filename.
48 *
49 * @serial the file of this URL
50 *
51 */
52 private String file;
53
54 /**
55 * The receiver's protocol identifier.
56 *
57 * @serial the protocol of this URL (http, file)
58 *
59 */
60 private String protocol = null;
61
62 /**
63 * The receiver's host name.
64 *
65 * @serial the host of this URL
66 *
67 */
68 private String host;
69
70 /**
71 * The receiver's port number.
72 *
73 * @serial the port of this URL
74 *
75 */
76 private int port = -1;
77
78 /**
79 * The receiver's authority.
80 *
81 * @serial the authority of this URL
82 *
83 */
84 private String authority = null;
85
86 /**
87 * The receiver's userInfo.
88 */
89 private transient String userInfo = null;
90
91 /**
92 * The receiver's path.
93 */
94 private transient String path = null;
95
96 /**
97 * The receiver's query.
98 */
99 private transient String query = null;
100
101 /**
102 * The receiver's reference.
103 *
104 * @serial the reference of this URL
105 *
106 */
107 private String ref = null;
108
109 /**
110 * Cache for storing protocol handler
111 */
112 private static Hashtable<String, URLStreamHandler> streamHandlers = new Hashtable<String, URLStreamHandler>();
113
114 /**
115 * The URL Stream (protocol) Handler
116 */
117 transient URLStreamHandler strmHandler;
118
119 /**
120 * The factory responsible for producing URL Stream (protocol) Handler
121 */
122 private static URLStreamHandlerFactory streamHandlerFactory;
123
124 /**
125 * Sets the {@code URLStreamHandlerFactory} which creates protocol specific
126 * stream handlers. This method can be invoked only once during an
127 * application's lifetime. If the {@code URLStreamHandlerFactory} is already
128 * set an {@link Error} will be thrown.
129 * <p>
130 * A security check is performed to verify whether the current policy allows
131 * to set the stream handler factory.
132 *
133 * @param streamFactory
134 * the factory to be used for creating stream protocol handlers.
135 */
136 public static synchronized void setURLStreamHandlerFactory(
137 URLStreamHandlerFactory streamFactory) {
138 if (streamHandlerFactory != null) {
139 throw new Error(Messages.getString("luni.9A")); //$NON-NLS-1$
140 }
141 SecurityManager sm = System.getSecurityManager();
142 if (sm != null) {
143 sm.checkSetFactory();
144 }
145 streamHandlers.clear();
146 streamHandlerFactory = streamFactory;
147 }
148
149 /**
150 * Creates a new URL instance by parsing the string {@code spec}.
151 *
152 * @param spec
153 * the URL string representation which has to be parsed.
154 * @throws MalformedURLException
155 * if the given string {@code spec} could not be parsed as a
156 * URL.
157 */
158 public URL(String spec) throws MalformedURLException {
159 this((URL) null, spec, (URLStreamHandler) null);
160 }
161
162 /**
163 * Creates a new URL to the specified resource {@code spec}. This URL is
164 * relative to the given {@code context}. If the protocol of the parsed URL
165 * does not match with the protocol of the context URL, then the newly
166 * created URL is absolute and bases only on the given URL represented by
167 * {@code spec}. Otherwise the protocol is defined by the context URL.
168 *
169 * @param context
170 * the URL which is used as the context.
171 * @param spec
172 * the URL string representation which has to be parsed.
173 * @throws MalformedURLException
174 * if the given string {@code spec} could not be parsed as a URL
175 * or an invalid protocol has been found.
176 */
177 public URL(URL context, String spec) throws MalformedURLException {
178 this(context, spec, (URLStreamHandler) null);
179 }
180
181 /**
182 * Creates a new URL to the specified resource {@code spec}. This URL is
183 * relative to the given {@code context}. The {@code handler} will be used
184 * to parse the URL string representation. If this argument is {@code null}
185 * the default {@code URLStreamHandler} will be used. If the protocol of the
186 * parsed URL does not match with the protocol of the context URL, then the
187 * newly created URL is absolute and bases only on the given URL represented
188 * by {@code spec}. Otherwise the protocol is defined by the context URL.
189 *
190 * @param context
191 * the URL which is used as the context.
192 * @param spec
193 * the URL string representation which has to be parsed.
194 * @param handler
195 * the specific stream handler to be used by this URL.
196 * @throws MalformedURLException
197 * if the given string {@code spec} could not be parsed as a URL
198 * or an invalid protocol has been found.
199 */
200 public URL(URL context, String spec, URLStreamHandler handler)
201 throws MalformedURLException {
202 if (handler != null) {
203 SecurityManager sm = System.getSecurityManager();
204 if (sm != null) {
205 sm.checkPermission(specifyStreamHandlerPermission);
206 }
207 strmHandler = handler;
208 }
209
210 if (spec == null) {
211 throw new MalformedURLException();
212 }
213 spec = spec.trim();
214
215 // The spec includes a protocol if it includes a colon character
216 // before the first occurrence of a slash character. Note that,
217 // "protocol" is the field which holds this URLs protocol.
218 int index;
219 try {
220 index = spec.indexOf(':');
221 } catch (NullPointerException e) {
222 throw new MalformedURLException(e.toString());
223 }
224 int startIPv6Addr = spec.indexOf('[');
225 if (index >= 0) {
226 if ((startIPv6Addr == -1) || (index < startIPv6Addr)) {
227 protocol = spec.substring(0, index);
228 // According to RFC 2396 scheme part should match
229 // the following expression:
230 // alpha *( alpha | digit | "+" | "-" | "." )
231 char c = protocol.charAt(0);
232 boolean valid = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
233 for (int i = 1; valid && (i < protocol.length()); i++) {
234 c = protocol.charAt(i);
235 valid = ('a' <= c && c <= 'z') ||
236 ('A' <= c && c <= 'Z') ||
237 ('0' <= c && c <= '9') ||
238 (c == '+') ||
239 (c == '-') ||
240 (c == '.');
241 }
242 if (!valid) {
243 protocol = null;
244 index = -1;
245 } else {
246 // Ignore case in protocol names.
247 // Scheme is defined by ASCII characters.
248 protocol = Util.toASCIILowerCase(protocol);
249 }
250 }
251 }
252
253 if (protocol != null) {
254 // If the context was specified, and it had the same protocol
255 // as the spec, then fill in the receiver's slots from the values
256 // in the context but still allow them to be over-ridden later
257 // by the values in the spec.
258 if (context != null && protocol.equals(context.getProtocol())) {
259 String cPath = context.getPath();
260 if (cPath != null && cPath.startsWith("/")) { //$NON-NLS-1$
261 set(protocol, context.getHost(), context.getPort(), context
262 .getAuthority(), context.getUserInfo(), cPath,
263 context.getQuery(), null);
264 }
265 if (strmHandler == null) {
266 strmHandler = context.strmHandler;
267 }
268 }
269 } else {
270 // If the spec did not include a protocol, then the context
271 // *must* be specified. Fill in the receiver's slots from the
272 // values in the context, but still allow them to be over-ridden
273 // by the values in the ("relative") spec.
274 if (context == null) {
275 throw new MalformedURLException(
276 Messages.getString(
277 "luni.9B", spec)); //$NON-NLS-1$
278 }
279 set(context.getProtocol(), context.getHost(), context.getPort(),
280 context.getAuthority(), context.getUserInfo(), context
281 .getPath(), context.getQuery(), null);
282 if (strmHandler == null) {
283 strmHandler = context.strmHandler;
284 }
285 }
286
287 // If the stream handler has not been determined, set it
288 // to the default for the specified protocol.
289 if (strmHandler == null) {
290 setupStreamHandler();
291 if (strmHandler == null) {
292 throw new MalformedURLException(
293 Messages.getString(
294 "luni.9C", protocol)); //$NON-NLS-1$
295 }
296 }
297
298 // Let the handler parse the URL. If the handler throws
299 // any exception, throw MalformedURLException instead.
300 //
301 // Note: We want "index" to be the index of the start of the scheme
302 // specific part of the URL. At this point, it will be either
303 // -1 or the index of the colon after the protocol, so we
304 // increment it to point at either character 0 or the character
305 // after the colon.
306 try {
307 strmHandler.parseURL(this, spec, ++index, spec.length());
308 } catch (Exception e) {
309 throw new MalformedURLException(e.toString());
310 }
311
312 if (port < -1) {
313 throw new MalformedURLException(Messages
314 .getString("luni.56", port)); //$NON-NLS-1$
315 }
316 }
317
318 /**
319 * Creates a new URL instance using the given arguments. The URL uses the
320 * default port for the specified protocol.
321 *
322 * @param protocol
323 * the protocol of the new URL.
324 * @param host
325 * the host name or IP address of the new URL.
326 * @param file
327 * the name of the resource.
328 * @throws MalformedURLException
329 * if the combination of all arguments do not represent a valid
330 * URL or the protocol is invalid.
331 */
332 public URL(String protocol, String host, String file)
333 throws MalformedURLException {
334 this(protocol, host, -1, file, (URLStreamHandler) null);
335 }
336
337 /**
338 * Creates a new URL instance using the given arguments. The URL uses the
339 * specified port instead of the default port for the given protocol.
340 *
341 * @param protocol
342 * the protocol of the new URL.
343 * @param host
344 * the host name or IP address of the new URL.
345 * @param port
346 * the specific port number of the URL. {@code -1} represents the
347 * default port of the protocol.
348 * @param file
349 * the name of the resource.
350 * @throws MalformedURLException
351 * if the combination of all arguments do not represent a valid
352 * URL or the protocol is invalid.
353 */
354 public URL(String protocol, String host, int port, String file)
355 throws MalformedURLException {
356 this(protocol, host, port, file, (URLStreamHandler) null);
357 }
358
359 /**
360 * Creates a new URL instance using the given arguments. The URL uses the
361 * specified port instead of the default port for the given protocol.
362 *
363 * @param protocol
364 * the protocol of the new URL.
365 * @param host
366 * the host name or IP address of the new URL.
367 * @param port
368 * the specific port number of the URL. {@code -1} represents the
369 * default port of the protocol.
370 * @param file
371 * the name of the resource.
372 * @param handler
373 * the stream handler to be used by this URL.
374 * @throws MalformedURLException
375 * if the combination of all arguments do not represent a valid
376 * URL or the protocol is invalid.
377 * @throws SecurityException
378 * if {@code handler} is non-{@code null}, and a security
379 * manager is installed that disallows user-defined protocol
380 * handlers.
381 */
382 public URL(String protocol, String host, int port, String file,
383 URLStreamHandler handler) throws MalformedURLException {
384 if (port < -1) {
385 throw new MalformedURLException(Messages.getString("luni.56", port)); //$NON-NLS-1$
386 }
387
388 if (host != null && host.indexOf(":") != -1 && host.charAt(0) != '[') { //$NON-NLS-1$
389 host = "[" + host + "]"; //$NON-NLS-1$ //$NON-NLS-2$
390 }
391
392 if (protocol == null) {
393 throw new NullPointerException(Messages.getString("luni.9C", "null")); //$NON-NLS-1$ //$NON-NLS-2$
394 }
395
396 this.protocol = protocol;
397 this.host = host;
398 this.port = port;
399
400 // Set the fields from the arguments. Handle the case where the
401 // passed in "file" includes both a file and a reference part.
402 int index = -1;
403 index = file.indexOf("#", file.lastIndexOf("/")); //$NON-NLS-1$ //$NON-NLS-2$
404 if (index >= 0) {
405 this.file = file.substring(0, index);
406 ref = file.substring(index + 1);
407 } else {
408 this.file = file;
409 }
410 fixURL(false);
411
412 // Set the stream handler for the URL either to the handler
413 // argument if it was specified, or to the default for the
414 // receiver's protocol if the handler was null.
415 if (handler == null) {
416 setupStreamHandler();
417 if (strmHandler == null) {
418 throw new MalformedURLException(
419 Messages.getString("luni.9C", protocol)); //$NON-NLS-1$
420 }
421 } else {
422 SecurityManager sm = System.getSecurityManager();
423 if (sm != null) {
424 sm.checkPermission(specifyStreamHandlerPermission);
425 }
426 strmHandler = handler;
427 }
428 }
429
430 void fixURL(boolean fixHost) {
431 int index;
432 if (host != null && host.length() > 0) {
433 authority = host;
434 if (port != -1) {
435 authority = authority + ":" + port; //$NON-NLS-1$
436 }
437 }
438 if (fixHost) {
439 if (host != null && (index = host.lastIndexOf('@')) > -1) {
440 userInfo = host.substring(0, index);
441 host = host.substring(index + 1);
442 } else {
443 userInfo = null;
444 }
445 }
446 if (file != null && (index = file.indexOf('?')) > -1) {
447 query = file.substring(index + 1);
448 path = file.substring(0, index);
449 } else {
450 query = null;
451 path = file;
452 }
453 }
454
455 /**
456 * Sets the properties of this URL using the provided arguments. Only a
457 * {@code URLStreamHandler} can use this method to set fields of the
458 * existing URL instance. A URL is generally constant.
459 *
460 * @param protocol
461 * the protocol to be set.
462 * @param host
463 * the host name to be set.
464 * @param port
465 * the port number to be set.
466 * @param file
467 * the file to be set.
468 * @param ref
469 * the reference to be set.
470 */
471 protected void set(String protocol, String host, int port, String file,
472 String ref) {
473 if (this.protocol == null) {
474 this.protocol = protocol;
475 }
476 this.host = host;
477 this.file = file;
478 this.port = port;
479 this.ref = ref;
480 hashCode = 0;
481 fixURL(true);
482 }
483
484 /**
485 * Compares this URL instance with the given argument {@code o} and
486 * determines if both are equal. Two URL instances are equal if all single
487 * parts are identical in their meaning. Compares the argument to the
488 * receiver, and returns true if they represent the same URL. Two URLs are
489 * equal if they have the same file, host, port, protocol, and reference
490 * components.
491 *
492 * @param o
493 * the URL this instance has to be compared with.
494 * @return {@code true} if both instances represents the same URL, {@code
495 * false} otherwise.
496 * @see #hashCode()
497 */
498 @Override
499 public boolean equals(Object o) {
500 if (o == null) {
501 return false;
502 }
503 if (this == o) {
504 return true;
505 }
506 if (this.getClass() != o.getClass()) {
507 return false;
508 }
509 return strmHandler.equals(this, (URL) o);
510 }
511
512 /**
513 * Returns whether this URL refers to the same resource as the given
514 * argument {@code otherURL}. All URL components except the reference field
515 * are compared.
516 *
517 * @param otherURL
518 * the URL to compare against.
519 * @return {@code true} if both instances refer to the same resource,
520 * {@code false} otherwise.
521 */
522 public boolean sameFile(URL otherURL) {
523 return strmHandler.sameFile(this, otherURL);
524 }
525
526 /**
527 * Gets the hashcode value of this URL instance.
528 *
529 * @return the appropriate hashcode value.
530 */
531 @Override
532 public int hashCode() {
533 if (hashCode == 0) {
534 hashCode = strmHandler.hashCode(this);
535 }
536 return hashCode;
537 }
538
539 /**
540 * Sets the receiver's stream handler to one which is appropriate for its
541 * protocol. Throws a MalformedURLException if no reasonable handler is
542 * available.
543 * <p>
544 * Note that this will overwrite any existing stream handler with the new
545 * one. Senders must check if the strmHandler is null before calling the
546 * method if they do not want this behavior (a speed optimization).
547 */
548 void setupStreamHandler() {
549 // Check for a cached (previously looked up) handler for
550 // the requested protocol.
551 strmHandler = streamHandlers.get(protocol);
552 if (strmHandler != null) {
553 return;
554 }
555
556 // If there is a stream handler factory, then attempt to
557 // use it to create the handler.
558 if (streamHandlerFactory != null) {
559 strmHandler = streamHandlerFactory.createURLStreamHandler(protocol);
560 if (strmHandler != null) {
561 streamHandlers.put(protocol, strmHandler);
562 return;
563 }
564 }
565
566 // Check if there is a list of packages which can provide handlers.
567 // If so, then walk this list looking for an applicable one.
568 String packageList = AccessController
569 .doPrivileged(new PriviAction<String>(
570 "java.protocol.handler.pkgs")); //$NON-NLS-1$
571 if (packageList != null) {
572 StringTokenizer st = new StringTokenizer(packageList, "|"); //$NON-NLS-1$
573 while (st.hasMoreTokens()) {
574 String className = st.nextToken() + "." + protocol + ".Handler"; //$NON-NLS-1$ //$NON-NLS-2$
575
576 try {
577 strmHandler = (URLStreamHandler) Class.forName(className,
578 true, ClassLoader.getSystemClassLoader())
579 .newInstance();
580 if (strmHandler != null) {
581 streamHandlers.put(protocol, strmHandler);
582 }
583 return;
584 } catch (IllegalAccessException e) {
585 } catch (InstantiationException e) {
586 } catch (ClassNotFoundException e) {
587 }
588 }
589 }
590
591 // No one else has provided a handler, so try our internal one.
592
593 String className = "org.apache.harmony.luni.internal.net.www.protocol." + protocol //$NON-NLS-1$
594 + ".Handler"; //$NON-NLS-1$
595 try {
596 strmHandler = (URLStreamHandler) Class.forName(className)
597 .newInstance();
598 } catch (IllegalAccessException e) {
599 } catch (InstantiationException e) {
600 } catch (ClassNotFoundException e) {
601 }
602 if (strmHandler != null) {
603 streamHandlers.put(protocol, strmHandler);
604 }
605
606 }
607
608 /**
609 * Gets the content of the resource which is referred by this URL. By
610 * default one of the following object types will be returned:
611 * <p>
612 * <li>Image for pictures</li>
613 * <li>AudioClip for audio sequences</li>
614 * <li>{@link InputStream} for all other data</li>
615 *
616 * @return the content of the referred resource.
617 * @throws IOException
618 * if an error occurs obtaining the content.
619 */
620 public final Object getContent() throws IOException {
621 return openConnection().getContent();
622 }
623
624 /**
625 * Gets the content of the resource which is referred by this URL. The
626 * argument {@code types} is an array of allowed or expected object types.
627 * {@code null} will be returned if the obtained object type does not match
628 * with one from this list. Otherwise the first type that matches will be
629 * used.
630 *
631 * @param types
632 * the list of allowed or expected object types.
633 * @return the object representing the resource referred by this URL,
634 * {@code null} if the content does not match to a specified content
635 * type.
636 * @throws IOException
637 * if an error occurs obtaining the content.
638 */
639 // Param not generic in spec
640 @SuppressWarnings("unchecked")
641 public final Object getContent(Class[] types) throws IOException {
642 return openConnection().getContent(types);
643 }
644
645 /**
646 * Opens an InputStream to read the resource referred by this URL.
647 *
648 * @return the stream which allows to read the resource.
649 * @throws IOException
650 * if an error occurs while opening the InputStream.
651 */
652 public final InputStream openStream() throws java.io.IOException {
653 return openConnection().getInputStream();
654 }
655
656 /**
657 * Opens a connection to the remote resource specified by this URL. This
658 * connection allows bidirectional data transfer.
659 *
660 * @return the connection to this URL.
661 * @throws IOException
662 * if an error occurs while opening the connection.
663 */
664 public URLConnection openConnection() throws IOException {
665 return strmHandler.openConnection(this);
666 }
667
668 /**
669 * Converts this URL instance into an equivalent URI object.
670 *
671 * @return the URI instance that represents this URL.
672 * @throws URISyntaxException
673 * if this URL cannot be converted into a URI.
674 */
675 public URI toURI() throws URISyntaxException {
676 return new URI(toExternalForm());
677 }
678
679 /**
680 * Opens a connection to the remote resource specified by this URL. The
681 * connection will be established through the given proxy and allows
682 * bidirectional data transfer.
683 *
684 * @param proxy
685 * the proxy through which the connection will be established.
686 * @return the appropriate URLconnection instance representing the
687 * connection to this URL.
688 * @throws IOException
689 * if an I/O error occurs while opening the connection.
690 * @throws SecurityException
691 * if a security manager is installed and it denies to connect
692 * to the proxy.
693 * @throws IllegalArgumentException
694 * if the argument proxy is {@code null} or is an invalid type.
695 * @throws UnsupportedOperationException
696 * if the protocol handler does not support opening connections
697 * through proxies.
698 */
699 public URLConnection openConnection(Proxy proxy) throws IOException {
700 if (proxy == null) {
701 // luni.9D=proxy should not be null
702 throw new IllegalArgumentException(Messages.getString("luni.9D")); //$NON-NLS-1$
703 }
704
705 SecurityManager sm = System.getSecurityManager();
706 if (sm != null && proxy.type() != Proxy.Type.DIRECT) {
707 InetSocketAddress pAddress = (InetSocketAddress) proxy.address();
708 String pHostName = pAddress.isUnresolved() ? pAddress.getHostName()
709 : pAddress.getAddress().getHostAddress();
710 sm.checkConnect(pHostName, pAddress.getPort());
711 }
712
713 return strmHandler.openConnection(this, proxy);
714 }
715
716 /**
717 * Returns a string containing a concise, human-readable representation of
718 * this URL. The returned string is the same as the result of the method
719 * {@code toExternalForm()}.
720 *
721 * @return the string representation of this URL.
722 */
723 @Override
724 public String toString() {
725 return toExternalForm();
726 }
727
728 /**
729 * Returns a string containing a concise, human-readable representation of
730 * this URL.
731 *
732 * @return the string representation of this URL.
733 */
734 public String toExternalForm() {
735 if (strmHandler == null) {
736 return "unknown protocol(" + protocol + ")://" + host + file; //$NON-NLS-1$ //$NON-NLS-2$
737 }
738 return strmHandler.toExternalForm(this);
739 }
740
741 /**
742 * This method is called to restore the state of a URL object that has been
743 * serialized. The stream handler is determined from the URL's protocol.
744 *
745 * @param stream
746 * the stream to read from.
747 *
748 * @throws IOException
749 * if an IO Exception occurs while reading the stream or the
750 * handler can not be found.
751 */
752 private void readObject(java.io.ObjectInputStream stream)
753 throws java.io.IOException {
754 try {
755 stream.defaultReadObject();
756 if (host != null && authority == null) {
757 fixURL(true);
758 } else if (authority != null) {
759 int index;
760 if ((index = authority.lastIndexOf('@')) > -1) {
761 userInfo = authority.substring(0, index);
762 }
763 if (file != null && (index = file.indexOf('?')) > -1) {
764 query = file.substring(index + 1);
765 path = file.substring(0, index);
766 } else {
767 path = file;
768 }
769 }
770 setupStreamHandler();
771 if (strmHandler == null) {
772 throw new IOException(Messages.getString("luni.9C", protocol)); //$NON-NLS-1$
773 }
774 } catch (ClassNotFoundException e) {
775 throw new IOException(e.toString());
776 }
777 }
778
779 /**
780 * This method is called to write any non-transient, non-static variables
781 * into the output stream.
782 * <p>
783 * Note that, we really only need the readObject method but the spec that
784 * says readObject will be ignored if no writeObject is present.
785 *
786 * @param s
787 * the stream to write on.
788 * @throws IOException
789 * if an IO Exception occurs during the write.
790 */
791 private void writeObject(ObjectOutputStream s) throws IOException {
792 s.defaultWriteObject();
793 }
794
795 /**
796 * Gets the value of the file part of this URL.
797 *
798 * @return the file name this URL refers to or an empty string if the file
799 * part is not set.
800 */
801 public String getFile() {
802 return file;
803 }
804
805 /**
806 * Gets the value of the host part of this URL.
807 *
808 * @return the host name or IP address of this URL.
809 */
810 public String getHost() {
811 return host;
812 }
813
814 /**
815 * Gets the port number of this URL or {@code -1} if the port is not set.
816 *
817 * @return the port number of this URL.
818 */
819 public int getPort() {
820 return port;
821 }
822
823 /**
824 * Gets the protocol of this URL.
825 *
826 * @return the protocol type of this URL.
827 */
828 public String getProtocol() {
829 return protocol;
830 }
831
832 /**
833 * Gets the value of the reference part of this URL.
834 *
835 * @return the reference part of this URL.
836 */
837 public String getRef() {
838 return ref;
839 }
840
841 /**
842 * Gets the value of the query part of this URL.
843 *
844 * @return the query part of this URL.
845 */
846 public String getQuery() {
847 return query;
848 }
849
850 /**
851 * Gets the value of the path part of this URL.
852 *
853 * @return the path part of this URL.
854 */
855 public String getPath() {
856 return path;
857 }
858
859 /**
860 * Gets the value of the user-info part of this URL.
861 *
862 * @return the user-info part of this URL.
863 */
864 public String getUserInfo() {
865 return userInfo;
866 }
867
868 /**
869 * Gets the value of the authority part of this URL.
870 *
871 * @return the authority part of this URL.
872 */
873 public String getAuthority() {
874 return authority;
875 }
876
877 /**
878 * Sets the properties of this URL using the provided arguments. Only a
879 * {@code URLStreamHandler} can use this method to set fields of the
880 * existing URL instance. A URL is generally constant.
881 *
882 * @param protocol
883 * the protocol to be set.
884 * @param host
885 * the host name to be set.
886 * @param port
887 * the port number to be set.
888 * @param authority
889 * the authority to be set.
890 * @param userInfo
891 * the user-info to be set.
892 * @param path
893 * the path to be set.
894 * @param query
895 * the query to be set.
896 * @param ref
897 * the reference to be set.
898 */
899 protected void set(String protocol, String host, int port,
900 String authority, String userInfo, String path, String query,
901 String ref) {
902 String filePart = path;
903 if (query != null && !query.equals("")) { //$NON-NLS-1$
904 if (filePart != null) {
905 filePart = filePart + "?" + query; //$NON-NLS-1$
906 } else {
907 filePart = "?" + query; //$NON-NLS-1$
908 }
909 }
910 set(protocol, host, port, filePart, ref);
911 this.authority = authority;
912 this.userInfo = userInfo;
913 this.path = path;
914 this.query = query;
915 }
916
917 /**
918 * Gets the default port number of the protocol used by this URL. If no
919 * default port is defined by the protocol or the {@code URLStreamHandler},
920 * {@code -1} will be returned.
921 *
922 * @return the default port number according to the protocol of this URL.
923 * @see URLStreamHandler#getDefaultPort
924 */
925 public int getDefaultPort() {
926 return strmHandler.getDefaultPort();
927 }
928 }