Java/Network Protocol/Utilities
Содержание
- 1 A class that encodes URL parameter values for MIDP devices.
- 2 Create Socket helper
- 3 Get the listing of everyone logged on
- 4 Implements a TCP/IP bounce utility (proxy)
- 5 Scan your computer for ports in use
- 6 TCP socket monitor
- 7 URL utilities class that makes it easy to create new URLs based off of old URLs without having to assemble or parse them yourself
- 8 Using the URL Class (GetURL.java)
A class that encodes URL parameter values for MIDP devices.
/*
Chapter 3 - Simple Protocols
Java 2 Network Protocols Black Book
by Al Williams
Paraglyph Press 2001
*/
/**
* A class that encodes URL parameter values
* for MIDP devices.
*/
public class EncodeURL {
// The characters that do not need to
// be converted.
private static final String noEncode =
"abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"0123456789.*-_";
// Mapping value values 0 through 15 to the
// corresponding hexadecimal character.
private static final char[] hexDigits = {
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "A", "B", "C", "D", "E", "F"
};
// Encodes the given string as required for
// use in a URL query string or POST data.
public static String encode(String src) {
StringBuffer result = new StringBuffer(src.length());
int count = src.length();
for (int i = 0; i < count; i++) {
char c = src.charAt(i);
if (noEncode.indexOf(c) != -1) {
// This is a character that does not
// need to be encoded
result.append(c);
continue;
}
// Space is converted to "+"
if (c == " ") {
result.append("+");
continue;
}
// The remaining characters must be converted to
// "%XY" where "XY" is the hexadecimal value of
// the character itself.
result.append("%");
result.append(hexDigits[(c >> 4) & 0xF]);
result.append(hexDigits[c & 0xF]);
}
return result.toString();
}
}
Create Socket helper
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the "License"). You may not use this file except
* in compliance with the License.
*
* You can obtain a copy of the license at
* glassfish/bootstrap/legal/CDDLv1.0.txt or
* https://glassfish.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* HEADER in each file and include the License file at
* glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
* add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your
* own identifying information: Portions Copyright [yyyy]
* [name of copyright owner]
*/
/*
* @(#)SocketFetcher.java 1.19 06/10/17
*
* Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
*/
import java.security.*;
import java.net.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import javax.net.*;
import javax.net.ssl.*;
/**
* This class is used to get Sockets. Depending on the arguments passed it will
* either return a plain java.net.Socket or dynamically load the SocketFactory
* class specified in the classname param and return a socket created by that
* SocketFactory.
*
* @author Max Spivak
* @author Bill Shannon
*/
public class SocketFetcher {
// No one should instantiate this class.
private SocketFetcher() {
}
/**
* This method returns a Socket. Properties control the use of socket
* factories and other socket characteristics. The properties used are:
* <p>
* <ul>
* <li> <i>prefix</i>.socketFactory.class
* <li> <i>prefix</i>.socketFactory.fallback
* <li> <i>prefix</i>.socketFactory.port
* <li> <i>prefix</i>.timeout
* <li> <i>prefix</i>.connectiontimeout
* <li> <i>prefix</i>.localaddress
* <li> <i>prefix</i>.localport
* </ul>
* <p>
* If the socketFactory.class property isn"t set, the socket returned is an
* instance of java.net.Socket connected to the given host and port. If the
* socketFactory.class property is set, it is expected to contain a fully
* qualified classname of a javax.net.SocketFactory subclass. In this case,
* the class is dynamically instantiated and a socket created by that
* SocketFactory is returned.
* <p>
*
* If the socketFactory.fallback property is set to false, don"t fall back to
* using regular sockets if the socket factory fails.
* <p>
*
* The socketFactory.port specifies a port to use when connecting through the
* socket factory. If unset, the port argument will be used.
* <p>
*
* If the connectiontimeout property is set, we use a separate thread to make
* the connection so that we can timeout that connection attempt.
* <p>
*
* If the timeout property is set, it is used to set the socket timeout.
* <p>
*
* If the localaddress property is set, it"s used as the local address to bind
* to. If the localport property is also set, it"s used as the local port
* number to bind to.
*
* @param host
* The host to connect to
* @param port
* The port to connect to at the host
* @param props
* Properties object containing socket properties
* @param prefix
* Property name prefix, e.g., "mail.imap"
* @param useSSL
* use the SSL socket factory as the default
*/
public static Socket getSocket(String host, int port, Properties props, String prefix,
boolean useSSL) throws IOException {
if (prefix == null)
prefix = "socket";
if (props == null)
props = new Properties(); // empty
String s = props.getProperty(prefix + ".connectiontimeout", null);
int cto = -1;
if (s != null) {
try {
cto = Integer.parseInt(s);
} catch (NumberFormatException nfex) {
}
}
Socket socket = null;
String timeout = props.getProperty(prefix + ".timeout", null);
String localaddrstr = props.getProperty(prefix + ".localaddress", null);
InetAddress localaddr = null;
if (localaddrstr != null)
localaddr = InetAddress.getByName(localaddrstr);
String localportstr = props.getProperty(prefix + ".localport", null);
int localport = 0;
if (localportstr != null) {
try {
localport = Integer.parseInt(localportstr);
} catch (NumberFormatException nfex) {
}
}
boolean fb = false;
String fallback = props.getProperty(prefix + ".socketFactory.fallback", null);
fb = fallback == null || (!fallback.equalsIgnoreCase("false"));
String sfClass = props.getProperty(prefix + ".socketFactory.class", null);
int sfPort = -1;
try {
SocketFactory sf = getSocketFactory(sfClass);
if (sf != null) {
String sfPortStr = props.getProperty(prefix + ".socketFactory.port", null);
if (sfPortStr != null) {
try {
sfPort = Integer.parseInt(sfPortStr);
} catch (NumberFormatException nfex) {
}
}
// if port passed in via property isn"t valid, use param
if (sfPort == -1)
sfPort = port;
socket = createSocket(localaddr, localport, host, sfPort, cto, sf, useSSL);
}
} catch (Exception ex) {
if (!fb) {
if (ex instanceof InvocationTargetException) {
Throwable t = ((InvocationTargetException) ex).getTargetException();
if (t instanceof Exception)
ex = (Exception) t;
}
if (ex instanceof IOException)
throw (IOException) ex;
IOException ioex = new IOException("Couldn"t connect using \"" + sfClass
+ "\" socket factory to host, port: " + host + ", " + sfPort + "; Exception: " + ex);
throw ioex;
}
}
if (socket == null)
socket = createSocket(localaddr, localport, host, port, cto, null, useSSL);
int to = -1;
if (timeout != null) {
try {
to = Integer.parseInt(timeout);
} catch (NumberFormatException nfex) {
}
}
if (to >= 0)
socket.setSoTimeout(to);
configureSSLSocket(socket, props, prefix);
return socket;
}
public static Socket getSocket(String host, int port, Properties props, String prefix)
throws IOException {
return getSocket(host, port, props, prefix, false);
}
/**
* Create a socket with the given local address and connected to the given
* host and port. Use the specified connection timeout. If a socket factory is
* specified, use it. Otherwise, use the SSLSocketFactory if useSSL is true.
*/
private static Socket createSocket(InetAddress localaddr, int localport, String host, int port,
int cto, SocketFactory sf, boolean useSSL) throws IOException {
Socket socket;
if (sf != null)
socket = sf.createSocket(host, port);
else if (useSSL)
socket = SSLSocketFactory.getDefault().createSocket(host, port);
else
socket = new Socket(host, port);
/*
* if (localaddr != null) socket.bind(new InetAddress(localaddr,
* localport)); if (cto >= 0) socket.connect(new InetSocketAddress(host,
* port), cto); else socket.connect(new InetSocketAddress(host, port));
*/
return socket;
}
/**
* Return a socket factory of the specified class.
*/
private static SocketFactory getSocketFactory(String sfClass) throws ClassNotFoundException,
NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (sfClass == null || sfClass.length() == 0)
return null;
// dynamically load the class
ClassLoader cl = getContextClassLoader();
Class clsSockFact = null;
if (cl != null) {
try {
clsSockFact = cl.loadClass(sfClass);
} catch (ClassNotFoundException cex) {
}
}
if (clsSockFact == null)
clsSockFact = Class.forName(sfClass);
// get & invoke the getDefault() method
Method mthGetDefault = clsSockFact.getMethod("getDefault", new Class[] {});
SocketFactory sf = (SocketFactory) mthGetDefault.invoke(new Object(), new Object[] {});
return sf;
}
/**
* Start TLS on an existing socket. Supports the "STARTTLS" command in many
* protocols. This version for compatibility possible third party code that
* might"ve used this API even though it shouldn"t.
*/
public static Socket startTLS(Socket socket) throws IOException {
return startTLS(socket, new Properties(), "socket");
}
/**
* Start TLS on an existing socket. Supports the "STARTTLS" command in many
* protocols.
*/
public static Socket startTLS(Socket socket, Properties props, String prefix) throws IOException {
InetAddress a = socket.getInetAddress();
String host = a.getHostName();
int port = socket.getPort();
// System.out.println("SocketFetcher: startTLS host " + host + ", port " +
// port);
try {
SSLSocketFactory ssf;
String sfClass = props.getProperty(prefix + ".socketFactory.class", null);
SocketFactory sf = getSocketFactory(sfClass);
if (sf != null && sf instanceof SSLSocketFactory)
ssf = (SSLSocketFactory) sf;
else
ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
socket = ssf.createSocket(socket, host, port, true);
configureSSLSocket(socket, props, prefix);
} catch (Exception ex) {
if (ex instanceof InvocationTargetException) {
Throwable t = ((InvocationTargetException) ex).getTargetException();
if (t instanceof Exception)
ex = (Exception) t;
}
if (ex instanceof IOException)
throw (IOException) ex;
// wrap anything else before sending it on
IOException ioex = new IOException("Exception in startTLS: host " + host + ", port " + port
+ "; Exception: " + ex);
throw ioex;
}
return socket;
}
/**
* Configure the SSL options for the socket (if it"s an SSL socket), based on
* the mail.<protocol>.ssl.protocols and mail.<protocol>.ssl.ciphersuites
* properties.
*/
private static void configureSSLSocket(Socket socket, Properties props, String prefix) {
if (!(socket instanceof SSLSocket))
return;
SSLSocket sslsocket = (SSLSocket) socket;
String protocols = props.getProperty(prefix + ".ssl.protocols", null);
// if (protocols != null)
// sslsocket.setEnabledProtocols(stringArray(protocols));
// else {
// /*
// * At least the UW IMAP server insists on only the TLSv1
// * protocol for STARTTLS, and won"t accept the old SSLv2
// * or SSLv3 protocols. Here we enable only the TLSv1
// * protocol. XXX - this should probably be parameterized.
// */
// sslsocket.setEnabledProtocols(new String[] {"TLSv1"});
// }
String ciphers = props.getProperty(prefix + ".ssl.ciphersuites", null);
if (ciphers != null)
sslsocket.setEnabledCipherSuites(stringArray(ciphers));
/*
* System.out.println("SSL protocols after " +
* Arrays.asList(sslsocket.getEnabledProtocols())); System.out.println("SSL
* ciphers after " + Arrays.asList(sslsocket.getEnabledCipherSuites()));
*/
}
/**
* Parse a string into whitespace separated tokens and return the tokens in an
* array.
*/
private static String[] stringArray(String s) {
StringTokenizer st = new StringTokenizer(s);
List tokens = new ArrayList();
while (st.hasMoreTokens())
tokens.add(st.nextToken());
return (String[]) tokens.toArray(new String[tokens.size()]);
}
/**
* Convenience method to get our context class loader. Assert any privileges
* we might have and then call the Thread.getContextClassLoader method.
*/
private static ClassLoader getContextClassLoader() {
return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (SecurityException ex) {
}
return cl;
}
});
}
}
Get the listing of everyone logged on
import java.applet.Applet;
import java.awt.Button;
import java.awt.Font;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class Who {
public static void main(String []v){
Socket s = null;
PrintWriter out = null;
BufferedReader in = null;
try {
// Connect to port 79 (the standard finger port) on the host.
String hostname = "www.jexp.ru";
s = new Socket(hostname, 79);
// Set up the streams
out = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
// Send a blank line to the finger server, telling it that we want
// a listing of everyone logged on instead of information about an
// individual user.
out.print("\n");
out.flush(); // Send it out
// Now read the server"s response
// The server should send lines terminated with \n or \r.
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
System.out.println("Who"s Logged On: " + hostname);
} catch (IOException e) {
System.out.println("Who"s Logged On: Error");
}
// Close the streams!
finally {
try {
in.close();
out.close();
s.close();
} catch (Exception e) {
}
}
}
}
Implements a TCP/IP bounce utility (proxy)
/**
* The utillib library.
* More information is available at http://www.jinchess.ru/.
* Copyright (C) 2002 Alexander Maryanovsky.
* All rights reserved.
*
* The utillib library is free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The utillib library is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with utillib library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;
/**
* Implements a TCP/IP bounce utility (proxy). You run bounce specifying which
* port to listen on, which host and on which port to connect to and it will
* act as a proxy relaying information between anyone who connects to it and the
* specified server.
*/
public class Bounce{
/**
* The main method.
*/
public static void main(String [] args){
if (args.length < 3){
printUsage();
System.exit(1);
}
int localPort;
try{
localPort = Integer.parseInt(args[0]);
} catch (NumberFormatException e){
System.err.println("Bad local port value: "+args[0]);
printUsage();
System.exit(2);
return;
}
String hostname = args[1];
int remotePort;
try{
remotePort = Integer.parseInt(args[2]);
} catch (NumberFormatException e){
System.err.println("Bad remote port value: "+args[2]);
printUsage();
System.exit(3);
return;
}
boolean shouldLog = args.length > 3 ? Boolean.valueOf(args[3]).booleanValue() : false;
int numConnections = 0;
try{
ServerSocket ssock = new ServerSocket(localPort);
while (true){
Socket incomingSock = ssock.accept();
Socket outgoingSock = new Socket(hostname, remotePort);
numConnections++;
InputStream incomingIn = incomingSock.getInputStream();
InputStream outgoingIn = outgoingSock.getInputStream();
OutputStream incomingOut = incomingSock.getOutputStream();
OutputStream outgoingOut = outgoingSock.getOutputStream();
if (shouldLog){
String incomingLogName = "in-log-"+incomingSock.getInetAddress().getHostName()+ "("+localPort+")-" + numConnections + ".dat";
String outgoingLogName = "out-log-" + hostname + "("+remotePort + ")-" + numConnections+".dat";
OutputStream incomingLog = new FileOutputStream(incomingLogName);
incomingOut = new MultiOutputStream(incomingOut, incomingLog);
OutputStream outgoingLog = new FileOutputStream(outgoingLogName);
outgoingOut = new MultiOutputStream(outgoingOut, outgoingLog);
}
PumpThread t1 = new PumpThread(incomingIn, outgoingOut);
PumpThread t2 = new PumpThread(outgoingIn, incomingOut);
t1.start();
t2.start();
}
} catch (IOException e){
e.printStackTrace();
System.exit(3);
}
}
/**
* Dumps usage information to the standard error stream.
*/
private static void printUsage(){
System.err.println("Bounce Utility");
System.err.println("Copyright (C) 2002 Alexander Maryanovsky");
System.err.println();
System.err.println("Usage: java free.util.Bounce localPort hostname remotePort [shouldLog]");
System.out.println();
System.out.println("Version 1.01 - 31 Nov. 2002");
}
}
/**
* The utillib library.
* More information is available at http://www.jinchess.ru/.
* Copyright (C) 2002 Alexander Maryanovsky.
* All rights reserved.
*
* The utillib library is free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The utillib library is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with utillib library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* An <code>OutputStream</code> which relays all data written into it into a
* list of given <code>OutputStreams</code>.
*/
class MultiOutputStream extends OutputStream{
/**
* An array containing the OutputStreams we"re relaying data to.
*/
private final OutputStream [] streams;
/**
* Creates a new <code>MultiOutputStream</code> which relays data to the
* specified two <code>OutputStreams</code>. Any <code>null</code> values
* will be silently ignored.
*/
public MultiOutputStream(OutputStream out1, OutputStream out2){
this(new OutputStream[]{out1, out2});
}
/**
* Creates a new <code>MultiOutputStream</code> which relays data to the
* specified <code>OutputStreams</code>. Any <code>null</code> items in the
* array will be silently ignored.
*/
public MultiOutputStream(OutputStream [] streams){
if (streams == null)
throw new IllegalArgumentException("Specified array may not be null");
int count = 0;
for (int i = 0; i < streams.length; i++)
if (streams[i] != null)
count++;
this.streams = new OutputStream[count];
count = 0;
for (int i = 0; i < streams.length; i++){
OutputStream stream = streams[i];
if (stream != null)
this.streams[count++] = stream;
}
}
/**
* Closes all the underlying <code>OutputStreams</code>.
*/
public void close() throws IOException{
for (int i = 0; i < streams.length; i++)
streams[i].close();
}
/**
* Flushes all the underlying <code>OutputStreams</code>.
*/
public void flush() throws IOException{
for (int i = 0; i < streams.length; i++)
streams[i].flush();
}
/**
* Writes the specified <code>byte</code> into the underlying
* <code>OutputStreams</code>.
*/
public void write(int b) throws IOException{
for (int i = 0; i < streams.length; i++)
streams[i].write(b);
}
/**
* Writes the specified amount of bytes from the given byte array starting
* at the specified offset to the underlying <code>OutputStreams</code>.
*/
public void write(byte [] arr, int offset, int length) throws IOException{
for (int i = 0; i < streams.length; i++)
streams[i].write(arr, offset, length);
}
}
/**
* The utillib library.
* More information is available at http://www.jinchess.ru/.
* Copyright (C) 2002 Alexander Maryanovsky.
* All rights reserved.
*
* The utillib library is free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The utillib library is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with utillib library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* A thread which pumps information read from a given input stream into the
* given output stream.
*/
class PumpThread extends Thread{
/**
* The InputStream.
*/
private final InputStream in;
/**
* The OutputStream.
*/
private final OutputStream out;
/**
* The buffer we"re using.
*/
private final byte [] buffer;
/**
* The IOException thrown while reading or writing information, or null if
* none.
*/
private IOException exception;
/**
* Creates a new PumpThread which will pump information from the given
* InputStream into the given OutputStream.
*/
public PumpThread(InputStream in, OutputStream out){
this(in, out, 2048);
}
/**
* Creates a new PumpThread which will pump information from the given
* InputStream into the given OutputStream and will use a buffer of the given
* size.
*/
public PumpThread(InputStream in, OutputStream out, int bufSize){
this(in, out, new byte[bufSize]);
}
/**
* Creates a new PumpThread which will pump information from the given
* InputStream into the given OutputStream and will use the given buffer.
*/
public PumpThread(InputStream in, OutputStream out, byte [] buffer){
this.in = in;
this.out = out;
this.buffer = buffer;
}
/**
* Does the actual pumping.
*/
public void run(){
try{
while (true){
int count = in.read(buffer);
if (count <= 0)
return;
out.write(buffer, 0, count);
}
} catch (IOException e){
exception = e;
}
}
/**
* Returns the exception thrown while reading or writing, or <code>null</code>
* if it finished normally, without throwing an exception (read returned -1).
*
* @throws IllegalStateException if the thread is still alive.
*/
public IOException getException(){
if (isAlive())
throw new IllegalStateException("The thread is still alive");
return exception;
}
}
Scan your computer for ports in use
import java.net.ServerSocket;
public class LocalScan {
public static void main(String[] args) {
for (int i = 1; i < 1023; i++) {
testPort(i);
}
System.out.println("Completed");
}
private static void testPort(int i) {
try {
ServerSocket sock = new ServerSocket(i);
} catch (java.io.IOException e) {
System.out.println("Port " + i + " in use.");
}
}
}
TCP socket monitor
URL utilities class that makes it easy to create new URLs based off of old URLs without having to assemble or parse them yourself
/*
* Copyright (c) 2002-2009 Gargoyle Software Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
/**
* URL utilities class that makes it easy to create new URLs based off of old URLs
* without having to assemble or parse them yourself.
*
* @version $Revision: 4387 $
* @author Daniel Gredler
* @author Martin Tamme
* @author Sudhan Moghe
*/
public final class UrlUtils {
/**
* Disallow instantiation of this class.
*/
private UrlUtils() {
// Empty.
}
/**
* Creates and returns a new URL identical to the specified URL, except using the specified protocol.
* @param u the URL on which to base the returned URL
* @param newProtocol the new protocol to use in the returned URL
* @return a new URL identical to the specified URL, except using the specified protocol
* @throws MalformedURLException if there is a problem creating the new URL
*/
public static URL getUrlWithNewProtocol(final URL u, final String newProtocol) throws MalformedURLException {
return createNewUrl(newProtocol, u.getHost(), u.getPort(), u.getPath(), u.getRef(), u.getQuery());
}
/**
* Creates and returns a new URL identical to the specified URL, except using the specified host.
* @param u the URL on which to base the returned URL
* @param newHost the new host to use in the returned URL
* @return a new URL identical to the specified URL, except using the specified host
* @throws MalformedURLException if there is a problem creating the new URL
*/
public static URL getUrlWithNewHost(final URL u, final String newHost) throws MalformedURLException {
return createNewUrl(u.getProtocol(), newHost, u.getPort(), u.getPath(), u.getRef(), u.getQuery());
}
/**
* Creates and returns a new URL identical to the specified URL, except using the specified port.
* @param u the URL on which to base the returned URL
* @param newPort the new port to use in the returned URL
* @return a new URL identical to the specified URL, except using the specified port
* @throws MalformedURLException if there is a problem creating the new URL
*/
public static URL getUrlWithNewPort(final URL u, final int newPort) throws MalformedURLException {
return createNewUrl(u.getProtocol(), u.getHost(), newPort, u.getPath(), u.getRef(), u.getQuery());
}
/**
* Creates and returns a new URL identical to the specified URL, except using the specified path.
* @param u the URL on which to base the returned URL
* @param newPath the new path to use in the returned URL
* @return a new URL identical to the specified URL, except using the specified path
* @throws MalformedURLException if there is a problem creating the new URL
*/
public static URL getUrlWithNewPath(final URL u, final String newPath) throws MalformedURLException {
return createNewUrl(u.getProtocol(), u.getHost(), u.getPort(), newPath, u.getRef(), u.getQuery());
}
/**
* Creates and returns a new URL identical to the specified URL, except using the specified reference.
* @param u the URL on which to base the returned URL
* @param newRef the new reference to use in the returned URL
* @return a new URL identical to the specified URL, except using the specified reference
* @throws MalformedURLException if there is a problem creating the new URL
*/
public static URL getUrlWithNewRef(final URL u, final String newRef) throws MalformedURLException {
return createNewUrl(u.getProtocol(), u.getHost(), u.getPort(), u.getPath(), newRef, u.getQuery());
}
/**
* Creates and returns a new URL identical to the specified URL, except using the specified query string.
* @param u the URL on which to base the returned URL
* @param newQuery the new query string to use in the returned URL
* @return a new URL identical to the specified URL, except using the specified query string
* @throws MalformedURLException if there is a problem creating the new URL
*/
public static URL getUrlWithNewQuery(final URL u, final String newQuery) throws MalformedURLException {
return createNewUrl(u.getProtocol(), u.getHost(), u.getPort(), u.getPath(), u.getRef(), newQuery);
}
/**
* Creates a new URL based on the specified fragments.
* @param protocol the protocol to use (may not be <tt>null</tt>)
* @param host the host to use (may not be <tt>null</tt>)
* @param port the port to use (may be <tt>-1</tt> if no port is specified)
* @param path the path to use (may be <tt>null</tt> and may omit the initial <tt>"/"</tt>)
* @param ref the reference to use (may be <tt>null</tt> and must not include the <tt>"#"</tt>)
* @param query the query to use (may be <tt>null</tt> and must not include the <tt>"?"</tt>)
* @return a new URL based on the specified fragments
* @throws MalformedURLException if there is a problem creating the new URL
*/
private static URL createNewUrl(final String protocol, final String host, final int port,
final String path, final String ref, final String query) throws MalformedURLException {
final StringBuilder s = new StringBuilder();
s.append(protocol);
s.append("://");
s.append(host);
if (port != -1) {
s.append(":").append(port);
}
if (path != null && path.length() > 0) {
if (!path.startsWith("/")) {
s.append("/");
}
s.append(path);
}
if (query != null) {
s.append("?").append(query);
}
if (ref != null) {
if (!ref.startsWith("#")) {
s.append("#");
}
s.append(ref);
}
final URL url = new URL(s.toString());
return url;
}
/**
* Resolves a given relative URL against a base URL. See
* :
*
* Section 4: Resolving Relative URLs
*
* This section describes an example algorithm for resolving URLs within
* a context in which the URLs may be relative, such that the result is
* always a URL in absolute form. Although this algorithm cannot
* guarantee that the resulting URL will equal that intended by the
* original author, it does guarantee that any valid URL (relative or
* absolute) can be consistently transformed to an absolute form given a
* valid base URL.
*
* @param baseUrl The base URL in which to resolve the specification.
* @param relativeUrl The relative URL to resolve against the base URL.
* @return the resolved specification.
*/
private static Url resolveUrl(final Url baseUrl, final String relativeUrl) {
final Url url = parseUrl(relativeUrl);
// Step 1: The base URL is established according to the rules of
// Section 3. If the base URL is the empty string (unknown),
// the embedded URL is interpreted as an absolute URL and
// we are done.
if (baseUrl == null) {
return url;
}
// Step 2: Both the base and embedded URLs are parsed into their
// component parts as described in Section 2.4.
// a) If the embedded URL is entirely empty, it inherits the
// entire base URL (i.e., is set equal to the base URL)
// and we are done.
if (relativeUrl.length() == 0) {
return new Url(baseUrl);
}
// b) If the embedded URL starts with a scheme name, it is
// interpreted as an absolute URL and we are done.
if (url.scheme_ != null) {
return url;
}
// c) Otherwise, the embedded URL inherits the scheme of
// the base URL.
url.scheme_ = baseUrl.scheme_;
// Step 3: If the embedded URL"s <net_loc> is non-empty, we skip to
// Step 7. Otherwise, the embedded URL inherits the <net_loc>
// (if any) of the base URL.
if (url.location_ != null) {
return url;
}
url.location_ = baseUrl.location_;
// Step 4: If the embedded URL path is preceded by a slash "/", the
// path is not relative and we skip to Step 7.
if ((url.path_ != null) && url.path_.startsWith("/")) {
url.path_ = removeLeadingSlashPoints(url.path_);
return url;
}
// Step 5: If the embedded URL path is empty (and not preceded by a
// slash), then the embedded URL inherits the base URL path,
// and
if (url.path_ == null) {
url.path_ = baseUrl.path_;
// a) if the embedded URL"s <params> is non-empty, we skip to
// step 7; otherwise, it inherits the <params> of the base
// URL (if any) and
if (url.parameters_ != null) {
return url;
}
url.parameters_ = baseUrl.parameters_;
// b) if the embedded URL"s <query> is non-empty, we skip to
// step 7; otherwise, it inherits the <query> of the base
// URL (if any) and we skip to step 7.
if (url.query_ != null) {
return url;
}
url.query_ = baseUrl.query_;
return url;
}
// Step 6: The last segment of the base URL"s path (anything
// following the rightmost slash "/", or the entire path if no
// slash is present) is removed and the embedded URL"s path is
// appended in its place. The following operations are
// then applied, in order, to the new path:
final String basePath = baseUrl.path_;
String path = new String();
if (basePath != null) {
final int lastSlashIndex = basePath.lastIndexOf("/");
if (lastSlashIndex >= 0) {
path = basePath.substring(0, lastSlashIndex + 1);
}
}
else {
path = "/";
}
path = path.concat(url.path_);
// a) All occurrences of "./", where "." is a complete path
// segment, are removed.
int pathSegmentIndex;
while ((pathSegmentIndex = path.indexOf("/./")) >= 0) {
path = path.substring(0, pathSegmentIndex + 1).concat(path.substring(pathSegmentIndex + 3));
}
// b) If the path ends with "." as a complete path segment,
// that "." is removed.
if (path.endsWith("/.")) {
path = path.substring(0, path.length() - 1);
}
// c) All occurrences of "<segment>/../", where <segment> is a
// complete path segment not equal to "..", are removed.
// Removal of these path segments is performed iteratively,
// removing the leftmost matching pattern on each iteration,
// until no matching pattern remains.
while ((pathSegmentIndex = path.indexOf("/../")) > 0) {
final String pathSegment = path.substring(0, pathSegmentIndex);
final int slashIndex = pathSegment.lastIndexOf("/");
if (slashIndex < 0) {
continue;
}
if (!pathSegment.substring(slashIndex).equals("..")) {
path = path.substring(0, slashIndex + 1).concat(path.substring(pathSegmentIndex + 4));
}
}
// d) If the path ends with "<segment>/..", where <segment> is a
// complete path segment not equal to "..", that
// "<segment>/.." is removed.
if (path.endsWith("/..")) {
final String pathSegment = path.substring(0, path.length() - 3);
final int slashIndex = pathSegment.lastIndexOf("/");
if (slashIndex >= 0) {
path = path.substring(0, slashIndex + 1);
}
}
path = removeLeadingSlashPoints(path);
url.path_ = path;
// Step 7: The resulting URL components, including any inherited from
// the base URL, are recombined to give the absolute form of
// the embedded URL.
return url;
}
/**
* "/.." at the beginning should be removed as browsers do (not in RFC)
*/
private static String removeLeadingSlashPoints(String path) {
while (path.startsWith("/..")) {
path = path.substring(3);
}
return path;
}
/**
* Class <tt>Url</tt> represents a Uniform Resource Locator.
*
* @author Martin Tamme
*/
private static class Url {
private String scheme_;
private String location_;
private String path_;
private String parameters_;
private String query_;
private String fragment_;
/**
* Creates a <tt>Url</tt> object.
*/
public Url() {
}
/**
* Creates a <tt>Url</tt> object from the specified
* <tt>Url</tt> object.
*
* @param url a <tt>Url</tt> object.
*/
public Url(final Url url) {
scheme_ = url.scheme_;
location_ = url.location_;
path_ = url.path_;
parameters_ = url.parameters_;
query_ = url.query_;
fragment_ = url.fragment_;
}
/**
* Returns a string representation of the <tt>Url</tt> object.
*
* @return a string representation of the <tt>Url</tt> object.
*/
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
if (scheme_ != null) {
sb.append(scheme_);
sb.append(":");
}
if (location_ != null) {
sb.append("//");
sb.append(location_);
}
if (path_ != null) {
sb.append(path_);
}
if (parameters_ != null) {
sb.append(";");
sb.append(parameters_);
}
if (query_ != null) {
sb.append("?");
sb.append(query_);
}
if (fragment_ != null) {
sb.append("#");
sb.append(fragment_);
}
return sb.toString();
}
}
}
/*
* Copyright (c) 2002-2009 Gargoyle Software Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* String utilities class for utility functions not covered by third party libraries.
*
* @version $Revision: 4002 $
* @author Daniel Gredler
* @author Ahmed Ashour
* @author Martin Tamme
*/
final class StringUtils {
/**
* Disallow instantiation of this class.
*/
private StringUtils() {
// Empty.
}
/**
* Escapes the characters "<", ">" and "&" into their XML entity equivalents. Note that
* sometimes we have to use this method instead of
* {@link org.apache.rumons.lang.StringEscapeUtils#escapeXml(String)} or
* {@link org.apache.rumons.lang.StringEscapeUtils#escapeHtml(String)} because those methods
* escape some unicode characters as well.
*
* @param s the string to escape
* @return the escaped form of the specified string
*/
public static String escapeXmlChars(final String s) {
return s.replace("&", "&").replace("<", "<").replace(">", ">");
}
/**
* Returns <tt>true</tt> if the specified string contains whitespace, <tt>false</tt> otherwise.
*
* @param s the string to check for whitespace
* @return <tt>true</tt> if the specified string contains whitespace, <tt>false</tt> otherwise
*/
public static boolean containsWhitespace(final String s) {
for (final char c : s.toCharArray()) {
if (Character.isWhitespace(c)) {
return true;
}
}
return false;
}
/**
* Returns the index within a given string of the first occurrence of
* the specified search character.
*
* @param s a string.
* @param searchChar a search character.
* @param beginIndex the index to start the search from.
* @param endIndex the index to stop the search.
* @return the index of the first occurrence of the character in the string or <tt>-1</tt>.
*/
public static int indexOf(
final String s,
final char searchChar,
final int beginIndex,
final int endIndex) {
for (int i = beginIndex; i < endIndex; i++) {
if (s.charAt(i) == searchChar) {
return i;
}
}
return -1;
}
/**
* Returns <tt>true</tt> if the specified string is a valid float, possibly triming the string before checking.
* @param s the string to check
* @param trim whether or not to trim the string before checking
* @return <tt>true</tt> if the specified string is a valid float, <tt>false</tt> otherwise
*/
public static boolean isFloat(String s, final boolean trim) {
if (trim) {
s = s.trim();
}
boolean ok;
try {
Float.parseFloat(s);
ok = true;
}
catch (final NumberFormatException e) {
ok = false;
}
return ok;
}
/**
* Returns <tt>true</tt> if the specified list of strings contains the specified string, ignoring case.
* @param strings the strings to search
* @param string the string to search for
* @return <tt>true</tt> if the specified list of strings contains the specified string, ignoring case
*/
public static boolean containsCaseInsensitive(final List<String> strings, String string) {
string = string.toLowerCase();
for (String s : strings) {
if (s.toLowerCase().equals(string)) {
return true;
}
}
return false;
}
}
Using the URL Class (GetURL.java)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Chapter 2 Example
*
* This program uses the standard Java URL class to open a connection to a web
* page and download the contents.
*
* @author Jeff Heaton
* @version 1.0
*/
public class GetURL {
/**
* This method will display the URL specified by the parameter.
*
* @param u
* The URL to display.
*/
static protected void getURL(String u) {
URL url;
InputStream is;
InputStreamReader isr;
BufferedReader r;
String str;
try {
System.out.println("Reading URL: " + u);
url = new URL(u);
is = url.openStream();
isr = new InputStreamReader(is);
r = new BufferedReader(isr);
do {
str = r.readLine();
if (str != null)
System.out.println(str);
} while (str != null);
} catch (MalformedURLException e) {
System.out.println("Must enter a valid URL");
} catch (IOException e) {
System.out.println("Can not connect");
}
}
/**
* Program entry point.
*
* @param args
* Command line arguments. Specified the URL to download.
*/
static public void main(String args[]) {
if (args.length < 1)
System.out.println("Usage: GetURL ");
else
getURL(args[0]);
}
}