001: package org.netbeans.modules.loadgenerator.spi;
002:
003: import java.awt.Image;
004: import java.beans.PropertyChangeListener;
005: import java.beans.PropertyChangeSupport;
006: import java.io.File;
007: import java.util.ArrayList;
008: import java.util.Collection;
009: import java.util.Collections;
010: import java.util.HashMap;
011: import java.util.Map;
012: import org.netbeans.modules.loadgenerator.api.impl.ManagerOutputWindowRegistry;
013: import org.netbeans.modules.loadgenerator.utils.NullOutputWriter;
014: import org.openide.filesystems.FileAttributeEvent;
015: import org.openide.filesystems.FileChangeListener;
016: import org.openide.filesystems.FileEvent;
017: import org.openide.filesystems.FileObject;
018: import org.openide.filesystems.FileRenameEvent;
019: import org.openide.filesystems.FileUtil;
020: import org.openide.util.WeakListeners;
021: import org.openide.windows.OutputWriter;
022:
023: /**
024: * Provides the basic scaffolding for a ILoadGeneratorInstance implementation
025: *
026: *
027: * @author Jaroslav Bachorik
028: */
029: public abstract class ProcessInstance {
030: public static final String FACTORY = ProcessInstance.class
031: .getName()
032: + "#FACTORY";
033: public final static String STATE = ProcessInstance.class.getName()
034: + "#STATE";
035:
036: private static final OutputWriter NULLWRITER = new NullOutputWriter();
037:
038: public ProcessInstance(final Engine factory) {
039: pcs = new PropertyChangeSupport(this );
040: listeners = new ArrayList<ProcessInstanceListener>();
041: listenerMap = Collections
042: .synchronizedMap(new HashMap<ProcessInstanceListener, ProcessInstanceListener>());
043:
044: setFactory(factory);
045: }
046:
047: public synchronized boolean isNew() {
048: return isNewFlag;
049: }
050:
051: public synchronized void touch() {
052: isNewFlag = false;
053: isModifiedFlag = false;
054: isDeletedFlag = false;
055: }
056:
057: void attachFactory(final Engine factory) {
058: setFactory(factory);
059: }
060:
061: void detachFactory() {
062: setFactory(null);
063: }
064:
065: /**
066: * Registers a new listener
067: * @param listener The listener instance to register
068: */
069: public void addListener(final ProcessInstanceListener listener) {
070: ProcessInstanceListener weak = WeakListeners.create(
071: ProcessInstanceListener.class, listener, this );
072: if (!listeners.contains(weak)) {
073: listeners.add(weak);
074: listenerMap.put(listener, weak);
075: }
076: }
077:
078: // <editor-fold defaultstate="collapsed" desc="PropertyChange support">
079: public void addPropertyChangeListener(
080: final PropertyChangeListener pcl) {
081: pcs.addPropertyChangeListener(pcl);
082: }
083:
084: public void addPropertyChangeListener(final String propertyName,
085: final PropertyChangeListener pcl) {
086: pcs.addPropertyChangeListener(propertyName, pcl);
087: }
088:
089: public void removePropertyChangeListener(
090: final PropertyChangeListener pcl) {
091: pcs.removePropertyChangeListener(pcl);
092: }
093:
094: public void removePropertyChangeListener(final String propertyName,
095: final PropertyChangeListener pcl) {
096: pcs.removePropertyChangeListener(propertyName, pcl);
097: }
098:
099: // </editor-fold>
100:
101: /**
102: * Unregisters a listener
103: * @param listener The listener to unregister
104: */
105: public void removeListener(final ProcessInstanceListener listener) {
106: ProcessInstanceListener weak = listenerMap.get(listener);
107: if (weak != null) {
108: listeners.remove(weak);
109: listenerMap.remove(listener);
110: }
111: }
112:
113: public Engine getFactory() {
114: return factory;
115: }
116:
117: public void start(final String scriptFileName) {
118: setCurrentScript(scriptFileName);
119: performStart(scriptFileName);
120: }
121:
122: public void start() {
123: if (currentScript != null) {
124: performStart(currentScript);
125: }
126: }
127:
128: public void stop(final boolean force) {
129: if (isRunning()) {
130: performStop(force);
131: } else {
132: publishStart(); // fake start; just to be sure we are stopping the engine in a consistent state
133: publishStop();
134: }
135: }
136:
137: public String getCurrentScript() {
138: return currentScript;
139: }
140:
141: public void setCurrentScript(final String value) {
142: if (currentScriptFile != null) {
143: currentScriptFile.removeFileChangeListener(fcl);
144: currentScriptFile = null;
145: }
146: if (value != null) {
147: currentScriptFile = FileUtil.toFileObject(new File(value));
148: currentScriptFile.addFileChangeListener(fcl);
149: }
150: currentScript = value;
151: }
152:
153: /**
154: * Attaches an OutputWriter instance to load generator
155: */
156: public void attachWriter(final OutputWriter writer) {
157: this .writer = writer;
158: }
159:
160: /**
161: * Detaches the previously set OutputWriter
162: */
163: public void detachWriter() {
164: this .writer = null;
165: }
166:
167: public boolean isModified() {
168: return isModifiedFlag;
169: }
170:
171: public boolean isDeleted() {
172: return isDeletedFlag;
173: }
174:
175: public abstract void performStart(final String scriptFileName);
176:
177: public abstract void performStop(final boolean force);
178:
179: /**
180: * Indicates the running status of a ProcessInstance instance
181: */
182: public abstract boolean isRunning();
183:
184: /**
185: * Returns a descriptive name for the particular process instance
186: * @return Returns a descriptive name
187: */
188: public abstract String getDisplayName();
189:
190: /**
191: * Returns the icon representing the load generator process if it exists
192: * @return Returns the icon representing the load generator or null
193: */
194: public abstract Image getIcon();
195:
196: /************* Private implementation ******************/
197: private Collection<ProcessInstanceListener> listeners;
198: private Map<ProcessInstanceListener, ProcessInstanceListener> listenerMap;
199: private PropertyChangeSupport pcs;
200: private String currentScript;
201: private FileObject currentScriptFile;
202: private OutputWriter writer;
203: private Engine factory;
204: private boolean isNewFlag = true, isModifiedFlag = false,
205: isDeletedFlag = false;
206:
207: final private FileChangeListener fcl = new FileChangeListener() {
208: public void fileFolderCreated(FileEvent fe) {
209: // IGNORE
210: }
211:
212: public void fileDataCreated(FileEvent fe) {
213: // IGNORE
214: }
215:
216: public void fileChanged(FileEvent fe) {
217: setModified();
218: }
219:
220: public void fileDeleted(FileEvent fe) {
221: fe.getFile().removeFileChangeListener(this );
222: currentScriptFile = null;
223: currentScript = null;
224: if (!isRunning()) {
225: ManagerOutputWindowRegistry.getDefault().close(
226: ProcessInstance.this );
227: } else {
228: setDeleted();
229: }
230: }
231:
232: public void fileRenamed(FileRenameEvent fe) {
233: currentScript = fe.getFile().getPath();
234: if (!isRunning()) {
235: ManagerOutputWindowRegistry.getDefault().close(
236: ProcessInstance.this );
237: ManagerOutputWindowRegistry.getDefault().open(
238: ProcessInstance.this );
239: } else {
240: setModified();
241: }
242: }
243:
244: public void fileAttributeChanged(FileAttributeEvent fe) {
245: // IGNORE
246: }
247: };
248:
249: protected synchronized void publishStart() {
250: for (ProcessInstanceListener listener : listeners) {
251: listener.generatorStarted(this );
252: }
253: pcs.firePropertyChange(STATE, false, true);
254: }
255:
256: protected synchronized void publishStart(final String logPath) {
257: for (ProcessInstanceListener listener : listeners) {
258: listener.generatorStarted(this , logPath);
259: }
260: pcs.firePropertyChange(STATE, false, true);
261: }
262:
263: protected synchronized void publishStop() {
264: Collection<ProcessInstanceListener> immutableListeners = new ArrayList<ProcessInstanceListener>(
265: listeners);
266: for (ProcessInstanceListener listener : immutableListeners) {
267: listener.generatorStopped(this );
268: }
269: pcs.firePropertyChange(STATE, true, false);
270: }
271:
272: protected synchronized void publishInvalidated() {
273: Collection<ProcessInstanceListener> immutableListeners = new ArrayList<ProcessInstanceListener>(
274: listeners);
275: for (ProcessInstanceListener listener : immutableListeners) {
276: listener.instanceInvalidated(this );
277: }
278: }
279:
280: protected OutputWriter getWriter() {
281: return writer != null ? writer : NULLWRITER;
282: }
283:
284: private void setFactory(final Engine factory) {
285: pcs.firePropertyChange(FACTORY, this .factory, factory);
286: this .factory = factory;
287: }
288:
289: private void setModified() {
290: isModifiedFlag = true;
291: publishInvalidated();
292: }
293:
294: private void setDeleted() {
295: isDeletedFlag = true;
296: isModifiedFlag = false;
297: publishInvalidated();
298: }
299: }
|