0001: /*
0002: * The contents of this file are subject to the terms of the Common Development
0003: * and Distribution License (the License). You may not use this file except in
0004: * compliance with the License.
0005: *
0006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
0007: * or http://www.netbeans.org/cddl.txt.
0008: *
0009: * When distributing Covered Code, include this CDDL Header Notice in each file
0010: * and include the License file at http://www.netbeans.org/cddl.txt.
0011: * If applicable, add the following below the CDDL Header, with the fields
0012: * enclosed by brackets [] replaced by your own identifying information:
0013: * "Portions Copyrighted [year] [name of copyright owner]"
0014: *
0015: * The Original Software is NetBeans. The Initial Developer of the Original
0016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0017: * Microsystems, Inc. All Rights Reserved.
0018: */
0019: package org.netbeans.modules.bpel.model.impl;
0020:
0021: import java.beans.PropertyChangeEvent;
0022: import java.beans.PropertyChangeListener;
0023: import java.beans.PropertyChangeSupport;
0024: import java.io.IOException;
0025: import java.util.ArrayList;
0026: import java.util.Collection;
0027: import java.util.LinkedList;
0028: import java.util.List;
0029: import java.util.Queue;
0030: import java.util.Set;
0031: import java.util.concurrent.Callable;
0032: import java.util.concurrent.atomic.AtomicLong;
0033: import java.util.concurrent.locks.Lock;
0034: import java.util.concurrent.locks.ReentrantReadWriteLock;
0035:
0036: import javax.swing.event.EventListenerList;
0037: import javax.swing.event.UndoableEditEvent;
0038: import javax.swing.event.UndoableEditListener;
0039: import javax.swing.text.BadLocationException;
0040: import javax.swing.text.Document;
0041: import javax.swing.undo.CompoundEdit;
0042: import javax.swing.undo.UndoManager;
0043: import javax.swing.undo.UndoableEditSupport;
0044: import javax.xml.namespace.QName;
0045:
0046: import org.netbeans.modules.bpel.model.api.AnotherVersionBpelProcess;
0047: import org.netbeans.modules.bpel.model.api.BpelContainer;
0048: import org.netbeans.modules.bpel.model.api.BpelEntity;
0049: import org.netbeans.modules.bpel.model.api.BpelModel;
0050: import org.netbeans.modules.bpel.model.api.ContentElement;
0051: import org.netbeans.modules.bpel.model.api.ExtensibleElements;
0052: import org.netbeans.modules.bpel.model.api.ExtensionEntity;
0053: import org.netbeans.modules.bpel.model.api.Process;
0054: import org.netbeans.modules.bpel.model.api.events.ChangeEvent;
0055: import org.netbeans.modules.bpel.model.api.events.ChangeEventListener;
0056: import org.netbeans.modules.bpel.model.api.events.ChangeEventSupport;
0057: import org.netbeans.modules.bpel.model.api.events.PropertyUpdateEvent;
0058: import org.netbeans.modules.bpel.model.api.events.VetoException;
0059: import org.netbeans.modules.bpel.model.api.support.UniqueId;
0060: import org.netbeans.modules.bpel.model.impl.events.TreeCreatedEvent;
0061: import org.netbeans.modules.bpel.model.spi.EntityFactory;
0062: import org.netbeans.modules.bpel.model.xam.BpelElements;
0063: import org.netbeans.modules.bpel.model.xam.spi.InnerEventDispatcher;
0064: import org.netbeans.modules.xml.xam.Component;
0065: import org.netbeans.modules.xml.xam.ComponentEvent;
0066: import org.netbeans.modules.xml.xam.ComponentListener;
0067: import org.netbeans.modules.xml.xam.ComponentUpdater;
0068: import org.netbeans.modules.xml.xam.ModelSource;
0069: import org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent;
0070: import org.netbeans.modules.xml.xam.dom.AbstractDocumentModel;
0071: import org.openide.util.Lookup;
0072: import org.openide.util.Lookup.Result;
0073: import org.openide.util.lookup.Lookups;
0074: import org.w3c.dom.Element;
0075: import org.w3c.dom.Node;
0076: import org.w3c.dom.Text;
0077:
0078: public class BpelModelImpl extends AbstractDocumentModel<BpelEntity>
0079: implements BpelModel {
0080:
0081: public BpelModelImpl(Document doc, Lookup lookup) {
0082: // TODO this is temporary constructor and this will be removed later.
0083: this (getOrCreateModelSource(doc, lookup));
0084: }
0085:
0086: public BpelModelImpl(ModelSource source) {
0087: super (source);
0088: init();
0089: }
0090:
0091: /* (non-Javadoc)
0092: * @see org.netbeans.modules.soa.model.bpel20.api.BpelModel#getProcess()
0093: */
0094: public ProcessImpl getProcess() {
0095: readLock();
0096: try {
0097: return (ProcessImpl) getRootComponent();
0098: } finally {
0099: readUnlock();
0100: }
0101: }
0102:
0103: /* (non-Javadoc)
0104: * @see org.netbeans.modules.soa.model.bpel20.api.BpelModel#getBuilder()
0105: */
0106: public BpelBuilderImpl getBuilder() {
0107: return myBuilder;
0108: }
0109:
0110: /* (non-Javadoc)
0111: * @see org.netbeans.modules.soa.model.bpel20.api.BpelModel#getEntity(org.netbeans.modules.soa.model.bpel20.api.support.UniqueId)
0112: */
0113: public BpelEntity getEntity(UniqueId id) {
0114: readLock();
0115: try {
0116: BpelEntityImpl impl = ((UniqueIdImpl) id).getEntity();
0117: if (impl.isDeleted()) {
0118: return null;
0119: }
0120: return impl;
0121: } finally {
0122: readUnlock();
0123: }
0124: }
0125:
0126: //==========================================================================
0127: //=========== need to override default impl in AbstractModel =============
0128: //==========================================================================
0129: @Override
0130: public void removePropertyChangeListener(
0131: java.beans.PropertyChangeListener pcl) {
0132: myPropertyChangeSupport.removePropertyChangeListener(pcl);
0133: }
0134:
0135: @Override
0136: public void addPropertyChangeListener(
0137: java.beans.PropertyChangeListener pcl) {
0138: myPropertyChangeSupport.addPropertyChangeListener(pcl);
0139: }
0140:
0141: @Override
0142: public void removeComponentListener(ComponentListener cl) {
0143: myComponentListeners.remove(ComponentListener.class, cl);
0144: }
0145:
0146: @Override
0147: public void addComponentListener(ComponentListener cl) {
0148: myComponentListeners.add(ComponentListener.class, cl);
0149: }
0150:
0151: //==========================================================================
0152:
0153: /* (non-Javadoc)
0154: * @see org.netbeans.modules.soa.model.bpel20.api.BpelModel#addPropertyChangeListener(org.netbeans.modules.soa.model.bpel20.api.events.ChangeEventListener)
0155: */
0156: public void addEntityChangeListener(ChangeEventListener listener) {
0157: mySupport.addChangeEventListener(listener);
0158: }
0159:
0160: /* (non-Javadoc)
0161: * @see org.netbeans.modules.soa.model.bpel20.api.BpelModel#removePropertyChangeListener(org.netbeans.modules.soa.model.bpel20.api.events.ChangeEventListener)
0162: */
0163: public void removeEntityChangeListener(ChangeEventListener listener) {
0164: mySupport.removeChangeEventListener(listener);
0165: }
0166:
0167: /* (non-Javadoc)
0168: * @see org.netbeans.modules.xml.xam.Model#addUndoableEditListener(javax.swing.event.UndoableEditListener)
0169: */
0170: public void addUndoableEditListener(UndoableEditListener listener) {
0171: myUndoSupport.addUndoableEditListener(listener);
0172: }
0173:
0174: /* (non-Javadoc)
0175: * @see org.netbeans.modules.xml.xam.Model#removeUndoableEditListener(javax.swing.event.UndoableEditListener)
0176: */
0177: public void removeUndoableEditListener(UndoableEditListener listener) {
0178: myUndoSupport.removeUndoableEditListener(listener);
0179: }
0180:
0181: //=============================================================================
0182:
0183: @Override
0184: public synchronized void addUndoableRefactorListener(
0185: UndoableEditListener listener) {
0186: mySavedUndoableEditListeners = myUndoSupport
0187: .getUndoableEditListeners();
0188: if (mySavedUndoableEditListeners != null) {
0189: for (UndoableEditListener saved : mySavedUndoableEditListeners) {
0190: if (saved instanceof UndoManager) {
0191: ((UndoManager) saved).discardAllEdits();
0192: }
0193: }
0194: }
0195: myUndoSupport = new BpelModelUndoableEditSupport();
0196: myUndoSupport.addUndoableEditListener(listener);
0197: }
0198:
0199: @Override
0200: public synchronized void removeUndoableRefactorListener(
0201: UndoableEditListener listener) {
0202: myUndoSupport.removeUndoableEditListener(listener);
0203: myUndoSupport = new BpelModelUndoableEditSupport();
0204: if (mySavedUndoableEditListeners != null) {
0205: for (UndoableEditListener saved : mySavedUndoableEditListeners) {
0206: myUndoSupport.addUndoableEditListener(saved);
0207: }
0208: mySavedUndoableEditListeners = null;
0209: }
0210: }
0211:
0212: /* (non-Javadoc)
0213: * @see org.netbeans.modules.soa.model.bpel20.api.BpelModel#invoke(java.util.concurrent.Callable, java.lang.Object)
0214: */
0215: public <V> V invoke(Callable<V> action, Object source)
0216: throws Exception {
0217: /*
0218: * This just start transcation.
0219: * It could be started for safe OM packet reading.
0220: * In this case muatation will not appear.
0221: * So we set flag in writeLock in true.
0222: * Any muation method will call writeLock()
0223: * with flag equals to false, so we can check
0224: * trying to mutate OM when it should not be possible.
0225: */
0226: writeLock(true, false);
0227: try {
0228: // mySource contains source of event.
0229: assert myTransaction != null;
0230: myTransaction.setSource(source);
0231: V v = action.call();
0232:
0233: return v;
0234: } finally {
0235: writeUnlock();
0236: }
0237: }
0238:
0239: /* (non-Javadoc)
0240: * @see org.netbeans.modules.bpel.model.api.BpelModel#invoke(java.lang.Runnable)
0241: */
0242: public void invoke(Runnable run) {
0243: readLock();
0244: try {
0245: myReadLockObtained.set(true);
0246: run.run();
0247: } finally {
0248: myReadLockObtained.set(false);
0249: readUnlock();
0250: }
0251:
0252: }
0253:
0254: /* (non-Javadoc)
0255: * @see org.netbeans.modules.xml.xam.AbstractModel#createRootComponent(org.w3c.dom.Element)
0256: */
0257: @Override
0258: public BpelEntity createRootComponent(Element root) {
0259: String namespace = root.getNamespaceURI();
0260: if (BpelEntity.BUSINESS_PROCESS_NS_URI.equals(namespace)
0261: && BpelElements.PROCESS.getName().equals(
0262: root.getLocalName())) {
0263: myProcess = new ProcessImpl(this , root);
0264: myAnotherRoot = null;
0265: return myProcess;
0266: } else {
0267: myAnotherRoot = root;
0268: return null;
0269: }
0270: }
0271:
0272: /* (non-Javadoc)
0273: * @see org.netbeans.modules.xml.xam.Model#getRootComponent()
0274: */
0275: public BpelEntity getRootComponent() {
0276: return myProcess;
0277: }
0278:
0279: /* (non-Javadoc)
0280: * @see org.netbeans.modules.xml.xam.AbstractModel#validateWrite()
0281: */
0282: @Override
0283: public void validateWrite() {
0284: }
0285:
0286: /* (non-Javadoc)
0287: * @see org.netbeans.modules.xml.xam.AbstractModel#firePropertyChangeEvent(java.beans.PropertyChangeEvent)
0288: */
0289: @Override
0290: public void firePropertyChangeEvent(PropertyChangeEvent event) {
0291: /*
0292: * We don't collect events for firing them in the end of transaction.
0293: * We fire each event right away. May be this is subject for change
0294: * appropriate to firing model specific events.
0295: *
0296: * We suppose actually that clients of model will use normal BPEL OM
0297: * specific events. So this is just for compatibility.
0298: */
0299: myPropertyChangeSupport.firePropertyChange(event);
0300: }
0301:
0302: /* (non-Javadoc)
0303: * @see org.netbeans.modules.xml.xam.AbstractModel#fireComponentChangedEvent(org.netbeans.modules.xml.xam.ComponentEvent)
0304: */
0305: @Override
0306: public void fireComponentChangedEvent(ComponentEvent evt) {
0307: /*
0308: * We don't collect events for firing them in the end of transaction.
0309: * We fire each event right away. May be this is subject for change
0310: * appropriate to firing model specific events.
0311: *
0312: * We suppose actually that clients of model will use normal BPEL OM
0313: * specific events. So this is just for compatibility.
0314: */
0315: ComponentListener[] listeners = myComponentListeners
0316: .getListeners(ComponentListener.class);
0317: for (ComponentListener listener : listeners) {
0318: evt.getEventType().fireEvent(evt, listener);
0319: }
0320:
0321: if (inSync()
0322: && evt.getEventType().equals(
0323: ComponentEvent.EventType.VALUE_CHANGED)) {
0324: /*
0325: * we care here only about events that appear from source editor
0326: * and only attribute events.
0327: */
0328:
0329: Object obj = evt.getSource();
0330: if (!(obj instanceof AbstractDocumentComponent)) {
0331: return;
0332: }
0333:
0334: AbstractDocumentComponent entity = (AbstractDocumentComponent) obj;
0335: Element element = entity.getPeer();
0336:
0337: assert myTransaction != null;
0338: int i;
0339: while ((i = myTransaction.remove(element)) >= 0) {
0340: Node oldAttr = myTransaction.removeOldAttribute(i);
0341: Node newAttr = myTransaction.removeNewAttribute(i);
0342:
0343: if (entity instanceof BpelEntityImpl) {
0344: ((BpelEntityImpl) entity).handleAttributeChange(
0345: oldAttr, newAttr);
0346: }
0347: }
0348: }
0349: }
0350:
0351: /* (non-Javadoc)
0352: * @see org.netbeans.modules.xml.xam.Model#sync()
0353: */
0354: @Override
0355: public void sync() throws IOException {
0356: writeLock(true, true);
0357: ProcessImpl process = null;
0358: State oldState = null;
0359: try {
0360: if (myLock.getWriteHoldCount() > 1) {
0361: // Fix for #IZ80104
0362: return;
0363: }
0364: oldState = getState();
0365: process = getProcess();
0366:
0367: preTreeCreated(process);
0368: super .sync();
0369: postTreeCreated(process, getProcess());
0370: } finally {
0371: try {
0372: if (oldState != getState()) {
0373: PropertyUpdateEvent event = new PropertyUpdateEvent(
0374: getSource(), process, STATE, oldState,
0375: getState());
0376: fireChangeEvent(event);
0377: }
0378: } finally {
0379: writeUnlock(true);
0380: }
0381: }
0382: }
0383:
0384: /* (non-Javadoc)
0385: * @see javax.swing.event.UndoableEditListener#undoableEditHappened(javax.swing.event.UndoableEditEvent)
0386: */
0387: @Override
0388: public void undoableEditHappened(UndoableEditEvent e) {
0389: if (!inUndoRedo()) { // Fix for #77785, #80584
0390: assert myLock.getWriteHoldCount() > 0;
0391: if (!myUndoSupport.editInProgress()) {
0392: myUndoSupport.beginUpdate();
0393: }
0394: }
0395: myUndoSupport.postEdit(e.getEdit());
0396: }
0397:
0398: /* (non-Javadoc)
0399: * @see org.netbeans.modules.xml.xam.AbstractModel#getQNames()
0400: */
0401: public Set<QName> getQNames() {
0402: return getEntityRegistry().getAllQNames();
0403: }
0404:
0405: /* (non-Javadoc)
0406: * @see org.netbeans.modules.xml.xam.DocumentModel#createComponent(C, org.w3c.dom.Element)
0407: */
0408: public BpelEntity createComponent(BpelEntity parent, Element element) {
0409: if (!(parent instanceof BpelContainer)) {
0410: return null;
0411: }
0412: return getChildBuilder()
0413: .create(element, (BpelContainer) parent);
0414: }
0415:
0416: /* (non-Javadoc)
0417: * @see org.netbeans.modules.bpel.model.api.BpelModel#findElement(int)
0418: */
0419: public BpelEntity findElement(int i) {
0420: readLock();
0421: try {
0422: Component comp = findComponent(i);
0423:
0424: assert comp == null || comp instanceof BpelEntity;
0425: return (BpelEntity) comp;
0426: } finally {
0427: readUnlock();
0428: }
0429: }
0430:
0431: @Override
0432: public boolean isIntransaction() {
0433: return myLock.getWriteHoldCount() > 0;
0434: }
0435:
0436: @Override
0437: public boolean startTransaction() {
0438: writeLock(true, false);
0439: isXamTransaction = true;
0440: return super .startTransaction();
0441: }
0442:
0443: @Override
0444: public void endTransaction() {
0445: try {
0446: super .endTransaction();
0447: } finally {
0448: if (isXamTransaction) {
0449: isXamTransaction = false;
0450: writeUnlock();
0451: }
0452: }
0453: }
0454:
0455: @Override
0456: public void rollbackTransaction() {
0457: try {
0458: myUndoSupport.abortUpdate();
0459: finishTransaction();
0460: } finally {
0461: if (isXamTransaction) {
0462: isXamTransaction = false;
0463: writeUnlock();
0464: }
0465: }
0466: }
0467:
0468: public boolean isSupportedExpension(String uri) {
0469: Collection<EntityFactory> factories = getEntityRegistry()
0470: .getFactories();
0471: for (EntityFactory factory : factories) {
0472: if (factory.isApplicable(uri)) {
0473: return true;
0474: }
0475: }
0476: return false;
0477: }
0478:
0479: /*
0480: * (non-Javadoc)
0481: *
0482: * @see org.netbeans.modules.bpel.model.api.BpelModel#getAnotherVersionProcess()
0483: */
0484: public AnotherVersionBpelProcess getAnotherVersionProcess() {
0485: if (getState() == State.VALID) {
0486: return null;
0487: } else {
0488: Element element = null;
0489: if (getProcess() == null) { // in the case when xml was invalid from very beggining
0490: org.w3c.dom.Document doc = getDocument();
0491: if (doc == null) {
0492: return null;
0493: }
0494: element = doc.getDocumentElement();
0495: if (element == null) {
0496: return null;
0497: }
0498: } else { // in the case when xml was originally good BPEL but was changed in incorrect way
0499: if (myAnotherRoot == null) {
0500: return null;
0501: }
0502: element = myAnotherRoot;
0503: }
0504: return new AnotherVersionBpelProcessImpl(this , element);
0505: }
0506: }
0507:
0508: /* (non-Javadoc)
0509: * @see org.netbeans.modules.bpel.model.api.BpelModel#getAnotherVersionProcess()
0510: */
0511: public boolean canExtend(ExtensibleElements extensible,
0512: Class<? extends ExtensionEntity> extensionType) {
0513: Collection<EntityFactory> factories = getEntityRegistry()
0514: .getFactories();
0515: for (EntityFactory factory : factories) {
0516: if (factory.canExtend(extensible, extensionType)) {
0517: return true;
0518: }
0519: }
0520: return false;
0521: }
0522:
0523: /*
0524: * (non-Javadoc)
0525: *
0526: * @see org.netbeans.modules.xml.xam.xdm.AbstractXDMModel#getComponentUpdater()
0527: */
0528: @Override
0529: protected ComponentUpdater<BpelEntity> getComponentUpdater() {
0530: if (mySyncUpdateVisitor == null) {
0531: mySyncUpdateVisitor = new SyncUpdateVisitor();
0532: }
0533: return mySyncUpdateVisitor;
0534: }
0535:
0536: protected void readLock() {
0537: readLock.lock();
0538: }
0539:
0540: protected void readUnlock() {
0541: readLock.unlock();
0542: }
0543:
0544: protected void writeLock() {
0545: writeLock(false, false);
0546: }
0547:
0548: protected void writeUnlock() {
0549: writeUnlock(false);
0550: }
0551:
0552: protected Object getSource() {
0553: assert myTransaction != null;
0554: return myTransaction.getSource();
0555: }
0556:
0557: EntityFactoryRegistry getEntityRegistry() {
0558: return EntityFactoryRegistry.getInstance();
0559: }
0560:
0561: long getNextID() {
0562: return myNextID.incrementAndGet();
0563: }
0564:
0565: final boolean isInEventsFiring() {
0566: if (myTransaction == null) {
0567: return false;
0568: }
0569: return myTransaction.isCommit;
0570: }
0571:
0572: /**
0573: * This method will be called before OM change was performed and we possibly
0574: * need to collect some information.
0575: *
0576: * @throws could
0577: * throw VetoException. It means that some visitor reject
0578: * change.
0579: */
0580: final void preInnerEventNotify(ChangeEvent event)
0581: throws VetoException {
0582: InnerEventDispatcher[] dispatchers = getInnerDispatchers();
0583: int executed = 0;
0584: try {
0585: for (InnerEventDispatcher dispatcher : dispatchers) {
0586: if (dispatcher.isApplicable(event)) {
0587: dispatcher.preDispatch(event);
0588: executed++;
0589: }
0590: }
0591: } catch (VetoException e) {
0592: int i = 0;
0593: for (InnerEventDispatcher dispatcher : dispatchers) {
0594: if (i > executed) {
0595: break;
0596: }
0597: if (dispatcher.isApplicable(event)) {
0598: dispatcher.reset(event);
0599: i++;
0600: }
0601: }
0602: throw e;
0603: }
0604: }
0605:
0606: /**
0607: * This method will be called right after OM change was performed and we
0608: * possibly need to change other elements in OM accordingly this change.
0609: */
0610: final void postInnerEventNotify(ChangeEvent event) {
0611: InnerEventDispatcher[] dispatchers = getInnerDispatchers();
0612: for (InnerEventDispatcher dispatcher : dispatchers) {
0613: if (dispatcher.isApplicable(event)) {
0614: dispatcher.postDispatch(event);
0615: }
0616: }
0617: }
0618:
0619: /**
0620: * This method should be visible only for model impl elements.
0621: *
0622: * @param event
0623: * event for firing.
0624: */
0625: final void fireChangeEvent(ChangeEvent event) {
0626: /*if ( event.getParent() instanceof PartnerLink ) {
0627: try {
0628: throw new Exception();
0629: }
0630: catch( Exception e ) {
0631: e.printStackTrace();
0632: }
0633: }*/
0634: myTransaction.add(event);
0635: }
0636:
0637: BpelChildEntitiesBuilder getChildBuilder() {
0638: return myChildBuilder;
0639: }
0640:
0641: private void writeLock(boolean allowMutation,
0642: boolean addMergeListener) {
0643: writeLock.lock();
0644: if (myReadLockObtained.get() != null
0645: && myReadLockObtained.get()) {
0646: throw new IllegalStateException(
0647: "You are trying to mutate OM " // NOI18N
0648: + "while read lock is obtianed."); // NOI18N
0649: }
0650: if (!inSync() && !allowMutation
0651: && getState().equals(State.NOT_WELL_FORMED)) {
0652: throw new IllegalStateException("Xml file is broken." + // NOI18N
0653: " One cannot mutate model in broken state."); // NOI18N
0654: }
0655: if (addMergeListener && myLock.getWriteHoldCount() == 1) {
0656: getAccess().addMergeEventHandler(myXDMListener);
0657: }
0658: if (myTransaction == null) {
0659: myTransaction = new Transaction();
0660: }
0661: myTransaction.start();
0662: }
0663:
0664: private void writeUnlock(boolean inSync) {
0665: try { // just want to be sure that unlock will happen anyway.
0666: assert myTransaction != null;
0667:
0668: if (inSync && myLock.getWriteHoldCount() == 1) {
0669: getAccess().removeMergeEventHandler(myXDMListener);
0670: setInSync(true);
0671: }
0672:
0673: myTransaction.end();
0674: } finally {
0675: writeLock.unlock();
0676: }
0677: }
0678:
0679: private static ModelSource getOrCreateModelSource(Document doc,
0680: Lookup lookup) {
0681: Lookup lkup = Lookups.fixed(new Object[] { doc });
0682: return new ModelSource(lkup, true);
0683: }
0684:
0685: /**
0686: *
0687: * I need the way to access to other OM ( Schema and WSDL )
0688: * and files . Currently for this purpose I use lookup.
0689: * Possibly this will be redone.
0690: *
0691: */
0692: private void init() {
0693: mySupport = new ChangeEventSupport();
0694: myUndoSupport = new BpelModelUndoableEditSupport();
0695: myPropertyChangeSupport = new PropertyChangeSupport(this );
0696: myComponentListeners = new EventListenerList();
0697: //getXDMAccess().getReferenceModel().setPretty(true);
0698: myXDMListener = new XDMListener();
0699: myChildBuilder = new BpelChildEntitiesBuilder(this );
0700:
0701: getAccess().setAutoSync(true);
0702: }
0703:
0704: private void postTreeCreated(Process old, Process newProcess) {
0705: TreeCreatedEvent<Process> newEvent = new TreeCreatedEvent<Process>(
0706: newProcess);
0707: if (old != newProcess) {
0708: postInnerEventNotify(newEvent);
0709: }
0710: }
0711:
0712: /**
0713: * @param process
0714: */
0715: private void preTreeCreated(Process process) {
0716: TreeCreatedEvent<Process> event = new TreeCreatedEvent<Process>(
0717: process);
0718: try {
0719: if (process == null) {
0720: preInnerEventNotify(event);
0721: }
0722: } catch (VetoException e) {
0723: assert false;
0724: }
0725: }
0726:
0727: @SuppressWarnings("unchecked")
0728: private InnerEventDispatcher[] getInnerDispatchers() {
0729: if (myDispatchers == null) {
0730: if (null == innerDispatcherResult) {
0731: innerDispatcherResult = Lookup.getDefault()
0732: .lookup(
0733: new Lookup.Template(
0734: InnerEventDispatcher.class));
0735: }
0736: myDispatchers = (InnerEventDispatcher[]) innerDispatcherResult
0737: .allInstances()
0738: .toArray(
0739: new InnerEventDispatcher[innerDispatcherResult
0740: .allInstances().size()]);
0741: }
0742: return myDispatchers;
0743: }
0744:
0745: protected class BpelModelUndoableEditSupport extends
0746: UndoableEditSupport {
0747:
0748: @Override
0749: public synchronized void beginUpdate() {
0750: super .beginUpdate();
0751: inProgress = true;
0752: }
0753:
0754: @Override
0755: public synchronized void endUpdate() {
0756: inProgress = false;
0757: super .endUpdate();
0758: }
0759:
0760: @Override
0761: protected CompoundEdit createCompoundEdit() {
0762: return new BpelModelUndoableEdit();
0763: }
0764:
0765: protected boolean editInProgress() {
0766: return inProgress;
0767: }
0768:
0769: protected void abortUpdate() {
0770: ModelUndoableEdit mue = (ModelUndoableEdit) compoundEdit;
0771: mue.justUndo();
0772: super .compoundEdit = createCompoundEdit();
0773: }
0774:
0775: private boolean inProgress;
0776: }
0777:
0778: protected class BpelModelUndoableEdit extends ModelUndoableEdit {
0779:
0780: private static final long serialVersionUID = 3771336438002454367L;
0781:
0782: @Override
0783: public void redo() {
0784: writeLock(true, true);
0785: try {
0786: super .redo();
0787: setInUndoRedo(true);
0788: } finally {
0789: writeUnlock(true);
0790: }
0791: }
0792:
0793: @Override
0794: public void undo() {
0795: writeLock(true, true);
0796: try {
0797: super .undo();
0798: setInUndoRedo(true);
0799: } finally {
0800: writeUnlock(true);
0801: }
0802: }
0803: }
0804:
0805: private final class Transaction {
0806:
0807: private Transaction() {
0808: myFullTransactionEventSet = new LinkedList<ChangeEvent>();
0809: }
0810:
0811: /**
0812: * Notify transaction about start.
0813: * Realy transaction could be already started.
0814: * We just notify it that one more lock is entered.
0815: */
0816: void start() {
0817: // ?? in previous version there was counter for locks.
0818: // Now I get this counter dirrectly from myLock.
0819: // Keep this method for possible rewriting. May be it needs to be removed.....
0820: }
0821:
0822: /**
0823: * Notify transaction about end.
0824: * Realy it just notify about lock was released.
0825: */
0826: void end() {
0827: if (myLock.getWriteHoldCount() == 1) {
0828: try {
0829: commitEvents();
0830: if (!inUndoRedo() && myUndoSupport.editInProgress()) {
0831: myUndoSupport.endUpdate();
0832: }
0833: } finally {
0834: if (inSync()) {
0835: setInUndoRedo(false);
0836: setInSync(false);
0837: }
0838: setSource(null);
0839: cleanEvents();
0840: cleanAttributeChanges();
0841: }
0842: }
0843: }
0844:
0845: private void cleanEvents() {
0846: myFullTransactionEventSet.clear();
0847: }
0848:
0849: /**
0850: * Add the event into chain if events.
0851: */
0852: void add(ChangeEvent event) {
0853: assert myLock.getWriteHoldCount() > 0;
0854: if (isCommit) {
0855: throw new IllegalStateException(
0856: "Model should not be changed inside " + // NOI18N
0857: "event listener.");// NOI18N
0858: }
0859: myFullTransactionEventSet.offer(event);
0860: }
0861:
0862: Object getSource() {
0863: if (mySource == null) {
0864: return Thread.currentThread();
0865: }
0866: return mySource;
0867: }
0868:
0869: void setSource(Object obj) {
0870: mySource = obj;
0871: }
0872:
0873: void addAttributeChange(Node parent, Node old, Node newValue) {
0874: myParents.add(parent);
0875: myOldAttrs.add(old);
0876: myNewAttrs.add(newValue);
0877: }
0878:
0879: int remove(org.w3c.dom.Node parent) {
0880: assert parent instanceof Node;
0881: int i = 0;
0882: int ret = -1;
0883: for (Node node : myParents) {
0884: if (areSameNodes(node, (Node) parent)) {
0885: ret = i;
0886: }
0887: i++;
0888: }
0889: if (ret >= 0) {
0890: myParents.remove(ret);
0891: }
0892: return ret;
0893: }
0894:
0895: Node removeOldAttribute(int i) {
0896: return myOldAttrs.remove(i);
0897: }
0898:
0899: Node removeNewAttribute(int i) {
0900: return myNewAttrs.remove(i);
0901: }
0902:
0903: private void commitEvents() {
0904: isCommit = true;
0905: ChangeEvent event;
0906: try {
0907: boolean eventsExist = false;
0908: while ((event = myFullTransactionEventSet.poll()) != null) {
0909: if (myFullTransactionEventSet.size() > 0) {
0910: event.setNotLast();
0911: } else {
0912: eventsExist = true;
0913: event.setLast();
0914: }
0915: mySupport.fireChangeEvent(event);
0916: }
0917: if (!inSync() && eventsExist) {
0918: // inSync flag tell us that update was performed
0919: // via editor
0920: getAccess().flush();
0921: }
0922: } finally {
0923: isCommit = false;
0924: }
0925: }
0926:
0927: private void cleanAttributeChanges() {
0928: if (!inSync()) {
0929: return;
0930: }
0931: myParents.clear();
0932: myOldAttrs.clear();
0933: myNewAttrs.clear();
0934: }
0935:
0936: private Queue<ChangeEvent> myFullTransactionEventSet;
0937:
0938: private boolean isCommit;
0939:
0940: private Object mySource;
0941:
0942: private List<Node> myParents = new ArrayList<Node>();
0943:
0944: private List<Node> myOldAttrs = new ArrayList<Node>();
0945:
0946: private List<Node> myNewAttrs = new ArrayList<Node>();
0947: }
0948:
0949: private class XDMListener implements PropertyChangeListener {
0950:
0951: public void propertyChange(PropertyChangeEvent event) {
0952: //System.out.println("CALLED !");
0953:
0954: Node old = getAccess().getOldEventNode(event);
0955: Node now = getAccess().getNewEventNode(event);
0956:
0957: Node notNull = old == null ? now : old;
0958: if (notNull == null) {
0959: return;
0960: }
0961:
0962: Node parent = old == null ? getAccess()
0963: .getNewEventParentNode(event) : getAccess()
0964: .getOldEventParentNode(event);
0965:
0966: if (notNull.getNodeType() == Node.ATTRIBUTE_NODE) {
0967: assert myTransaction != null;
0968: myTransaction.addAttributeChange(parent, old, now);
0969: }
0970:
0971: //if ( notNull.getNodeType() == Node.TEXT_NODE){
0972: if (notNull instanceof Text) {
0973: handleChangeInText(old, now, parent);
0974: }
0975:
0976: }
0977:
0978: private void handleChangeInText(Node old, Node now, Node parent) {
0979: //if ( parent instanceof org.netbeans.modules.xml.xdm.nodes.Element ){
0980: if (parent instanceof Element) {
0981: Component component = findComponent(getAccess()
0982: .getPathFromRoot(getDocument(),
0983: (Element) parent));
0984: if (component instanceof ContentElement) {
0985: String oldValue = null;
0986: String value = null;
0987: if (old != null) {
0988: oldValue = old.getNodeValue();
0989: }
0990: if (now != null) {
0991: value = now.getNodeValue();
0992: }
0993: PropertyUpdateEvent ev = new PropertyUpdateEvent(
0994: getSource(), (BpelEntity) component,
0995: ContentElement.CONTENT_PROPERTY, oldValue,
0996: value);
0997:
0998: assert myTransaction != null;
0999: myTransaction.add(ev);
1000: }
1001: }
1002: }
1003:
1004: }
1005:
1006: private ChangeEventSupport mySupport;
1007:
1008: private Lookup.Result innerDispatcherResult;
1009:
1010: private InnerEventDispatcher[] myDispatchers;
1011:
1012: private final BpelBuilderImpl myBuilder = new BpelBuilderImpl(this );
1013:
1014: private ProcessImpl myProcess;
1015:
1016: private AtomicLong myNextID = new AtomicLong();
1017:
1018: private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
1019:
1020: private final Lock readLock = myLock.readLock();
1021:
1022: private final Lock writeLock = myLock.writeLock();
1023:
1024: private BpelModelUndoableEditSupport myUndoSupport;
1025:
1026: private SyncUpdateVisitor mySyncUpdateVisitor;
1027:
1028: private XDMListener myXDMListener;
1029:
1030: private Transaction myTransaction;
1031:
1032: private PropertyChangeSupport myPropertyChangeSupport;
1033:
1034: private EventListenerList myComponentListeners;
1035:
1036: private boolean isXamTransaction;
1037:
1038: private UndoableEditListener[] mySavedUndoableEditListeners;
1039:
1040: private ThreadLocal<Boolean> myReadLockObtained = new ThreadLocal<Boolean>();
1041:
1042: private BpelChildEntitiesBuilder myChildBuilder;
1043:
1044: private Element myAnotherRoot;
1045:
1046: }
|