/*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program 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
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package com.sun.cdc.io;
import java.io.*;
import javax.microedition.io.*;
import sun.security.action.GetPropertyAction;
public class InternalConnectorImpl implements InternalConnector {
protected ClassLoader protocolClassLoader;
protected String classRoot;
/*
* The default for class root is <code>com.sun.cdc.io</code> and can be
* replaced by setting the system property
* <code>javax.microedition.io.Connector.protocolpath</code>.
*
* @return class root
*/
protected String getClassRoot() {
if (classRoot != null) {
return classRoot;
}
String profileTemp = null;
try {
/*
* Check to see if there is a property override for the dynamic
* building of class root.
*/
classRoot =(String)java.security.AccessController.doPrivileged(
new GetPropertyAction(
"javax.microedition.io.Connector.protocolpath"));
} catch (Throwable t) {
// do nothing
}
if (classRoot == null) {
classRoot = "com.sun.cdc.io";
}
return classRoot;
}
protected ClassLoader getProtocolClassLoader() {
if (protocolClassLoader != null) {
return protocolClassLoader;
}
protocolClassLoader = this.getClass().getClassLoader();
return protocolClassLoader;
}
/*
* Create and open a Connection.
* <p>
* There are 2 ways to find a connection implementation.
* 1. Get the class name from a system property generated in the form of:
* <pre>
* j2me.{connection protocol}.protocol
* </pre>
* 2. Use the class root (see getClassRoot) and the connection
* protocol to dynamically construct a class name in the the form of:
* <pre>
* {class root}.j2me.{connection protocol}.Protocol
* </pre>
* The connection protocol is parsed from the <code>name</code> parameter
* which takes the form of:
* <pre>
* {connection protocol}:{protocol specific part}
* </pre>
* In order to avoid problems with illegal
* class file names, all the '-' characters in the connection protocol
* are automatically converted into '_' characters.
* <p>
* Additionally the protocol specific part is parsed from the name
* parameter and passed to the connection's factory method.
*
* @param name The URL for the connection
* @param mode The access mode
* @param timeouts A flag to indicate that the caller
* wants timeout exceptions
*
* @return A new Connection object
*
* @exception IllegalArgumentException If a parameter is invalid.
* @exception ConnectionNotFoundException If the target of the
* name cannot be found, or if the requested protocol type
* is not supported.
* @exception IOException If some other kind of I/O error occurs.
* @exception IllegalArgumentException If a parameter is invalid.
*/
public Connection open(String name, int mode, boolean timeouts)
throws IOException {
String oemPrefix= "";
/* Test for null argument */
if (name == null) {
throw new IllegalArgumentException("Null URL");
}
try {
/*
* Check for OEM specific http and https handler override.
*/
oemPrefix =(String)java.security.AccessController.doPrivileged(
new GetPropertyAction(
"oem.http.handler.prefix", ""));
} catch (Throwable t) {
// do nothing
}
if (name.startsWith("http")) {
name = oemPrefix + name;
}
/* Look for : as in "http:", "file:", or whatever */
int colon = name.indexOf(':');
if (colon == -1) {
throw new IllegalArgumentException("Illegal protocol");
}
try {
String protocol;
/* Strip off the protocol name */
protocol = name.substring(0, colon).toLowerCase();
checkProtocol(protocol);
/* Strip off the rest of the string */
name = name.substring(colon + 1);
/*
* Convert all the '-' characters in the protocol
* name to '_' characters (dashes are not allowed
* in class names). This operation creates garbage
* only if the protocol name actually contains dashes
*/
protocol = protocol.replace('-', '_');
/*
* Use the platform and protocol names to look up
* a class to implement the connection
*/
String className = getClassRoot() + "." + "j2me"+ "." + protocol +
".Protocol";
Class clazz = Class.forName(className, true,
getProtocolClassLoader());
/* Construct a new instance of the protocol */
ConnectionBaseInterface uc =
(ConnectionBaseInterface)clazz.newInstance();
/* Open the connection, and return it */
return uc.openPrim(name, mode, timeouts);
} catch (InstantiationException x) {
throw new IOException(x.toString());
} catch (IllegalAccessException x) {
throw new IOException(x.toString());
} catch (ClassCastException x) {
throw new IOException(x.toString());
} catch (ClassNotFoundException x) {
throw new ConnectionNotFoundException(
"The requested protocol does not exist " + name);
}
}
/** Characters allowed as first char of scheme. */
private static final String ALLOWED_FIRST_CHAR =
"abcdefghijklmnopqrstuvwxyz";
/** Characters allowed after the first char of scheme. */
private static final String ALLOWED_CHAR =
ALLOWED_FIRST_CHAR + "0123456789+-.";
/**
* Checks validity of protocol (a.k.a scheme) string.
*
* <p>
* Throws <code>IllegalArgumentException</code> if string is invalid.
* </p>
*
* <p>
* Note: <code>URL</code> class might be used, but it might be better
* to be maximally independent of external stuff.
* </p>
*
* @param protocol string to check (must be lower case)
*/
public static void checkProtocol(final String protocol) {
if (protocol.length() == 0) {
throw new IllegalArgumentException("protocols is empty string");
}
if (!isOneOf(protocol.charAt(0), ALLOWED_FIRST_CHAR)) {
throw new IllegalArgumentException("wrong leading character: "
+ protocol);
}
for (int i = 1; i < protocol.length(); i++) {
final char c = protocol.charAt(i);
if (!isOneOf(c, ALLOWED_CHAR)) {
throw new IllegalArgumentException("wrong character at "
+ i + ": " + protocol);
}
}
}
/**
* Checks if the character is one of the given set.
*
* @param c character to check
* @param set set to check against
*
* @return <code>true</code> iff <code>c</code> belongs to <code>set</code>
*/
private static boolean isOneOf(final char c, final String set) {
return set.indexOf(c) != -1;
}
}