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: MIDletThread.java 1354 2007-09-28 15:35:10Z vlads $
21   */
22  package org.microemu.app.util;
23  
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.WeakHashMap;
27  
28  import org.microemu.MIDletBridge;
29  import org.microemu.MIDletContext;
30  import org.microemu.log.Logger;
31  import org.microemu.util.ThreadUtils;
32  
33  /**
34   * MIDletContext is used to hold keys to running Threads created by  MIDlet  
35   * 
36   * @author vlads
37   */
38  public class MIDletThread extends Thread {
39  
40  	public static int graceTerminationPeriod = 5000;
41  	
42  	private static final String THREAD_NAME_PREFIX = "MIDletThread-";
43  	
44  	private static boolean terminator = false;
45  	
46  	private static Map midlets = new WeakHashMap();
47  	
48      private static int threadInitNumber;
49      
50      private String callLocation;
51      
52      private static synchronized int nextThreadNum() {
53      	return threadInitNumber++;
54      }
55      
56  	public MIDletThread() {
57  		super(THREAD_NAME_PREFIX + nextThreadNum());
58  		register(this);
59  	}
60  	
61  	public MIDletThread(Runnable target) {
62  		super(target, THREAD_NAME_PREFIX + nextThreadNum());
63  		register(this);
64  	}
65  	
66  	public MIDletThread(Runnable target, String name) {
67  		super(target, THREAD_NAME_PREFIX + name);
68  		register(this);
69  	}
70  	
71  	public MIDletThread(String name) {
72  		super(THREAD_NAME_PREFIX + name);
73  		register(this);
74  	}
75  	
76  	private static void register(MIDletThread thread) {
77  		MIDletContext midletContext = MIDletBridge.getMIDletContext();
78  		if (midletContext == null) {
79  			Logger.error("Creating thread with no MIDlet context", new Throwable());
80  			return;
81  		}
82  		thread.callLocation  = ThreadUtils.getCallLocation(MIDletThread.class.getName());
83  		Map threads = (Map)midlets.get(midletContext);
84  		if (threads == null) {
85  			threads = new WeakHashMap();
86  			midlets.put(midletContext, threads);
87  		}
88  		threads.put(thread, midletContext);
89  	}
90  	
91  	//TODO overrite run() in user Threads using ASM
92  	public void run() {
93  		 try {
94  			super.run();
95  		} catch (Throwable e) {
96  			Logger.debug("MIDletThread throw", e);
97  		}
98  		//Logger.debug("thread ends, created from " + callLocation);	
99  	 }
100 	
101 	/**
102 	 * Terminate all Threads created by MIDlet
103 	 * @param previousMidletAccess
104 	 */
105 	public static void contextDestroyed(final MIDletContext midletContext) {
106 		if (midletContext == null) {
107 			return;
108 		}
109 		final Map threads = (Map)midlets.remove(midletContext);
110 		if ((threads != null) && (threads.size() != 0)) {
111 			terminator = true;
112 			Thread terminator = new Thread("MIDletThreadsTerminator") {
113 				public void run() {
114 					terminateThreads(threads);
115 				}
116 			};
117 			terminator.start();
118 		}
119 		MIDletTimer.contextDestroyed(midletContext);
120 	}
121 	
122 	public static boolean hasRunningThreads(MIDletContext midletContext) {
123 		//return (midlets.get(midletContext) != null);
124 		return terminator;
125 	}
126 	
127 	private static void terminateThreads(Map threads) {
128 		long endTime = System.currentTimeMillis() + graceTerminationPeriod;
129 		for (Iterator iter = threads.keySet().iterator(); iter.hasNext();) {
130 			Object o = iter.next();
131 			if (o == null) {
132 				continue;
133 			}
134 			if (o instanceof MIDletThread) {
135 				MIDletThread t = (MIDletThread) o;
136 				if (t.isAlive()) {
137 					Logger.info("wait thread [" + t.getName() + "] end");
138 					while ((endTime > System.currentTimeMillis()) && (t.isAlive())) {
139 						try {
140 							t.join(700);
141 						} catch (InterruptedException e) {
142 							break;
143 						}
144 					}
145 					if (t.isAlive()) {
146 						Logger.warn("MIDlet thread [" + t.getName() + "] still running" + ThreadUtils.getTreadStackTrace(t));
147 						if (t.callLocation != null) {
148 							Logger.info("this thread [" + t.getName() + "] was created from " + t.callLocation);
149 						}
150 						t.interrupt();
151 					}
152 				}
153 			} else {
154 				Logger.debug("unrecognized Object [" + o.getClass().getName() + "]");
155 			}
156 		};
157 		Logger.debug("all "+ threads.size() + " thread(s) finished");
158 		terminator = false;
159 	}
160 
161 }