001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package test.stress;
023:
024: import java.util.Random;
025: import java.util.Properties;
026: import java.util.List;
027: import java.util.Collections;
028: import java.util.LinkedList;
029: import java.util.Set;
030:
031: import javax.management.MBeanServer;
032: import javax.management.MBeanServerFactory;
033: import javax.management.ObjectName;
034:
035: import junit.framework.TestCase;
036:
037: /**
038: * Stresses concurrent use of the MBeanServer for registration, querying.
039: * @author Scott.Stark@jboss.org
040: * @version $Revision: 57200 $
041: */
042: public class ConcurrencyTestCase extends TestCase {
043: // Constants ---------------------------------------------------------------
044: static final int N = 100000;
045: static final int Nadders = 2;
046: static final int NDomains = 1;
047: static final List names = Collections
048: .synchronizedList(new LinkedList());
049:
050: // Attributes --------------------------------------------------------------
051:
052: /**
053: * The MBeanServer
054: */
055: private MBeanServer server;
056: private Random rnd;
057: private boolean adding;
058:
059: // Constructor -------------------------------------------------------------
060:
061: /**
062: * Construct the test
063: */
064: public ConcurrencyTestCase(String s) {
065: super (s);
066: }
067:
068: // Tests -------------------------------------------------------------------
069:
070: public void testAddRemoveQuery() throws Exception {
071: MBeanAdder[] adders = new MBeanAdder[Nadders];
072: Thread[] adderThreads = new Thread[Nadders];
073: MBeanRemover[] removers = new MBeanRemover[Nadders];
074: Thread[] removerThreads = new Thread[Nadders];
075: MBeanFinder finder = new MBeanFinder();
076: adding = true;
077: for (int n = 0; n < adders.length; n++) {
078: int minID = n * N / Nadders;
079: int maxID = (n + 1) * N / Nadders;
080: adders[n] = new MBeanAdder(minID, maxID);
081: adderThreads[n] = new Thread(adders[n], "MBeanAdder#" + n);
082: adderThreads[n].start();
083: }
084: Thread t1 = new Thread(finder, "MBeanFinder");
085: t1.start();
086: for (int n = 0; n < adders.length; n++) {
087: removers[n] = new MBeanRemover();
088: removerThreads[n] = new Thread(removers[n], "MBeanRemover#"
089: + n);
090: removerThreads[n].start();
091: }
092:
093: for (int n = 0; n < adders.length; n++) {
094: adderThreads[n].join();
095: }
096: adding = false;
097: t1.join();
098: for (int n = 0; n < adders.length; n++) {
099: removerThreads[n].join();
100: }
101:
102: for (int n = 0; n < adders.length; n++) {
103: assertNull("There was no exception in MBeanAdder#" + n,
104: adders[n].getException());
105: }
106: assertNull("There was no exception in MBeanFinder", finder
107: .getException());
108: for (int n = 0; n < adders.length; n++) {
109: assertNull("There was no exception in MBeanRemover#" + n,
110: removers[n].getException());
111: }
112: }
113:
114: // Support -----------------------------------------------------------------
115:
116: /**
117: * Start a new test
118: */
119: protected void setUp() {
120: server = MBeanServerFactory.createMBeanServer();
121: rnd = new Random();
122: }
123:
124: /**
125: * End the test
126: */
127: protected void tearDown() throws Exception {
128: MBeanServerFactory.releaseMBeanServer(server);
129: }
130:
131: /**
132: * Sleep for a bit
133: */
134: private void sleep(long time) {
135: try {
136: Thread.sleep(time);
137: } catch (InterruptedException ignored) {
138: }
139: }
140:
141: class MBeanAdder implements Runnable {
142: private int minID;
143: private int maxID;
144: private String domain;
145: private Properties nameProps = new Properties();
146: private Throwable ex;
147:
148: MBeanAdder(int minID, int maxID) {
149: this .minID = minID;
150: this .maxID = maxID;
151: }
152:
153: public void run() {
154: System.out.println("MBeanAdder, min=" + minID + ", max="
155: + maxID + ", starting");
156: nameProps.setProperty("type", "simple");
157: try {
158: for (int n = 0; n < N; n++) {
159: int id = minID + n % maxID;
160: domain = "jboss.test." + rnd.nextInt(NDomains);
161: nameProps.setProperty("id", "#" + id);
162: addMBean();
163: }
164: } catch (Throwable t) {
165: this .ex = t;
166: ex.printStackTrace();
167: }
168: System.out.println("MBeanAdder, min=" + minID + ", max="
169: + maxID + ", ending");
170: }
171:
172: void addMBean() throws Exception {
173: ObjectName name = new ObjectName(domain, nameProps);
174: if (server.isRegistered(name))
175: server.unregisterMBean(name);
176: Simple mbean = new Simple(name);
177: server.registerMBean(mbean, name);
178: names.add(name);
179: }
180:
181: Throwable getException() {
182: return ex;
183: }
184: }
185:
186: class MBeanRemover implements Runnable {
187: private Throwable ex;
188:
189: public void run() {
190: try {
191: while (adding) {
192: int max = names.size();
193: if (max == 0) {
194: sleep(10);
195: continue;
196: }
197: int index = rnd.nextInt(max);
198: try {
199: ObjectName name = (ObjectName) names
200: .remove(index);
201: server.unregisterMBean(name);
202: } catch (IndexOutOfBoundsException ignore) {
203: }
204: }
205: } catch (Throwable t) {
206: this .ex = t;
207: ex.printStackTrace();
208: }
209: }
210:
211: Throwable getException() {
212: return ex;
213: }
214: }
215:
216: class MBeanFinder implements Runnable {
217: private Throwable ex;
218:
219: public void run() {
220: try {
221: ObjectName query = new ObjectName(
222: "jboss.test.*:type=simple,*");
223: int count = 0;
224: while (adding) {
225: Set matches = server.queryNames(query, null);
226: count++;
227: if (count % 1000 == 0)
228: System.out.println(count
229: + " queries, names.size="
230: + names.size() + ", matches.size="
231: + matches.size());
232: }
233: } catch (Throwable t) {
234: this .ex = t;
235: ex.printStackTrace();
236: }
237: }
238:
239: Throwable getException() {
240: return ex;
241: }
242: }
243:
244: static interface SimpleMBean {
245: public ObjectName getName();
246: }
247:
248: static class Simple implements SimpleMBean {
249: private ObjectName name;
250:
251: Simple(ObjectName name) {
252: this .name = name;
253: }
254:
255: public ObjectName getName() {
256: return name;
257: }
258: }
259: }
|