View Javadoc
1   package psl;
2   
3   import java.lang.management.ManagementFactory;
4   import java.util.ArrayList;
5   import java.util.Iterator;
6   import java.util.LinkedList;
7   import java.util.List;
8   import java.util.concurrent.ThreadFactory;
9   
10  import javax.management.InstanceAlreadyExistsException;
11  import javax.management.InstanceNotFoundException;
12  import javax.management.MBeanRegistrationException;
13  import javax.management.MBeanServer;
14  import javax.management.MalformedObjectNameException;
15  import javax.management.NotCompliantMBeanException;
16  import javax.management.ObjectName;
17  
18  import ensure.Ensure;
19  
20  /**
21   * Factory that creates dispatcher threads.
22   */
23  final class DispatcherThreadFactory implements ThreadFactory {
24  	/**
25  	 * Number of the next thread to create. Minimum value <code>1</code>.
26  	 */
27  	private int m_next_number;
28  	
29  	/**
30  	 * Factory name. Never <code>null</code>.
31  	 */
32  	private String m_name;
33  	
34  	/**
35  	 * The exception handler. Never <code>null</code>.
36  	 */
37  	private ExceptionHandler m_exception_handler;
38  	
39  	/**
40  	 * Created threads. Never <code>null</code>.
41  	 */
42  	private List<DispatcherThread> m_created;
43  	
44  	/**
45  	 * Name used for registering the MX bean. Never <code>null</code>
46  	 */
47  	private ObjectName m_mx_name;
48  	
49  	/**
50  	 * Is the factory active?
51  	 */
52  	private boolean m_active;
53  	
54  	/**
55  	 * Creates a thread factory with a name which will be used as a prefix
56  	 * for new threads.
57  	 * @param name the factory name, cannot be <code>null</code>
58  	 * @param exception_handler the handler to receive exceptions, cannot
59  	 * be <code>null</code>
60  	 */
61  	private DispatcherThreadFactory(String name,
62  			ExceptionHandler exception_handler) {
63  		Ensure.not_null(name, "name == null");
64  		Ensure.not_null(exception_handler, "exception_handler == null");
65  		
66  		m_name = name;
67  		m_next_number = 1;
68  		m_exception_handler = exception_handler;
69  		m_created = new LinkedList<>();
70  		m_active = true;
71  		
72  		try {
73  			m_mx_name = object_name(m_name);
74  			DispatcherThreadFactoryMXBeanImpl mx =
75  					new DispatcherThreadFactoryMXBeanImpl(this);
76  			MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
77  			mbs.registerMBean(mx, m_mx_name);
78  		} catch (NotCompliantMBeanException | MBeanRegistrationException
79  				| InstanceAlreadyExistsException e) {
80  			Ensure.never_thrown(e);
81  		}
82  	}
83  	
84  	/**
85  	 * Shuts down the factory.
86  	 */
87  	synchronized void shutdown() {
88  		Ensure.is_true(m_active, "m_active == false");
89  		
90  		m_active = false;
91  		m_created.clear();
92  		
93  		try {
94  			MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
95  			mbs.unregisterMBean(m_mx_name);
96  		} catch (InstanceNotFoundException | MBeanRegistrationException e) {
97  			Ensure.never_thrown(e);
98  		}
99  	}
100 	
101 	/**
102 	 * Obtains the MX object name for a factory with the given name.
103 	 * @param factory_name the factory name, cannot be <code>null</code>
104 	 * @return the object name
105 	 */
106 	public static ObjectName object_name(String factory_name) {
107 		Ensure.not_null(factory_name, "factory_name == null");
108 		
109 		try {
110 			return new ObjectName(DispatcherThreadFactory.class.getName()
111 					+ ":name=" + factory_name + ",info=factory");
112 		} catch (MalformedObjectNameException e) {
113 			return Ensure.never_thrown(e);
114 		}
115 	}
116 	
117 	/**
118 	 * Creates a new dispatcher thread factory.
119 	 * @param name the factory name, cannot be <code>null</code>
120 	 * @param exception_handler the handler to receive exceptions, cannot
121 	 * be <code>null</code>
122 	 * @return the thread factory
123 	 */
124 	public static DispatcherThreadFactory make(String name,
125 			ExceptionHandler exception_handler) {
126 		Ensure.not_null(name, "name == null");
127 		Ensure.not_null(exception_handler, "exception_handler == null");
128 		
129 		DispatcherThreadFactory factory = new DispatcherThreadFactory(name,
130 				exception_handler);
131 		return factory;
132 	}
133 	
134 	@Override
135 	public synchronized Thread newThread(Runnable r) {
136 		Ensure.not_null(r, "r == null");
137 		Ensure.is_true(m_active, "m_active == false");
138 		
139 		DispatcherThread t = DispatcherThread.make(r, m_name,
140 				m_next_number, m_exception_handler);
141 		m_next_number++;
142 		clear_terminated();
143 		m_created.add(t);
144 		return t;
145 	}
146 	
147 	/**
148 	 * Obtains all threads created that are still alive.
149 	 * @return all threads
150 	 */
151 	public synchronized List<DispatcherThread> threads() {
152 		Ensure.is_true(m_active, "m_active == false");
153 		
154 		clear_terminated();
155 		List<DispatcherThread> all = new ArrayList<>(m_created);
156 		return all;
157 	}
158 	
159 	/**
160 	 * Clears all terminated threads from {@link #m_created}.
161 	 */
162 	private void clear_terminated() {
163 		Iterator<DispatcherThread> it = m_created.iterator();
164 		while (it.hasNext()) {
165 			DispatcherThread dt = it.next();
166 			if (dt.done()) {
167 				it.remove();
168 			}
169 		}
170 	}
171 	
172 	/**
173 	 * Obtains the factory name.
174 	 * @return the factory name
175 	 */
176 	public String name() {
177 		return m_name;
178 	}
179 	
180 	/**
181 	 * Obtains the thread count.
182 	 * @return the thread count
183 	 */
184 	public synchronized int thread_count() {
185 		clear_terminated();
186 		return m_created.size();
187 	}
188 }