162 // Create a thread group for the applet, and start a new
163 // thread to load the applet.
164 String nm = "applet-" + getCode();
165 loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
166 loader.grab(); // Keep this puppy around!
167
168 // 4668479: Option to turn off codebase lookup in AppletClassLoader
169 // during resource requests. [stanley.ho]
170 String param = getParameter("codebase_lookup");
171
172 if (param != null && param.equals("false"))
173 loader.setCodebaseLookup(false);
174 else
175 loader.setCodebaseLookup(true);
176
177
178 ThreadGroup appletGroup = loader.getThreadGroup();
179
180 handler = new Thread(appletGroup, this, "thread " + nm);
181 // set the context class loader for this thread
182 AccessController.doPrivileged(new PrivilegedAction() {
183 @Override
184 public Object run() {
185 handler.setContextClassLoader(loader);
186 return null;
187 }
188 });
189 handler.start();
190 }
191
192 void joinAppletThread() throws InterruptedException {
193 if (handler != null) {
194 handler.join();
195 handler = null;
196 }
197 }
198
199 void release() {
200 if (loader != null) {
201 loader.release();
202 loader = null;
236 @Override
237 public Dimension minimumSize() {
238 return new Dimension(defaultAppletSize.width,
239 defaultAppletSize.height);
240 }
241
242 /**
243 * Preferred size
244 */
245 @Override
246 public Dimension preferredSize() {
247 return new Dimension(currentAppletSize.width,
248 currentAppletSize.height);
249 }
250
251 private AppletListener listeners;
252
253 /**
254 * AppletEvent Queue
255 */
256 private Queue queue = null;
257
258
259 synchronized public void addAppletListener(AppletListener l) {
260 listeners = AppletEventMulticaster.add(listeners, l);
261 }
262
263 synchronized public void removeAppletListener(AppletListener l) {
264 listeners = AppletEventMulticaster.remove(listeners, l);
265 }
266
267 /**
268 * Dispatch event to the listeners..
269 */
270 public void dispatchAppletEvent(int id, Object argument) {
271 //System.out.println("SEND= " + id);
272 if (listeners != null) {
273 AppletEvent evt = new AppletEvent(this, id, argument);
274 listeners.appletStateChanged(evt);
275 }
276 }
277
278 /**
279 * Send an event. Queue it for execution by the handler thread.
280 */
281 public void sendEvent(int id) {
282 synchronized(this) {
283 if (queue == null) {
284 //System.out.println("SEND0= " + id);
285 queue = new Queue();
286 }
287 Integer eventId = Integer.valueOf(id);
288 queue.enqueue(eventId);
289 notifyAll();
290 }
291 if (id == APPLET_QUIT) {
292 try {
293 joinAppletThread(); // Let the applet event handler exit
294 } catch (InterruptedException e) {
295 }
296
297 // AppletClassLoader.release() must be called by a Thread
298 // not within the applet's ThreadGroup
299 if (loader == null)
300 loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
301 release();
302 }
303 }
304
305 /**
306 * Get an event from the queue.
307 */
308 synchronized AppletEvent getNextEvent() throws InterruptedException {
309 while (queue == null || queue.isEmpty()) {
310 wait();
311 }
312 Integer eventId = (Integer)queue.dequeue();
313 return new AppletEvent(this, eventId.intValue(), null);
314 }
315
316 boolean emptyEventQueue() {
317 if ((queue == null) || (queue.isEmpty()))
318 return true;
319 else
320 return false;
321 }
322
323 /**
324 * This kludge is specific to get over AccessControlException thrown during
325 * Applet.stop() or destroy() when static thread is suspended. Set a flag
326 * in AppletClassLoader to indicate that an
327 * AccessControlException for RuntimePermission "modifyThread" or
328 * "modifyThreadGroup" had occurred.
329 */
330 private void setExceptionStatus(AccessControlException e) {
331 Permission p = e.getPermission();
332 if (p instanceof RuntimePermission) {
614 status = APPLET_ERROR;
615 if (e.getMessage() != null) {
616 showAppletStatus("error2", e.getClass().getName(),
617 e.getMessage());
618 } else {
619 showAppletStatus("error", e.getClass().getName());
620 }
621 showAppletException(e);
622 }
623 clearLoadAbortRequest();
624 }
625 }
626
627 /**
628 * Gets most recent focus owner component associated with the given window.
629 * It does that without calling Window.getMostRecentFocusOwner since it
630 * provides its own logic contradicting with setDefautlFocus. Instead, it
631 * calls KeyboardFocusManager directly.
632 */
633 private Component getMostRecentFocusOwnerForWindow(Window w) {
634 Method meth = (Method)AccessController.doPrivileged(new PrivilegedAction() {
635 @Override
636 public Object run() {
637 Method meth = null;
638 try {
639 meth = KeyboardFocusManager.class.getDeclaredMethod(
640 "getMostRecentFocusOwner",
641 new Class[]{Window.class});
642 meth.setAccessible(true);
643 } catch (Exception e) {
644 // Must never happen
645 e.printStackTrace();
646 }
647 return meth;
648 }
649 });
650 if (meth != null) {
651 // Meth refers static method
652 try {
653 return (Component)meth.invoke(null, new Object[] {w});
654 } catch (Exception e) {
655 // Must never happen
656 e.printStackTrace();
657 }
658 }
659 // Will get here if exception was thrown or meth is null
660 return w.getMostRecentFocusOwner();
661 }
971 t.printStackTrace();
972 repaint();
973 }
974
975 /**
976 * Get caching key for classloader cache
977 */
978 public String getClassLoaderCacheKey()
979 {
980 /**
981 * Fixed #4501142: Classloader sharing policy doesn't
982 * take "archive" into account. This will be overridden
983 * by Java Plug-in. [stanleyh]
984 */
985 return getCodeBase().toString();
986 }
987
988 /**
989 * The class loaders
990 */
991 private static HashMap classloaders = new HashMap();
992
993 /**
994 * Flush a class loader.
995 */
996 public static synchronized void flushClassLoader(String key) {
997 classloaders.remove(key);
998 }
999
1000 /**
1001 * Flush all class loaders.
1002 */
1003 public static synchronized void flushClassLoaders() {
1004 classloaders = new HashMap();
1005 }
1006
1007 /**
1008 * This method actually creates an AppletClassLoader.
1009 *
1010 * It can be override by subclasses (such as the Plug-in)
1011 * to provide different classloaders.
1012 */
1013 protected AppletClassLoader createClassLoader(final URL codebase) {
1014 return new AppletClassLoader(codebase);
1015 }
1016
1017 /**
1018 * Get a class loader. Create in a restricted context
1019 */
1020 synchronized AppletClassLoader getClassLoader(final URL codebase, final String key) {
1021 AppletClassLoader c = (AppletClassLoader)classloaders.get(key);
1022 if (c == null) {
1023 AccessControlContext acc =
1024 getAccessControlContext(codebase);
1025 c = (AppletClassLoader)
1026 AccessController.doPrivileged(new PrivilegedAction() {
1027 @Override
1028 public Object run() {
1029 AppletClassLoader ac = createClassLoader(codebase);
1030 /* Should the creation of the classloader be
1031 * within the class synchronized block? Since
1032 * this class is used by the plugin, take care
1033 * to avoid deadlocks, or specialize
1034 * AppletPanel within the plugin. It may take
1035 * an arbitrary amount of time to create a
1036 * class loader (involving getting Jar files
1037 * etc.) and may block unrelated applets from
1038 * finishing createAppletThread (due to the
1039 * class synchronization). If
1040 * createAppletThread does not finish quickly,
1041 * the applet cannot process other messages,
1042 * particularly messages such as destroy
1043 * (which timeout when called from the browser).
1044 */
1045 synchronized (getClass()) {
1046 AppletClassLoader res =
1047 (AppletClassLoader)classloaders.get(key);
1048 if (res == null) {
1049 classloaders.put(key, ac);
1050 return ac;
1051 } else {
1052 return res;
1053 }
1054 }
1055 }
1056 },acc);
1057 }
1058 return c;
1059 }
1060
1061 /**
1062 * get the context for the AppletClassLoader we are creating.
1063 * the context is granted permission to create the class loader,
1064 * connnect to the codebase, and whatever else the policy grants
1065 * to all codebases.
1066 */
1067 private AccessControlContext getAccessControlContext(final URL codebase) {
1068
1069 PermissionCollection perms = (PermissionCollection)
1070 AccessController.doPrivileged(new PrivilegedAction() {
1071 @Override
1072 public Object run() {
1073 Policy p = java.security.Policy.getPolicy();
1074 if (p != null) {
1075 return p.getPermissions(new CodeSource(null,
1076 (java.security.cert.Certificate[]) null));
1077 } else {
1078 return null;
1079 }
1080 }
1081 });
1082
1083 if (perms == null)
1084 perms = new Permissions();
1085
1086 //XXX: this is needed to be able to create the classloader itself!
1087
1088 perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
1089
1090 Permission p;
1091 java.net.URLConnection urlConnection = null;
1092 try {
1155 // is created in main thread group. Thus, when certain
1156 // AWT/Swing events are generated, the events will be
1157 // dispatched through the wrong event dispatch thread.
1158 //
1159 // To fix this, we rearrange the AppContext with the frame,
1160 // so the proper event queue will be looked up.
1161 //
1162 // Swing also maintains a Frame list for the AppContext,
1163 // so we will have to rearrange it as well.
1164
1165 // Check if frame's AppContext has already been set properly
1166 AppContext oldAppContext = SunToolkit.targetToAppContext(frame);
1167
1168 if (oldAppContext == newAppContext)
1169 return;
1170
1171 // Synchronization on Window.class is needed for locking the
1172 // critical section of the window list in AppContext.
1173 synchronized (Window.class)
1174 {
1175 WeakReference weakRef = null;
1176 // Remove frame from the Window list in wrong AppContext
1177 {
1178 // Lookup current frame's AppContext
1179 Vector<WeakReference<Window>> windowList = (Vector<WeakReference<Window>>)oldAppContext.get(Window.class);
1180 if (windowList != null) {
1181 for (WeakReference ref : windowList) {
1182 if (ref.get() == frame) {
1183 weakRef = ref;
1184 break;
1185 }
1186 }
1187 // Remove frame from wrong AppContext
1188 if (weakRef != null)
1189 windowList.remove(weakRef);
1190 }
1191 }
1192
1193 // Put the frame into the applet's AppContext map
1194 SunToolkit.insertTargetMapping(frame, newAppContext);
1195
1196 // Insert frame into the Window list in the applet's AppContext map
1197 {
1198 Vector<WeakReference<Window>> windowList = (Vector)newAppContext.get(Window.class);
1199 if (windowList == null) {
1200 windowList = new Vector<WeakReference<Window>>();
1201 newAppContext.put(Window.class, windowList);
1202 }
1203 // use the same weakRef here as it is used elsewhere
1204 windowList.add(weakRef);
1205 }
1206 }
1207 }
1208
1209 // Flag to indicate if applet is targeted for JDK 1.1.
1210 private boolean jdk11Applet = false;
1211
1212 // Flag to indicate if applet is targeted for JDK 1.2.
1213 private boolean jdk12Applet = false;
1214
1215 /**
1216 * Determine JDK level of an applet.
1217 */
1218 private void findAppletJDKLevel(Applet applet)
1219 {
1220 // To determine the JDK level of an applet, the
1221 // most reliable way is to check the major version
1222 // of the applet class file.
1223
1224 // synchronized on applet class object, so calling from
1225 // different instances of the same applet will be
1226 // serialized.
1227 Class appletClass = applet.getClass();
1228
1229 synchronized(appletClass) {
1230 // Determine if the JDK level of an applet has been
1231 // checked before.
1232 Boolean jdk11Target = loader.isJDK11Target(appletClass);
1233 Boolean jdk12Target = loader.isJDK12Target(appletClass);
1234
1235 // if applet JDK level has been checked before, retrieve
1236 // value and return.
1237 if (jdk11Target != null || jdk12Target != null) {
1238 jdk11Applet = (jdk11Target == null) ? false : jdk11Target.booleanValue();
1239 jdk12Applet = (jdk12Target == null) ? false : jdk12Target.booleanValue();
1240 return;
1241 }
1242
1243 String name = appletClass.getName();
1244
1245 // first convert any '.' to '/'
1246 name = name.replace('.', '/');
1247
|
162 // Create a thread group for the applet, and start a new
163 // thread to load the applet.
164 String nm = "applet-" + getCode();
165 loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
166 loader.grab(); // Keep this puppy around!
167
168 // 4668479: Option to turn off codebase lookup in AppletClassLoader
169 // during resource requests. [stanley.ho]
170 String param = getParameter("codebase_lookup");
171
172 if (param != null && param.equals("false"))
173 loader.setCodebaseLookup(false);
174 else
175 loader.setCodebaseLookup(true);
176
177
178 ThreadGroup appletGroup = loader.getThreadGroup();
179
180 handler = new Thread(appletGroup, this, "thread " + nm);
181 // set the context class loader for this thread
182 AccessController.doPrivileged(new PrivilegedAction<Object>() {
183 @Override
184 public Object run() {
185 handler.setContextClassLoader(loader);
186 return null;
187 }
188 });
189 handler.start();
190 }
191
192 void joinAppletThread() throws InterruptedException {
193 if (handler != null) {
194 handler.join();
195 handler = null;
196 }
197 }
198
199 void release() {
200 if (loader != null) {
201 loader.release();
202 loader = null;
236 @Override
237 public Dimension minimumSize() {
238 return new Dimension(defaultAppletSize.width,
239 defaultAppletSize.height);
240 }
241
242 /**
243 * Preferred size
244 */
245 @Override
246 public Dimension preferredSize() {
247 return new Dimension(currentAppletSize.width,
248 currentAppletSize.height);
249 }
250
251 private AppletListener listeners;
252
253 /**
254 * AppletEvent Queue
255 */
256 private Queue<Integer> queue = null;
257
258
259 synchronized public void addAppletListener(AppletListener l) {
260 listeners = AppletEventMulticaster.add(listeners, l);
261 }
262
263 synchronized public void removeAppletListener(AppletListener l) {
264 listeners = AppletEventMulticaster.remove(listeners, l);
265 }
266
267 /**
268 * Dispatch event to the listeners..
269 */
270 public void dispatchAppletEvent(int id, Object argument) {
271 //System.out.println("SEND= " + id);
272 if (listeners != null) {
273 AppletEvent evt = new AppletEvent(this, id, argument);
274 listeners.appletStateChanged(evt);
275 }
276 }
277
278 /**
279 * Send an event. Queue it for execution by the handler thread.
280 */
281 public void sendEvent(int id) {
282 synchronized(this) {
283 if (queue == null) {
284 //System.out.println("SEND0= " + id);
285 queue = new Queue<>();
286 }
287 Integer eventId = Integer.valueOf(id);
288 queue.enqueue(eventId);
289 notifyAll();
290 }
291 if (id == APPLET_QUIT) {
292 try {
293 joinAppletThread(); // Let the applet event handler exit
294 } catch (InterruptedException e) {
295 }
296
297 // AppletClassLoader.release() must be called by a Thread
298 // not within the applet's ThreadGroup
299 if (loader == null)
300 loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
301 release();
302 }
303 }
304
305 /**
306 * Get an event from the queue.
307 */
308 synchronized AppletEvent getNextEvent() throws InterruptedException {
309 while (queue == null || queue.isEmpty()) {
310 wait();
311 }
312 Integer eventId = queue.dequeue();
313 return new AppletEvent(this, eventId.intValue(), null);
314 }
315
316 boolean emptyEventQueue() {
317 if ((queue == null) || (queue.isEmpty()))
318 return true;
319 else
320 return false;
321 }
322
323 /**
324 * This kludge is specific to get over AccessControlException thrown during
325 * Applet.stop() or destroy() when static thread is suspended. Set a flag
326 * in AppletClassLoader to indicate that an
327 * AccessControlException for RuntimePermission "modifyThread" or
328 * "modifyThreadGroup" had occurred.
329 */
330 private void setExceptionStatus(AccessControlException e) {
331 Permission p = e.getPermission();
332 if (p instanceof RuntimePermission) {
614 status = APPLET_ERROR;
615 if (e.getMessage() != null) {
616 showAppletStatus("error2", e.getClass().getName(),
617 e.getMessage());
618 } else {
619 showAppletStatus("error", e.getClass().getName());
620 }
621 showAppletException(e);
622 }
623 clearLoadAbortRequest();
624 }
625 }
626
627 /**
628 * Gets most recent focus owner component associated with the given window.
629 * It does that without calling Window.getMostRecentFocusOwner since it
630 * provides its own logic contradicting with setDefautlFocus. Instead, it
631 * calls KeyboardFocusManager directly.
632 */
633 private Component getMostRecentFocusOwnerForWindow(Window w) {
634 Method meth = AccessController.doPrivileged(
635 new PrivilegedAction<Method>() {
636 @Override
637 public Method run() {
638 Method meth = null;
639 try {
640 meth = KeyboardFocusManager.class.getDeclaredMethod(
641 "getMostRecentFocusOwner",
642 new Class<?>[]{Window.class});
643 meth.setAccessible(true);
644 } catch (Exception e) {
645 // Must never happen
646 e.printStackTrace();
647 }
648 return meth;
649 }
650 });
651 if (meth != null) {
652 // Meth refers static method
653 try {
654 return (Component)meth.invoke(null, new Object[] {w});
655 } catch (Exception e) {
656 // Must never happen
657 e.printStackTrace();
658 }
659 }
660 // Will get here if exception was thrown or meth is null
661 return w.getMostRecentFocusOwner();
662 }
972 t.printStackTrace();
973 repaint();
974 }
975
976 /**
977 * Get caching key for classloader cache
978 */
979 public String getClassLoaderCacheKey()
980 {
981 /**
982 * Fixed #4501142: Classloader sharing policy doesn't
983 * take "archive" into account. This will be overridden
984 * by Java Plug-in. [stanleyh]
985 */
986 return getCodeBase().toString();
987 }
988
989 /**
990 * The class loaders
991 */
992 private static HashMap<String, AppletClassLoader> classloaders = new HashMap<>();
993
994 /**
995 * Flush a class loader.
996 */
997 public static synchronized void flushClassLoader(String key) {
998 classloaders.remove(key);
999 }
1000
1001 /**
1002 * Flush all class loaders.
1003 */
1004 public static synchronized void flushClassLoaders() {
1005 classloaders = new HashMap<>();
1006 }
1007
1008 /**
1009 * This method actually creates an AppletClassLoader.
1010 *
1011 * It can be override by subclasses (such as the Plug-in)
1012 * to provide different classloaders.
1013 */
1014 protected AppletClassLoader createClassLoader(final URL codebase) {
1015 return new AppletClassLoader(codebase);
1016 }
1017
1018 /**
1019 * Get a class loader. Create in a restricted context
1020 */
1021 synchronized AppletClassLoader getClassLoader(final URL codebase, final String key) {
1022 AppletClassLoader c = classloaders.get(key);
1023 if (c == null) {
1024 AccessControlContext acc =
1025 getAccessControlContext(codebase);
1026 c = AccessController.doPrivileged(
1027 new PrivilegedAction<AppletClassLoader>() {
1028 @Override
1029 public AppletClassLoader run() {
1030 AppletClassLoader ac = createClassLoader(codebase);
1031 /* Should the creation of the classloader be
1032 * within the class synchronized block? Since
1033 * this class is used by the plugin, take care
1034 * to avoid deadlocks, or specialize
1035 * AppletPanel within the plugin. It may take
1036 * an arbitrary amount of time to create a
1037 * class loader (involving getting Jar files
1038 * etc.) and may block unrelated applets from
1039 * finishing createAppletThread (due to the
1040 * class synchronization). If
1041 * createAppletThread does not finish quickly,
1042 * the applet cannot process other messages,
1043 * particularly messages such as destroy
1044 * (which timeout when called from the browser).
1045 */
1046 synchronized (getClass()) {
1047 AppletClassLoader res = classloaders.get(key);
1048 if (res == null) {
1049 classloaders.put(key, ac);
1050 return ac;
1051 } else {
1052 return res;
1053 }
1054 }
1055 }
1056 },acc);
1057 }
1058 return c;
1059 }
1060
1061 /**
1062 * get the context for the AppletClassLoader we are creating.
1063 * the context is granted permission to create the class loader,
1064 * connnect to the codebase, and whatever else the policy grants
1065 * to all codebases.
1066 */
1067 private AccessControlContext getAccessControlContext(final URL codebase) {
1068
1069 PermissionCollection perms = AccessController.doPrivileged(
1070 new PrivilegedAction<PermissionCollection>() {
1071 @Override
1072 public PermissionCollection run() {
1073 Policy p = java.security.Policy.getPolicy();
1074 if (p != null) {
1075 return p.getPermissions(new CodeSource(null,
1076 (java.security.cert.Certificate[]) null));
1077 } else {
1078 return null;
1079 }
1080 }
1081 });
1082
1083 if (perms == null)
1084 perms = new Permissions();
1085
1086 //XXX: this is needed to be able to create the classloader itself!
1087
1088 perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
1089
1090 Permission p;
1091 java.net.URLConnection urlConnection = null;
1092 try {
1155 // is created in main thread group. Thus, when certain
1156 // AWT/Swing events are generated, the events will be
1157 // dispatched through the wrong event dispatch thread.
1158 //
1159 // To fix this, we rearrange the AppContext with the frame,
1160 // so the proper event queue will be looked up.
1161 //
1162 // Swing also maintains a Frame list for the AppContext,
1163 // so we will have to rearrange it as well.
1164
1165 // Check if frame's AppContext has already been set properly
1166 AppContext oldAppContext = SunToolkit.targetToAppContext(frame);
1167
1168 if (oldAppContext == newAppContext)
1169 return;
1170
1171 // Synchronization on Window.class is needed for locking the
1172 // critical section of the window list in AppContext.
1173 synchronized (Window.class)
1174 {
1175 WeakReference<Window> weakRef = null;
1176 // Remove frame from the Window list in wrong AppContext
1177 {
1178 // Lookup current frame's AppContext
1179 @SuppressWarnings("unchecked")
1180 Vector<WeakReference<Window>> windowList =
1181 (Vector<WeakReference<Window>>)oldAppContext.get(Window.class);
1182 if (windowList != null) {
1183 for (WeakReference<Window> ref : windowList) {
1184 if (ref.get() == frame) {
1185 weakRef = ref;
1186 break;
1187 }
1188 }
1189 // Remove frame from wrong AppContext
1190 if (weakRef != null)
1191 windowList.remove(weakRef);
1192 }
1193 }
1194
1195 // Put the frame into the applet's AppContext map
1196 SunToolkit.insertTargetMapping(frame, newAppContext);
1197
1198 // Insert frame into the Window list in the applet's AppContext map
1199 {
1200 @SuppressWarnings("unchecked")
1201 Vector<WeakReference<Window>> windowList =
1202 (Vector<WeakReference<Window>>)newAppContext.get(Window.class);
1203 if (windowList == null) {
1204 windowList = new Vector<WeakReference<Window>>();
1205 newAppContext.put(Window.class, windowList);
1206 }
1207 // use the same weakRef here as it is used elsewhere
1208 windowList.add(weakRef);
1209 }
1210 }
1211 }
1212
1213 // Flag to indicate if applet is targeted for JDK 1.1.
1214 private boolean jdk11Applet = false;
1215
1216 // Flag to indicate if applet is targeted for JDK 1.2.
1217 private boolean jdk12Applet = false;
1218
1219 /**
1220 * Determine JDK level of an applet.
1221 */
1222 private void findAppletJDKLevel(Applet applet)
1223 {
1224 // To determine the JDK level of an applet, the
1225 // most reliable way is to check the major version
1226 // of the applet class file.
1227
1228 // synchronized on applet class object, so calling from
1229 // different instances of the same applet will be
1230 // serialized.
1231 Class<?> appletClass = applet.getClass();
1232
1233 synchronized(appletClass) {
1234 // Determine if the JDK level of an applet has been
1235 // checked before.
1236 Boolean jdk11Target = loader.isJDK11Target(appletClass);
1237 Boolean jdk12Target = loader.isJDK12Target(appletClass);
1238
1239 // if applet JDK level has been checked before, retrieve
1240 // value and return.
1241 if (jdk11Target != null || jdk12Target != null) {
1242 jdk11Applet = (jdk11Target == null) ? false : jdk11Target.booleanValue();
1243 jdk12Applet = (jdk12Target == null) ? false : jdk12Target.booleanValue();
1244 return;
1245 }
1246
1247 String name = appletClass.getName();
1248
1249 // first convert any '.' to '/'
1250 name = name.replace('.', '/');
1251
|