View Javadoc

1   /**
2    *  MicroEmulator
3    *  Copyright (C) 2006-2007 Bartek Teodorczyk <barteo@barteo.net>
4    *  Copyright (C) 2006-2007 Vlad Skarzhevskyy
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or (at your option) any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   *
20   *  @version $Id: ConnectorImpl.java 1539 2008-01-11 22:29:21Z vlads $
21   */
22  package org.microemu.microedition.io;
23  
24  import java.io.IOException;
25  import java.lang.reflect.Proxy;
26  import java.security.AccessControlContext;
27  import java.security.AccessController;
28  import java.security.PrivilegedActionException;
29  import java.security.PrivilegedExceptionAction;
30  import java.util.Vector;
31  
32  import javax.microedition.io.Connection;
33  import javax.microedition.io.ConnectionNotFoundException;
34  
35  import org.microemu.cldc.ClosedConnection;
36  import org.microemu.log.Logger;
37  
38  import com.sun.cdc.io.ConnectionBaseInterface;
39  
40  /**
41   * @author vlads Original MicroEmulator implementation of
42   *         javax.microedition.Connector
43   * 
44   * TODO integrate with ImplementationInitialization
45   */
46  public class ConnectorImpl extends ConnectorAdapter {
47  
48  	/* The context to be used when loading classes */
49  	private AccessControlContext acc;
50  
51  	// TODO make this configurable
52  	public static boolean debugConnectionInvocations = false;
53  
54  	private final boolean needPrivilegedCalls = isWebstart();
55  
56  	public ConnectorImpl() {
57  		acc = AccessController.getContext();
58  	}
59  
60  	private static boolean isWebstart() {
61  		try {
62  			return (System.getProperty("javawebstart.version") != null);
63  		} catch (SecurityException e) {
64  			// This is the case for Applet.
65  			return false;
66  		}
67  	}
68  
69  	public Connection open(final String name, final int mode, final boolean timeouts) throws IOException {
70  		try {
71  			return (Connection) AccessController.doPrivileged(new PrivilegedExceptionAction() {
72  				public Object run() throws IOException {
73  					if (debugConnectionInvocations || needPrivilegedCalls) {
74  						return openSecureProxy(name, mode, timeouts, needPrivilegedCalls);
75  					} else {
76  						return openSecure(name, mode, timeouts);
77  					}
78  				}
79  			}, acc);
80  		} catch (PrivilegedActionException e) {
81  			if (e.getCause() instanceof IOException) {
82  				throw (IOException) e.getCause();
83  			}
84  			throw new IOException(e.toString());
85  		}
86  	}
87  
88  	private static Class[] getAllInterfaces(Class klass) {
89  		Vector allInterfaces = new Vector();
90  		Class parent = klass;
91  		while (parent != null) {
92  			Class[] interfaces = parent.getInterfaces();
93  			for (int i = 0; i < interfaces.length; i++) {
94  				allInterfaces.add(interfaces[i]);
95  			}
96  			parent = parent.getSuperclass();
97  		}
98  
99  		return (Class[]) allInterfaces.toArray(new Class[allInterfaces.size()]);
100 	}
101 
102 	private Connection openSecureProxy(String name, int mode, boolean timeouts, boolean needPrivilegedCalls)
103 			throws IOException {
104 		Connection origConnection = openSecure(name, mode, timeouts);
105 		Class connectionClass = null;
106 		Class[] interfaces = getAllInterfaces(origConnection.getClass());
107 		for (int i = 0; i < interfaces.length; i++) {
108 			if (Connection.class.isAssignableFrom(interfaces[i])) {
109 				connectionClass = interfaces[i];
110 				break;
111 			} else if (interfaces[i].getClass().getName().equals(Connection.class.getName())) {
112 				Logger.debugClassLoader("ME2 Connection.class", Connection.class);
113 				Logger.debugClassLoader(name + " Connection.class", interfaces[i]);
114 				Logger.error("Connection interface loaded by different ClassLoader");
115 			}
116 		}
117 		if (connectionClass == null) {
118 			throw new ClassCastException(origConnection.getClass().getName() + " Connection expected");
119 		}
120 		return (Connection) Proxy.newProxyInstance(ConnectorImpl.class.getClassLoader(), interfaces,
121 				new ConnectionInvocationHandler(origConnection, needPrivilegedCalls));
122 	}
123 
124 	private Connection openSecure(String name, int mode, boolean timeouts) throws IOException {
125 		String className = null;
126 		String protocol = null;
127 		try {
128 			try {
129 				protocol = name.substring(0, name.indexOf(':'));
130 				className = "org.microemu.cldc." + protocol + ".Connection";
131 				Class cl = Class.forName(className);
132 				Object inst = cl.newInstance();
133 				if (inst instanceof ConnectionImplementation) {
134 					return ((ConnectionImplementation) inst).openConnection(name, mode, timeouts);
135 				} else {
136 					return ((ClosedConnection) inst).open(name);
137 				}
138 			} catch (ClassNotFoundException e) {
139 				try {
140 					className = "com.sun.cdc.io.j2me." + protocol + ".Protocol";
141 					Class cl = Class.forName(className);
142 					ConnectionBaseInterface base = (ConnectionBaseInterface) cl.newInstance();
143 					return base.openPrim(name.substring(name.indexOf(':') + 1), mode, timeouts);
144 				} catch (ClassNotFoundException ex) {
145 					Logger.debug("connection [" + protocol + "] class not found", e);
146 					Logger.debug("connection [" + protocol + "] class not found", ex);
147 					throw new ConnectionNotFoundException("connection [" + protocol + "] class not found");
148 				}
149 			}
150 		} catch (InstantiationException e) {
151 			Logger.error("Unable to create", className, e);
152 			throw new ConnectionNotFoundException();
153 		} catch (IllegalAccessException e) {
154 			Logger.error("Unable to create", className, e);
155 			throw new ConnectionNotFoundException();
156 		}
157 	}
158 }