View Javadoc

1   /**
2    *  MicroEmulator
3    *  Copyright (C) 2006-2007 Bartek Teodorczyk <barteo@barteo.net>
4    *  Copyright (C) 2006-2007 Vlad Skarzhevskyy
5    *
6    *  It is licensed under the following two licenses as alternatives:
7    *    1. GNU Lesser General Public License (the "LGPL") version 2.1 or any newer version
8    *    2. Apache License (the "AL") Version 2.0
9    *
10   *  You may not use this file except in compliance with at least one of
11   *  the above two licenses.
12   *
13   *  You may obtain a copy of the LGPL at
14   *      http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
15   *
16   *  You may obtain a copy of the AL at
17   *      http://www.apache.org/licenses/LICENSE-2.0
18   *
19   *  Unless required by applicable law or agreed to in writing, software
20   *  distributed under the License is distributed on an "AS IS" BASIS,
21   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22   *  See the LGPL or the AL for the specific language governing permissions and
23   *  limitations.
24   *
25   *  @version $Id: ImplFactory.java 1683 2008-04-09 20:59:35Z vlads $
26   */
27  package org.microemu.microedition;
28  
29  import java.security.AccessControlContext;
30  import java.security.AccessController;
31  import java.security.PrivilegedExceptionAction;
32  import java.util.HashMap;
33  import java.util.Map;
34  
35  import org.microemu.microedition.io.ConnectorDelegate;
36  
37  /**
38   * This class allows to unbind implemenation with CLDC or MIDP declarations.
39   * 
40   * @author vlads
41   * 
42   */
43  public class ImplFactory {
44  
45  	public static final String DEFAULT = "org.microemu.default";
46  
47  	private static final String INTERFACE_NAME_SUFIX = "Delegate";
48  
49  	private static final String IMPLEMENTATION_NAME_SUFIX = "Impl";
50  
51  	private Map implementations = new HashMap();
52  
53  	private Map implementationsGCF = new HashMap();
54  
55  	/* The context to be used when loading classes and resources */
56  	private AccessControlContext acc;
57  
58  	/**
59  	 * Allow default initialization. In Secure environment instance() should be
60  	 * called initialy from secure contex.
61  	 */
62  	private static class SingletonHolder {
63  		private static ImplFactory instance = new ImplFactory();
64  	}
65  
66  	private ImplFactory() {
67  		acc = AccessController.getContext();
68  	}
69  
70  	public static ImplFactory instance() {
71  		return SingletonHolder.instance;
72  	}
73  
74  	public static void register(Class delegate, Class implementationClass) {
75  		instance().implementations.put(delegate, implementationClass);
76  	}
77  
78  	public static void register(Class delegate, Object implementationInstance) {
79  		instance().implementations.put(delegate, implementationInstance);
80  	}
81  
82  	public static void unregister(Class delegate, Class implementation) {
83  		// TODO implement
84  	}
85  
86  	/**
87  	 * 
88  	 * Register Generic Connection Framework scheme implementation.
89  	 * 
90  	 * @param implementation
91  	 *            instance of ConnectorDelegate
92  	 * @param scheme
93  	 */
94  	public static void registerGCF(String scheme, Object implementation) {
95  		if (!ConnectorDelegate.class.isAssignableFrom(implementation.getClass())) {
96  			throw new IllegalArgumentException();
97  		}
98  		if (scheme == null) {
99  			scheme = DEFAULT;
100 		}
101 		Object impl = instance().implementationsGCF.get(scheme);
102 		if (impl instanceof ImplementationUnloadable) {
103 			((ImplementationUnloadable) impl).unregisterImplementation();
104 		}
105 		instance().implementationsGCF.put(scheme, implementation);
106 	}
107 
108 	public static void unregistedGCF(String scheme, Object implementation) {
109 		if (!ConnectorDelegate.class.isAssignableFrom(implementation.getClass())) {
110 			throw new IllegalArgumentException();
111 		}
112 		if (scheme == null) {
113 			scheme = DEFAULT;
114 		}
115 		Object impl = instance().implementationsGCF.get(scheme);
116 		if (impl == implementation) {
117 			instance().implementationsGCF.remove(scheme);
118 		}
119 	}
120 
121 	private Object getDefaultImplementation(Class delegateInterface) {
122 		try {
123 			String name = delegateInterface.getName();
124 			if (name.endsWith(INTERFACE_NAME_SUFIX)) {
125 				name = name.substring(0, name.length() - INTERFACE_NAME_SUFIX.length());
126 			}
127 			final String implClassName = name + IMPLEMENTATION_NAME_SUFIX;
128 			return AccessController.doPrivileged(new PrivilegedExceptionAction() {
129 				public Object run() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
130 					Class implClass = ImplFactory.class.getClassLoader().loadClass(implClassName);
131 					try {
132 						implClass.getConstructor(null);
133 					} catch (NoSuchMethodException e) {
134 						throw new InstantiationException("No default constructor in class " + implClassName);
135 					}
136 					return implClass.newInstance();
137 				}
138 			}, acc);
139 		} catch (Throwable e) {
140 			throw new RuntimeException("Unable create " + delegateInterface.getName() + " implementation", e);
141 		}
142 	}
143 
144 	private Object implementationNewInstance(final Class implClass) {
145 		try {
146 			return AccessController.doPrivileged(new PrivilegedExceptionAction() {
147 				public Object run() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
148 					return implClass.newInstance();
149 				}
150 			}, acc);
151 		} catch (Throwable e) {
152 			throw new RuntimeException("Unable create " + implClass.getName() + " implementation", e);
153 		}
154 	}
155 
156 	/**
157 	 * 
158 	 * @param name
159 	 *            The URL for the connection.
160 	 * @return UTL scheme
161 	 */
162 	public static String getCGFScheme(String name) {
163 		return name.substring(0, name.indexOf(':'));
164 	}
165 
166 	/**
167 	 * 
168 	 * @param name
169 	 *            The URL for the connection.
170 	 * @return
171 	 */
172 	public static ConnectorDelegate getCGFImplementation(String name) {
173 		String scheme = getCGFScheme(name);
174 		ConnectorDelegate impl = (ConnectorDelegate) instance().implementationsGCF.get(scheme);
175 		if (impl != null) {
176 			return impl;
177 		}
178 		impl = (ConnectorDelegate) instance().implementationsGCF.get(DEFAULT);
179 		if (impl != null) {
180 			return impl;
181 		}
182 		return (ConnectorDelegate) instance().getDefaultImplementation(ConnectorDelegate.class);
183 	}
184 
185 	// public static Implementation getImplementation(Class origClass, Object[]
186 	// constructorArgs) {
187 	// //TO-DO constructorArgs
188 	// return getImplementation(origClass);
189 	// }
190 
191 	public static Implementation getImplementation(Class origClass, Class delegateInterface) {
192 		// if called from implementation constructor return null to avoid
193 		// recurive calls!
194 		// TODO can be done using thread stack analyse or ThreadLocal
195 		Object impl = instance().implementations.get(delegateInterface);
196 		// debugClassLoader(Implementation.class);
197 		// debugClassLoader(origClass);
198 		// debugClassLoader(delegateInterface);
199 		// debugClassLoader(o);
200 
201 		if (impl != null) {
202 			if (impl instanceof Class) {
203 				return (Implementation) instance().implementationNewInstance((Class) impl);
204 			} else {
205 				return (Implementation) impl;
206 			}
207 		}
208 		return (Implementation) instance().getDefaultImplementation(delegateInterface);
209 	}
210 
211 	// private static void debugClassLoader(Object obj) {
212 	// if (obj == null) {
213 	// System.out.print("no class");
214 	// return;
215 	// }
216 	// Class klass;
217 	// if (obj instanceof Class) {
218 	// klass = (Class)obj;
219 	// System.out.print("class ");
220 	// } else {
221 	// klass = obj.getClass();
222 	// System.out.print("instance ");
223 	// }
224 	// System.out.print(klass.getName() + " loaded by ");
225 	// if (klass.getClassLoader() != null) {
226 	// System.out.print(klass.getClassLoader().hashCode());
227 	// } else {
228 	// System.out.print("system");
229 	// }
230 	// System.out.println();
231 	// }
232 }