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.model.impl;
020:
021: import java.util.ArrayList;
022: import java.util.Collections;
023: import java.util.HashMap;
024: import java.util.List;
025: import java.util.Map;
026:
027: import java.util.WeakHashMap;
028: import javax.xml.namespace.QName;
029:
030: import org.netbeans.modules.bpel.model.api.BpelContainer;
031: import org.netbeans.modules.bpel.model.api.BpelEntity;
032: import org.netbeans.modules.bpel.model.api.events.ChangeEvent;
033: import org.netbeans.modules.bpel.model.api.events.VetoException;
034: import org.netbeans.modules.bpel.model.api.references.BpelReference;
035: import org.netbeans.modules.bpel.model.api.references.BpelReferenceable;
036: import org.netbeans.modules.bpel.model.api.references.SchemaReference;
037: import org.netbeans.modules.bpel.model.api.support.BpelModelVisitor;
038: import org.netbeans.modules.bpel.model.api.support.ExNamespaceContext;
039: import org.netbeans.modules.bpel.model.api.support.SimpleBpelModelVisitor;
040: import org.netbeans.modules.bpel.model.api.support.TBoolean;
041: import org.netbeans.modules.bpel.model.api.support.UniqueId;
042: import org.netbeans.modules.bpel.model.ext.ExtBpelAttribute;
043: import org.netbeans.modules.bpel.model.impl.events.BuildEvent;
044: import org.netbeans.modules.bpel.model.impl.events.CopyEvent;
045: import org.netbeans.modules.bpel.model.impl.events.CutEvent;
046: import org.netbeans.modules.bpel.model.impl.references.BpelReferenceBuilder;
047: import org.netbeans.modules.bpel.model.impl.references.SchemaReferenceBuilder;
048: import org.netbeans.modules.bpel.model.impl.references.WSDLReference;
049: import org.netbeans.modules.bpel.model.impl.references.WSDLReferenceBuilder;
050: import org.netbeans.modules.bpel.model.xam.BpelAttributes;
051: import org.netbeans.modules.bpel.model.xam.BpelElements;
052: import org.netbeans.modules.xml.schema.model.ReferenceableSchemaComponent;
053: import org.netbeans.modules.xml.wsdl.model.ReferenceableWSDLComponent;
054: import org.netbeans.modules.xml.xam.Component;
055: import org.netbeans.modules.xml.xam.Reference;
056: import org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent;
057: import org.netbeans.modules.xml.xam.dom.Attribute;
058: import org.w3c.dom.Comment;
059: import org.w3c.dom.Element;
060: import org.w3c.dom.Node;
061: import org.w3c.dom.NodeList;
062: import org.w3c.dom.Text;
063:
064: /**
065: * @author ads
066: */
067: public abstract class BpelEntityImpl extends
068: AbstractDocumentComponent<BpelEntity> implements BpelEntity {
069:
070: BpelEntityImpl(BpelModelImpl model, Element e) {
071: super (model, e);
072: myModel = model;
073: myAccess = new AttributeAccess(this );
074: }
075:
076: /**
077: * This constructor is designed only for using in <code>builder</code>.
078: * Here some inner events will be generated when new element is created via
079: * builder.
080: */
081: BpelEntityImpl(BpelBuilderImpl builder, String tagName) {
082: this (builder.getModel(), createNewComponent(builder.getModel(),
083: tagName));
084: writeLock();
085: try {
086: BuildEvent<? extends BpelEntity> event = preCreated(this );
087: postEvent(event);
088: } finally {
089: writeUnlock();
090: }
091: }
092:
093: public BpelEntityImpl(BpelBuilderImpl builder, BpelElements elem) {
094: this (builder.getModel(), createNewComponent(builder.getModel(),
095: elem));
096: writeLock();
097: try {
098: BuildEvent<? extends BpelEntity> event = preCreated(this );
099: postEvent(event);
100: } finally {
101: writeUnlock();
102: }
103: }
104:
105: /**
106: * This method should be implemented by any real class.
107: * It returns list of possible attributes for entity.
108: * It used in firing event about attribute change while synchronizing with source.
109: */
110: protected abstract Attribute[] getDomainAttributes();
111:
112: public BpelModelImpl getBpelModel() {
113: return myModel;
114: }
115:
116: @Override
117: public BpelModelImpl getModel() {
118: return (BpelModelImpl) super .getModel();
119: }
120:
121: @Override
122: public boolean canPaste(Component child) {
123: // only container can contain children elements.
124: // this method is redefined in BpelContainer.
125: return false;
126: }
127:
128: /*
129: * (non-Javadoc)
130: *
131: * @see org.netbeans.modules.soa.model.bpel.api.BpelEntity#copy(java.util.HashMap)
132: */
133: public BpelEntity copy(HashMap<UniqueId, UniqueId> uniqueMap) {
134: writeLock();
135: try {
136: checkDeleted();
137: checkInTree();
138: CopyEvent<? extends BpelEntity> event = preCopy(this );
139:
140: BpelEntity entity = copy(getParent());
141: // we set our unique map as cookie in created entity.
142: // after constructing we will remove it.
143: entity.setCookie(IdMapKey.class, uniqueMap);
144: event.setOutOfModelEntity(entity);
145:
146: postEvent(event);
147:
148: entity.removeCookie(IdMapKey.class);
149: return entity;
150: } finally {
151: writeUnlock();
152: }
153: }
154:
155: @Override
156: public final BpelContainerImpl getParent() {
157: return (BpelContainerImpl) super .getParent();
158: }
159:
160: /*
161: * (non-Javadoc)
162: *
163: * @see org.netbeans.modules.soa.model.bpel.api.BpelEntity#cut()
164: */
165: public BpelEntity cut() {
166: writeLock();
167: try {
168: checkDeleted();
169: checkInTree();
170: CutEvent<? extends BpelEntity> event = preCut(this );
171:
172: BpelEntity entity = copy(getParent());
173: if (getParent() != null) {
174: assert getParent() instanceof BpelContainer;
175: ((BpelContainer) getParent()).remove(this );
176: }
177:
178: event.setOutOfModelEntity(entity);
179: postEvent(event);
180:
181: return entity;
182: } finally {
183: writeUnlock();
184: }
185: }
186:
187: @Override
188: public BpelEntity copy(BpelEntity parent) {
189: writeLock();
190: try {
191: BpelEntity entity = (BpelEntity) super .copy(parent);
192: return entity;
193: } finally {
194: writeUnlock();
195: }
196: }
197:
198: /*
199: * (non-Javadoc)
200: *
201: * @see org.netbeans.modules.soa.model.bpel.api.BpelEntity#getUID()
202: */
203: public UniqueId getUID() {
204: return myUid;
205: }
206:
207: /*
208: * (non-Javadoc)
209: *
210: * @see org.netbeans.modules.soa.model.bpel.api.BpelEntity#getNamespaceContext()
211: */
212: public ExNamespaceContext getNamespaceContext() {
213: return new ExNamespaceContextImpl(this );
214: }
215:
216: /* (non-Javadoc)
217: * @see org.netbeans.modules.soa.model.bpel20.api.BpelEntity#accept(org.netbeans.modules.soa.model.bpel20.api.support.BpelModelVisitor)
218: */
219: public final void accept(SimpleBpelModelVisitor visitor) {
220: accept((BpelModelVisitor) visitor);
221: acceptChildren(visitor);
222: }
223:
224: /*
225: * (non-Javadoc)
226: *
227: * @see org.netbeans.modules.soa.model.bpel.api.BpelEntity#getCookie(java.lang.Class)
228: */
229: public Object getCookie(Object key) {
230: return myCookies.get(key);
231:
232: }
233:
234: /*
235: * (non-Javadoc)
236: *
237: * @see org.netbeans.modules.soa.model.bpel.api.BpelEntity#setCookie(java.lang.Object)
238: */
239: public void setCookie(Object key, Object obj) {
240:
241: myCookies.put(key, obj);
242: }
243:
244: /*
245: * (non-Javadoc)
246: *
247: * @see org.netbeans.modules.soa.model.bpel.api.BpelEntity#removeCookie(java.lang.Object)
248: */
249: public void removeCookie(Object obj) {
250:
251: myCookies.remove(obj);
252:
253: }
254:
255: //############################################################################
256: //##
257: //## Methods for creation references to other model and inside BPEL model.
258: //## Default implementation.
259: //##
260: //############################################################################
261: public <T extends ReferenceableSchemaComponent> SchemaReference<T> createSchemaReference(
262: T target, Class<T> type) {
263: readLock();
264: try {
265: return SchemaReferenceBuilder.getInstance().build(target,
266: type, this );
267: } finally {
268: readUnlock();
269: }
270: }
271:
272: public <T extends BpelReferenceable> BpelReference<T> createReference(
273: T target, Class<T> type) {
274: readLock();
275: try {
276: return BpelReferenceBuilder.getInstance().build(target,
277: type, this );
278: } finally {
279: readUnlock();
280: }
281: }
282:
283: public <T extends ReferenceableWSDLComponent> WSDLReference<T> createWSDLReference(
284: T target, Class<T> type) {
285: readLock();
286: try {
287: return WSDLReferenceBuilder.getInstance().build(target,
288: type, this );
289: } finally {
290: readUnlock();
291: }
292: }
293:
294: @Override
295: public String getAttribute(Attribute attr) {
296: readLock();
297: try {
298: // Extension attribute requires namespace context to
299: // provide a prefix. Therefore the implied owner has to be assigned.
300: if (attr instanceof ExtBpelAttribute) {
301: ((ExtBpelAttribute) attr).setOwner(this );
302: }
303:
304: /*
305: * TODO : there is bug in XAM/XDM.
306: * XML entities such as >, ', " is not recognized.
307: * The method below perform replacement in string pointed
308: * entities to corresponding values.
309: * Usage of this method possibly should be removed
310: * when bug in XAM/XDM will be fixed.
311: */
312: return Utils.hackXmlEntities(super .getAttribute(attr));
313: } finally {
314: readUnlock();
315: }
316: }
317:
318: @Override
319: public void setAttribute(String propName, Attribute attr,
320: Object value) {
321: writeLock();
322: try {
323: super .setAttribute(propName, attr, value);
324: } finally {
325: writeUnlock();
326: }
327: }
328:
329: //############################################################################
330: /**
331: * @param visitor
332: */
333: protected void acceptChildren(SimpleBpelModelVisitor visitor) {
334: List<BpelEntity> children = getChildren();
335: for (BpelEntity entity : children) {
336: entity.accept(visitor);
337: }
338: }
339:
340: protected TBoolean getBooleanAttribute(Attribute attr) {
341: return getAttributeAccess().getBooleanAttribute(attr);
342: }
343:
344: protected <T extends BpelReferenceable> List<BpelReference<T>> getBpelReferenceList(
345: Attribute attr, Class<T> type) {
346: return getAttributeAccess().getBpelReferenceList(attr, type);
347: }
348:
349: protected <T extends ReferenceableWSDLComponent> List<org.netbeans.modules.bpel.model.api.references.WSDLReference<T>> getWSDLReferenceList(
350: Attribute attr, Class<T> type) {
351: return getAttributeAccess().getWSDLReferenceList(attr, type);
352: }
353:
354: protected <T extends ReferenceableSchemaComponent> List<SchemaReference<T>> getSchemaReferenceList(
355: Attribute attr, Class<T> type) {
356: return getAttributeAccess().getSchemaReferenceList(attr, type);
357: }
358:
359: protected <T extends BpelReferenceable> void setBpelReferenceList(
360: Attribute attr, Class<T> type, List<BpelReference<T>> list) {
361: getAttributeAccess().setBpelReferenceList(attr, type, list);
362: }
363:
364: protected <T extends ReferenceableWSDLComponent> void setWSDLReferenceList(
365: Attribute attr,
366: Class<T> type,
367: List<org.netbeans.modules.bpel.model.api.references.WSDLReference<T>> list) {
368: getAttributeAccess().setWSDLReferenceList(attr, type, list);
369: }
370:
371: protected void setBpelAttribute(Attribute attr, String value)
372: throws VetoException {
373: getAttributeAccess().setBpelAttribute(attr, value);
374: }
375:
376: protected void setBpelAttribute(Attribute attr, Enum value) {
377: getAttributeAccess().setBpelAttribute(attr, value);
378: }
379:
380: protected void setBpelAttribute(Attribute attr, QName qName)
381: throws VetoException {
382: getAttributeAccess().setBpelAttribute(attr, qName);
383: }
384:
385: protected QName getQNameAttribute(Attribute attr) {
386: return getAttributeAccess().getQNameAttribute(attr);
387: }
388:
389: @Override
390: protected void setText(String propName, String text) {
391: writeLock();
392: try {
393: StringBuilder oldValue = new StringBuilder();
394: ArrayList<Node> toRemove = new ArrayList<Node>();
395: NodeList nodeList = getPeer().getChildNodes();
396:
397: Element ref = null;
398: for (int i = 0; i < nodeList.getLength(); i++) {
399: Node node = nodeList.item(i);
400: if (node != null
401: && node.getNodeType() == Node.ELEMENT_NODE) {
402: ref = (Element) node;
403: }
404: if (node instanceof Text
405: && node.getNodeType() != Node.COMMENT_NODE) {
406: toRemove.add(node);
407: oldValue.append(node.getNodeValue());
408: }
409: }
410:
411: getModel().getAccess().removeChildren(getPeer(), toRemove,
412: this );
413: if (text != null) {
414: Text newNode = getModel().getDocument().createTextNode(
415: text);
416: if (ref != null) {
417: getModel().getAccess().insertBefore(getPeer(),
418: newNode, ref, this );
419: } else {
420: getModel().getAccess().appendChild(getPeer(),
421: newNode, this );
422: }
423: }
424:
425: firePropertyChange(propName, oldValue == null ? null
426: : oldValue.toString(), text);
427: fireValueChanged();
428: } finally {
429: writeUnlock();
430: }
431: }
432:
433: protected void setText(String text) throws VetoException {
434: getAttributeAccess().setText(text);
435: }
436:
437: protected void removeAttribute(Attribute attr) {
438: getAttributeAccess().removeAttribute(attr);
439: }
440:
441: protected <T extends BpelReferenceable> BpelReference<T> getBpelReference(
442: Attribute attr, Class<T> clazz) {
443: return getAttributeAccess().getBpelReference(attr, clazz);
444: }
445:
446: protected <T extends ReferenceableWSDLComponent> WSDLReference<T> getWSDLReference(
447: Attribute attr, Class<T> clazz) {
448: return getAttributeAccess().getWSDLReference(attr, clazz);
449: }
450:
451: protected <T extends ReferenceableSchemaComponent> SchemaReference<T> getSchemaReference(
452: Attribute attr, Class<T> clazz) {
453: return getAttributeAccess().getSchemaReference(attr, clazz);
454: }
455:
456: protected <T extends BpelReferenceable> void setBpelReference(
457: Attribute attr, BpelReference<T> ref) {
458: getAttributeAccess().setBpelReference(attr, ref);
459: }
460:
461: protected <T extends ReferenceableWSDLComponent> void setWSDLReference(
462: Attribute attr,
463: org.netbeans.modules.bpel.model.api.references.WSDLReference<T> ref) {
464: getAttributeAccess().setWSDLReference(attr, ref);
465: }
466:
467: protected <T extends ReferenceableSchemaComponent> void setSchemaReference(
468: Attribute attr, SchemaReference<T> ref) {
469: getAttributeAccess().setSchemaReference(attr, ref);
470: }
471:
472: protected void removeReference(BpelAttributes attr) {
473: getAttributeAccess().removeAttribute(attr);
474: }
475:
476: /**
477: * This method is return corrected Text content without XML
478: * comments. See the problem appeared in getText() method.
479: *
480: */
481: protected String getCorrectedText() {
482: readLock();
483: try {
484: StringBuilder text = new StringBuilder();
485: NodeList nodeList = getPeer().getChildNodes();
486: for (int i = 0; i < nodeList.getLength(); i++) {
487: Node node = nodeList.item(i);
488: if (node instanceof Text && !(node instanceof Comment)) {
489: text.append(node.getNodeValue());
490: }
491: }
492: /*
493: * TODO : there is bug in XAM/XDM.
494: * XML entities such as >, ', " is not recognized.
495: * The method below perform replacement in string pointed
496: * entities to corresponding values.
497: * Usage of this method possibly should be removed
498: * when bug in XAM/XDM will be fixed.
499: * Fix for #84651
500: */
501: return Utils.hackXmlEntities(text.toString());
502: } finally {
503: readUnlock();
504: }
505: }
506:
507: /*
508: * This method has some problems.
509: * It return XML comments that are found inside current XML element.
510: * This is consequence of XDM implementation. XDM consider each line in
511: * XML comment as Text Node.
512: * Possibly it will be fixed. New method getCorrectedText() is created for
513: * fixing this problem.
514: *
515: * (non-Javadoc)
516: * @see org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent#getText()
517: */
518: @Override
519: protected String getText() {
520: readLock();
521: try {
522: /*
523: * TODO : there is bug in XAM/XDM.
524: * XML entities such as >, ', " is not recognized.
525: * The method below perform replacement in string pointed
526: * entities to corresponding values.
527: * Usage of this method possibly should be removed
528: * when bug in XAM/XDM will be fixed.
529: */
530: return Utils.hackXmlEntities(super .getText());
531: } finally {
532: readUnlock();
533: }
534: }
535:
536: @Override
537: protected void populateChildren(List<BpelEntity> children) {
538: // bpelentity is not container
539: }
540:
541: /*@Override
542: protected String getNamespaceURI()
543: {
544: return BUSINESS_PROCESS_NS_URI;
545: }*/
546: @Override
547: protected Object getAttributeValueOf(Attribute attr,
548: String stringValue) {
549: return getAttributeAccess().getAttributeValueOf(attr,
550: stringValue);
551: }
552:
553: //#############################################################
554: //##
555: //## Next methods are utility methods for model framework.
556: //##
557: //#############################################################
558: protected final void readLock() {
559: getBpelModel().readLock();
560: }
561:
562: protected final void readUnlock() {
563: getBpelModel().readUnlock();
564: }
565:
566: protected final void writeLock() {
567: getBpelModel().writeLock();
568: }
569:
570: protected final void writeUnlock() {
571: getBpelModel().writeUnlock();
572: }
573:
574: protected final void checkInTree() {
575: if (!isInTree()) {
576: throw new IllegalStateException(
577: "Trying to access entity that "// NOI18N
578: + "is not in the tree"); // NOI18N
579: }
580: }
581:
582: protected final void checkDeleted() {
583: if (getBpelModel().isInEventsFiring()) {
584: // allow to access to tree structure while handling event.
585: return;
586: }
587: if (isDeleted()) {
588: throw new IllegalStateException(
589: "Trying to access entity that "// NOI18N
590: + "already was deleted"); // NOI18N
591: }
592: }
593:
594: protected final String getEntityName() {
595: return getPeer().getLocalName();
596: }
597:
598: protected final void setInTree() {
599: isInTree = true;
600: }
601:
602: protected final void setInTreeRecursively() {
603: setInTree();
604: List<BpelEntityImpl> list = getChildren(BpelEntityImpl.class);
605: for (BpelEntityImpl child : list) {
606: child.setInTreeRecursively();
607: }
608: }
609:
610: /**
611: * This method changes old reference <code>reference</code>
612: * to new reference with referenceable object <code>subject</code>
613: */
614: @SuppressWarnings("unchecked")
615: void updateReference(Reference reference, BpelReferenceable subject) {
616: getAttributeAccess().updateReference(reference, subject);
617: }
618:
619: void handleAttributeChange(Node oldAttr, Node newAttr) {
620: getAttributeAccess().handleAttributeChange(oldAttr, newAttr);
621: }
622:
623: void setUID(UniqueId id) {
624: myUid = id;
625: }
626:
627: Map<Object, Object> getCookies() {
628: return myCookies;
629: }
630:
631: void setCookies(Map<Object, Object> cookieSet) {
632: myCookies = cookieSet;
633: }
634:
635: final boolean isInTree() {
636: /*Element element = getPeer();
637: assert element instanceof org.netbeans.modules.xml.xdm.nodes.Element;
638:
639: return ((org.netbeans.modules.xml.xdm.nodes.Element) element)
640: .isInTree();*/
641: return isInTree;
642: }
643:
644: final boolean isDeleted() {
645: return isDeleted;
646: }
647:
648: final void setDeleted() {
649: isDeleted = true;
650: }
651:
652: class IdMapKey {
653: };
654:
655: //#############################################################
656: //##
657: //## These are methods for firing event in model.
658: //##
659: //#############################################################
660: protected void postGlobalEvent(ChangeEvent event,
661: boolean propogateToModel) {
662: checkDeleted();
663:
664: try {
665: if (isInTree()) {
666: if (propogateToModel) {
667: getModel().fireChangeEvent(event);
668: }
669: } else {
670: getModel().getBuilder().fireChangeEvent(event);
671: }
672: } finally {
673: /*
674: * Real firing of event will be performed only after unlocking.
675: * So this is the safe to perfrom dispatching events by inner listeners
676: * becuase previous action just put event into the queue.
677: * But dispatching by inner listeners will be perfromed right now.
678: * So external listeners will be notified when inner already
679: * have ended its work.
680: */
681: getModel().postInnerEventNotify(event);
682: }
683: }
684:
685: protected void postGlobalEvent(ChangeEvent event) {
686: postGlobalEvent(event, true);
687: }
688:
689: private <T extends BpelEntity> CutEvent<T> preCut(T entity) {
690: CutEvent<T> event = new CutEvent<T>(entity);
691: try {
692: getModel().preInnerEventNotify(event);
693: } catch (VetoException e) {
694: assert false;
695: }
696: return event;
697: }
698:
699: final AttributeAccess getAttributeAccess() {
700: return myAccess;
701: }
702:
703: private <T extends BpelEntity> CopyEvent<T> preCopy(T entity) {
704: CopyEvent<T> event = new CopyEvent<T>(entity);
705: try {
706: getModel().preInnerEventNotify(event);
707: } catch (VetoException e) {
708: assert false;
709: }
710: return event;
711: }
712:
713: private <T extends BpelEntity> BuildEvent<T> preCreated(T entity) {
714: BuildEvent<T> event = new BuildEvent<T>(entity, getEntityName());
715: try {
716: getModel().preInnerEventNotify(event);
717: } catch (VetoException e) {
718: assert false;
719: }
720: return event;
721: }
722:
723: private <T extends BpelEntity> void postEvent(ChangeEvent event) {
724: getBpelModel().postInnerEventNotify(event);
725: }
726:
727: //#############################################################################
728: private static Element createNewComponent(BpelModelImpl model,
729: String tagName) {
730: return model.getDocument().createElementNS(
731: BpelEntity.BUSINESS_PROCESS_NS_URI, tagName);
732: }
733:
734: private static Element createNewComponent(BpelModelImpl model,
735: BpelElements elem) {
736: if (elem.getNamespace() == null) {
737: return createNewComponent(model, elem.getName());
738: } else {
739: return model.getDocument().createElementNS(
740: elem.getNamespace(), elem.getName());
741: }
742: }
743:
744: private static final byte INIT_COOKIE_CAPACITY = 8; // we don't need big capaicty. This is degree of 2.
745: private Map<Object, Object> myCookies = Collections
746: .synchronizedMap(new WeakHashMap<Object, Object>(
747: INIT_COOKIE_CAPACITY));
748: private UniqueId myUid;
749: private boolean isDeleted;
750: private BpelModelImpl myModel;
751: private AttributeAccess myAccess;
752: private boolean isInTree;
753: }
|