001: /*
002: * This file is part of the Echo Web Application Framework (hereinafter "Echo").
003: * Copyright (C) 2002-2005 NextApp, Inc.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package nextapp.echo2.testapp.thousandmonkeys;
031:
032: import java.util.ArrayList;
033: import java.util.List;
034:
035: import nextapp.echo2.app.CheckBox;
036: import nextapp.echo2.app.Column;
037: import nextapp.echo2.app.Component;
038: import nextapp.echo2.app.ContentPane;
039: import nextapp.echo2.app.Grid;
040: import nextapp.echo2.app.IllegalChildException;
041: import nextapp.echo2.app.ListBox;
042: import nextapp.echo2.app.PasswordField;
043: import nextapp.echo2.app.RadioButton;
044: import nextapp.echo2.app.Row;
045: import nextapp.echo2.app.SelectField;
046: import nextapp.echo2.app.SplitPane;
047: import nextapp.echo2.app.TextArea;
048: import nextapp.echo2.app.TextField;
049: import nextapp.echo2.app.WindowPane;
050: import nextapp.echo2.testapp.thousandmonkeys.factories.ButtonFactory;
051: import nextapp.echo2.testapp.thousandmonkeys.factories.GenericFactory;
052: import nextapp.echo2.testapp.thousandmonkeys.factories.LabelFactory;
053:
054: /**
055: * A "Monkey" randomly adds, updates, and removes <code>Component</code>s from
056: * the application.
057: * Note: yes, there is only one monkey per application (you'll need 1000
058: * browser clients to truly achieve 1000 monkeys).
059: */
060: public class Monkey {
061:
062: private static final ComponentFactory[] componentFactories = new ComponentFactory[] {
063: new ButtonFactory(), new GenericFactory(CheckBox.class),
064: new GenericFactory(Column.class),
065: new GenericFactory(ContentPane.class),
066: new GenericFactory(Grid.class), new LabelFactory(),
067: new GenericFactory(ListBox.class),
068: new GenericFactory(PasswordField.class),
069: new GenericFactory(RadioButton.class),
070: new GenericFactory(Row.class),
071: new GenericFactory(SelectField.class),
072: new GenericFactory(SplitPane.class),
073: new GenericFactory(TextField.class),
074: new GenericFactory(TextArea.class),
075: new GenericFactory(WindowPane.class) };
076:
077: /**
078: * The maximum number of children to add to the root
079: * <code>ContentPane</code>.
080: */
081: private static final int MAX_CONTENT_PANE_CHILDREN = 5;
082:
083: /**
084: * The minimum number of add operations to perform per iteration.
085: */
086: private static final int MIN_ADDS = 0;
087:
088: /**
089: * The maximum number of add operations to perform per iteration.
090: */
091: private static final int MAX_ADDS = 20;
092:
093: /**
094: * The minimum number of remove operations to perform per iteration.
095: */
096: private static final int MIN_REMOVES = 0;
097:
098: /**
099: * The maximum number of remove operations to perform per iteration.
100: */
101: private static final int MAX_REMOVES = 12;
102:
103: /**
104: * The root <code>ContentPane</code> to which children should be added
105: * (will never be removed).
106: */
107: private ContentPane contentPane;
108:
109: /**
110: * List of all potential parent <code>Component</code>s.
111: */
112: private List components = new ArrayList();
113:
114: /**
115: * Creates a new <code>Monkey</code>.
116: *
117: * @param contentPane the root <code>ContentPane</code> to which children
118: * should be added (will never be removed)
119: */
120: public Monkey(ContentPane contentPane) {
121: this .contentPane = contentPane;
122: }
123:
124: /**
125: * Creates a random <code>Component</code> and adds it beneath a random
126: * parent.
127: */
128: private void doAdd() {
129: int addParentIndex;
130: if (components.size() < MAX_CONTENT_PANE_CHILDREN) {
131: addParentIndex = ((int) Math.random() * (components.size() + 1)) - 1;
132: } else {
133: addParentIndex = ((int) Math.random() * components.size());
134: }
135: ComponentFactory componentFactory = componentFactories[((int) (Math
136: .random() * componentFactories.length))];
137: Component child = componentFactory.newInstance();
138:
139: for (int i = 0; i < 5; ++i) {
140: Component parent = addParentIndex == -1 ? contentPane
141: : (Component) components.get(addParentIndex);
142: try {
143: parent.add(child);
144: components.add(child);
145: return;
146: } catch (IllegalChildException ex) {
147: }
148: }
149: }
150:
151: /**
152: * Removes a random <code>Component</code> from the hierarchy.
153: */
154: private void doRemove() {
155: if (components.size() == 0) {
156: // No components to remove.
157: return;
158: }
159: Component child = (Component) components.get((int) (Math
160: .random() * components.size()));
161: child.getParent().remove(child);
162: recursiveRemoveComponentFromList(child);
163: }
164:
165: /**
166: * Performs a single iteration, potentially adding, removing, and/or
167: * updating several <code>Component</code>s.
168: */
169: public void iterate() {
170: int removes = ((int) (Math.random() * (1 + MAX_REMOVES - MIN_REMOVES)))
171: + MIN_REMOVES;
172: for (int i = 0; i < removes; ++i) {
173: doRemove();
174: }
175:
176: int adds = ((int) (Math.random() * (1 + MAX_ADDS - MIN_ADDS)))
177: + MIN_ADDS;
178: for (int i = 0; i < adds; ++i) {
179: doAdd();
180: }
181: System.err.println(components.size());
182: }
183:
184: /**
185: * Recursively removes a <code>Component</code> and its descendants from
186: * the list of eligible parents. This operation is performed due to the
187: * <code>Component</code> having been deleted.
188: *
189: * @param component the deleted <code>Component</code>
190: */
191: private void recursiveRemoveComponentFromList(Component component) {
192: components.remove(component);
193: Component[] children = component.getComponents();
194: for (int i = 0; i < children.length; ++i) {
195: recursiveRemoveComponentFromList(children[i]);
196: }
197: }
198: }
|