001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019: package org.netbeans.modules.bpel.mapper.logging.multiview;
020:
021: import java.awt.event.ActionEvent;
022: import java.awt.event.ActionListener;
023: import java.lang.ref.WeakReference;
024: import java.util.EventObject;
025: import javax.swing.JTree;
026: import javax.swing.SwingUtilities;
027: import javax.swing.Timer;
028: import org.netbeans.modules.bpel.mapper.logging.model.LoggingMapperModelFactory;
029: import org.netbeans.modules.bpel.mapper.multiview.BpelDesignContext;
030: import org.netbeans.modules.bpel.mapper.multiview.BpelModelSynchListener;
031: import org.netbeans.modules.bpel.mapper.multiview.DesignContextController;
032: import org.netbeans.modules.bpel.mapper.tree.TreeExpandedState;
033: import org.netbeans.modules.bpel.mapper.tree.TreeExpandedStateImpl;
034: import org.netbeans.modules.bpel.mapper.tree.spi.MapperTcContext;
035: import org.netbeans.modules.bpel.model.api.BpelEntity;
036: import org.netbeans.modules.bpel.model.api.BpelModel;
037: import org.netbeans.modules.bpel.model.api.events.ChangeEvent;
038: import org.netbeans.modules.soa.mappercore.Mapper;
039: import org.netbeans.modules.soa.mappercore.model.MapperModel;
040: import org.netbeans.modules.xml.xam.Model.State;
041: import org.openide.nodes.Node;
042: import org.openide.windows.TopComponent;
043:
044: /**
045: * Controls the state of the BPEL mapper and manages different events:
046: * - change of activated node
047: * - change in the related BPEL model
048: *
049: * @author nk160297
050: * @author Vitaly Bychkov
051: *
052: */
053: public class DesignContextControllerImpl implements
054: DesignContextController {
055:
056: private static int RELOAD_DELAY = 100;
057: private static int NODE_UPDATE_DELAY = 200;
058:
059: private BpelDesignContext mContext;
060:
061: private MapperTcContext mMapperTcContext;
062: private BpelModelSynchListener mBpelModelSynchListener;
063:
064: // A new instance of ReloadProcessor is created for each timer event
065: // The field holds the last created processor.
066: // It is intended to allow the process to be interrupted.
067: private ReloadProcessor mReloadProcessor;
068:
069: private Timer reloadTimer;
070: private Timer nodeUpdateTimer;
071:
072: // Fields which hold parameters for the UpdateProcessor
073: private BpelDesignContext mNewContext;
074: private boolean mNeedReload;
075:
076: private WeakReference<Object> mBpelModelUpdateSourceRef;
077:
078: /** Creates a new instance of DesignContextChangeListener */
079: public DesignContextControllerImpl(MapperTcContext mapperTcContext) {
080: mMapperTcContext = mapperTcContext;
081: mBpelModelSynchListener = new BpelModelSynchListener(this );
082: //
083: reloadTimer = new Timer(RELOAD_DELAY, new ActionListener() {
084: public void actionPerformed(ActionEvent e) {
085: //
086: // Create new instance of UpdateProcessor
087: ReloadProcessor reloadProcessor = new ReloadProcessor();
088: synchronized (DesignContextControllerImpl.this ) {
089: mReloadProcessor = reloadProcessor;
090: }
091: //
092: reloadProcessor.reloadMapperImpl();
093: //
094: if (!(reloadProcessor.isInterrupted())) {
095: // Discard the flag in case the processor
096: // hasn't been interrupted.
097: // The flag has to be discarded here!
098: synchronized (DesignContextControllerImpl.this ) {
099: mNeedReload = false;
100: }
101: }
102: }
103: });
104: reloadTimer.setRepeats(false);
105: //
106: nodeUpdateTimer = new Timer(NODE_UPDATE_DELAY,
107: new ActionListener() {
108: public void actionPerformed(ActionEvent e) {
109: //
110: // Create new instance of UpdateProcessor
111: ReloadProcessor reloadProcessor = new ReloadProcessor();
112: synchronized (DesignContextControllerImpl.this ) {
113: mReloadProcessor = reloadProcessor;
114: }
115: //
116: reloadProcessor.setContextImpl();
117: //
118: if (!(reloadProcessor.isInterrupted())) {
119: // Discard the flag in case the processor
120: // hasn't been interrupted.
121: // The flag has to be discarded here!
122: synchronized (DesignContextControllerImpl.this ) {
123: mNeedReload = false;
124: }
125: }
126: }
127: });
128: nodeUpdateTimer.setRepeats(false);
129: }
130:
131: public MapperTcContext getMapperTcContext() {
132: return mMapperTcContext;
133: }
134:
135: public void setBpelModelUpdateSource(Object source) {
136: mBpelModelUpdateSourceRef = new WeakReference<Object>(source);
137: }
138:
139: private synchronized Object getBpelModelUpdateSource() {
140: if (mBpelModelUpdateSourceRef != null) {
141: return mBpelModelUpdateSourceRef.get();
142: }
143: //
144: return null;
145: }
146:
147: public synchronized BpelDesignContext getContext() {
148: return mContext;
149: }
150:
151: public synchronized void setContext(BpelDesignContext newContext) {
152: if (newContext == null) {
153: return;
154: }
155: Node aNode = newContext.getActivatedNode();
156: if (aNode != null && mMapperTcContext != null) {
157: TopComponent mapperTc = mMapperTcContext.getTopComponent();
158: if (mapperTc != null) {
159: mapperTc.setActivatedNodes(new Node[] { aNode });
160: }
161: }
162:
163: BpelModel model = getCurrBpelModel();
164: // BpelEntity newEntity = newContext.getBpelEntity();
165: BpelEntity newEntity = newContext.getSelectedEntity();
166: // avoid entities from another BpelModel
167: if ((model != null && newEntity != null && !model
168: .equals(newEntity.getBpelModel()))
169: || newEntity == null) {
170: return;
171: }
172:
173: reloadTimer.stop();
174: nodeUpdateTimer.stop();
175: //
176: if (mReloadProcessor != null) {
177: mReloadProcessor.interrupt();
178: }
179: //
180: mNewContext = newContext;
181: //
182: nodeUpdateTimer.start();
183: }
184:
185: public synchronized void reloadMapper(EventObject event) {
186: //
187: // Ignore reload if is has been initiated by the mapper itself
188: if (event.getSource() == getBpelModelUpdateSource()) {
189: return;
190: }
191: //
192: if (!nodeUpdateTimer.isRunning()) {
193: reloadTimer.stop();
194: //
195: if (mReloadProcessor != null) {
196: mReloadProcessor.interrupt();
197: }
198: //
199: reloadTimer.start();
200: }
201: //
202: // The flag has to be set at the end of the method!
203: mNeedReload = true;
204: }
205:
206: private synchronized BpelModel getCurrBpelModel() {
207: if (mContext != null) {
208: return mContext.getBpelModel();
209: }
210: return null;
211: }
212:
213: private void setMapperModel(MapperModel newMapperModel) {
214: mMapperTcContext.setMapperModel(newMapperModel);
215: }
216:
217: /**
218: * Processes events from reload and node update timers and
219: * reloads the mapper content.
220: */
221: private class ReloadProcessor {
222:
223: private boolean isInterrupted = false;
224:
225: /**
226: * Sets isInterrupted flag.
227: */
228: public void interrupt() {
229: isInterrupted = true;
230: }
231:
232: public boolean isInterrupted() {
233: return isInterrupted;
234: }
235:
236: public void reloadMapperImpl() {
237: if (mContext == null) {
238: return;
239: }
240: //
241: if (isModelInvalid()) {
242: disableMapper();
243: return;
244: }
245: //
246: // No need to resubscribe to another BPEL model here
247: // because of the same design context.
248: //
249: MapperModel newMapperModel = new LoggingMapperModelFactory()
250: .constructModel(mMapperTcContext, mContext);
251: //
252: // Save left tree state
253: TreeExpandedState leftTreeState = null;
254: Mapper mapper = mMapperTcContext.getMapper();
255: if (mapper != null) {
256: // JTree leftTree = mapper.getLeftTree();
257: // if (leftTree != null) {
258: leftTreeState = new TreeExpandedStateImpl(mapper);
259: leftTreeState.save();
260: // }
261: }
262: //
263: setMapperModel(newMapperModel);
264: //
265: // Restore left tree state
266: final TreeExpandedState state = leftTreeState;
267: if (state != null) {
268: SwingUtilities.invokeLater(new Runnable() {
269: public void run() {
270: state.restore();
271: }
272: });
273: // TODO: restore tree selection, restore right tree, expanded graph
274: }
275: }
276:
277: public void setContextImpl() {
278: // Copy the context to a new local variable at first.
279: BpelDesignContext newContext = mNewContext;
280: //
281: if (newContext == null
282: || newContext.getSelectedEntity() == null) {
283: // Hide the mapper if there is not a BPEL entity selected
284: disableMapper();
285: return;
286: }
287: //
288: if (isModelInvalid()) {
289: disableMapper();
290: return;
291: }
292: //
293: if (!newContext.equals(mContext)) {
294: BpelEntity contextEntity = newContext
295: .getSelectedEntity();
296: boolean needShow = LoggingMapperModelFactory
297: .needShowMapper(contextEntity);
298: //
299: if (!needShow) {
300: disableMapper();
301: } else {
302: //
303: // Re subscribe to another BPEL model if necessary.
304: if (newContext.getBpelModel() != getCurrBpelModel()) {
305: setListenBpelModel(getCurrBpelModel(), false);
306: setListenBpelModel(newContext.getBpelModel(),
307: true);
308: }
309: //
310: MapperModel newMapperModel = new LoggingMapperModelFactory()
311: .constructModel(mMapperTcContext,
312: newContext);
313: //
314: mContext = newContext;
315: setMapperModel(newMapperModel);
316: //
317: mMapperTcContext.showMapperTcGroup(true);
318: }
319: } else {
320: //
321: boolean needReload;
322: synchronized (DesignContextControllerImpl.this ) {
323: needReload = mNeedReload;
324: }
325: if (needReload) {
326: reloadMapperImpl();
327: }
328: }
329: }
330:
331: private void setListenBpelModel(BpelModel bpelModel,
332: boolean isEnabled) {
333: if (bpelModel == null) {
334: return;
335: }
336: //
337: if (isEnabled) {
338: if (mBpelModelSynchListener != null) {
339: bpelModel
340: .addEntityChangeListener(mBpelModelSynchListener);
341: }
342: } else {
343: if (mBpelModelSynchListener != null) {
344: bpelModel
345: .removeEntityChangeListener(mBpelModelSynchListener);
346: }
347: }
348: }
349:
350: private void disableMapper() {
351: mMapperTcContext.showMapperTcGroup(false);
352: mMapperTcContext.setMapper(null);
353: setListenBpelModel(getCurrBpelModel(), false);
354: //
355: mContext = null;
356: }
357:
358: private boolean isModelInvalid() {
359: BpelModel bpelModel = getCurrBpelModel();
360: if (bpelModel != null) {
361: return bpelModel.getState().equals(
362: State.NOT_WELL_FORMED);
363: }
364: return false; // Consider the model valid by default
365: }
366:
367: }
368:
369: public void showMapper() {
370: // do nothing
371: }
372:
373: public void hideMapper() {
374: // do nothing
375: }
376:
377: public void cleanup() {
378: //TODO a
379: }
380:
381: public void processDataObject(Object dataObject) {
382: // Do nothing. This DCC implementation is never used
383: }
384: }
|