001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.addressing;
021:
022: import org.apache.axiom.om.OMAbstractFactory;
023: import org.apache.axiom.om.OMAttribute;
024: import org.apache.axiom.om.OMElement;
025: import org.apache.axiom.om.OMFactory;
026: import org.apache.axiom.om.OMNamespace;
027: import org.apache.axiom.om.OMNode;
028: import org.apache.axiom.om.impl.builder.StAXOMBuilder;
029: import org.apache.axiom.om.util.StAXUtils;
030: import org.apache.axiom.om.util.UUIDGenerator;
031: import org.apache.axis2.AxisFault;
032: import org.apache.axis2.util.ObjectStateUtils;
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035:
036: import javax.xml.namespace.QName;
037: import javax.xml.stream.XMLStreamReader;
038: import java.io.ByteArrayInputStream;
039: import java.io.ByteArrayOutputStream;
040: import java.io.IOException;
041: import java.io.Serializable;
042: import java.util.ArrayList;
043: import java.util.HashMap;
044: import java.util.Iterator;
045: import java.util.Map;
046:
047: /**
048: * Class EndpointReference
049: * This class models the WS-A EndpointReferenceType. But this can be used without any WS-A handlers as well
050: * Since the models for this in Submission and Final versions are different, lets make this to comply with
051: * WS-A Final version. So any information found with WS-A submission will be "pumped" in to this model.
052: */
053: public class EndpointReference implements Serializable {
054:
055: private static final long serialVersionUID = 5278892171162372439L;
056:
057: private static final Log log = LogFactory
058: .getLog(EndpointReference.class);
059:
060: private static final String myClassName = "EndpointReference";
061:
062: /**
063: * An ID which can be used to correlate operations on an instance of
064: * this object in the log files
065: */
066: private String logCorrelationIDString = null;
067:
068: /**
069: * <EndpointReference>
070: * <Address>xs:anyURI</Address>
071: * <ReferenceParameters>xs:any*</ReferenceParameters>
072: * <MetaData>xs:any*</MetaData>
073: * <!-- In addition to this, EPR can contain any number of OMElements -->
074: * </EndpointReference>
075: */
076:
077: private String name;
078: private String address;
079: private ArrayList addressAttributes;
080: private ArrayList metaData;
081: private ArrayList metaDataAttributes;
082: private Map referenceParameters;
083: private ArrayList extensibleElements;
084: private ArrayList attributes;
085:
086: /**
087: * @param address
088: */
089: public EndpointReference(String address) {
090: this .address = address;
091: }
092:
093: /**
094: * @param omElement
095: */
096: public void addReferenceParameter(OMElement omElement) {
097: if (omElement == null) {
098: return;
099: }
100: if (referenceParameters == null) {
101: referenceParameters = new HashMap();
102: }
103: referenceParameters.put(omElement.getQName(), omElement);
104: }
105:
106: /**
107: * @param qname
108: * @param value - the text of the OMElement. Remember that this is a convenient method for the user,
109: * which has limited capability. If you want more power use @See EndpointReference#addReferenceParameter(OMElement)
110: */
111: public void addReferenceParameter(QName qname, String value) {
112: if (qname == null) {
113: return;
114: }
115: OMElement omElement = OMAbstractFactory.getOMFactory()
116: .createOMElement(qname, null);
117: omElement.setText(value);
118: addReferenceParameter(omElement);
119: }
120:
121: /**
122: * This will return a Map of reference parameters with QName as the key and an OMElement
123: * as the value
124: *
125: * @return - map of the reference parameters, where the key is the QName of the reference parameter
126: * and the value is an OMElement
127: */
128: public Map getAllReferenceParameters() {
129: return referenceParameters;
130: }
131:
132: public String getAddress() {
133: return address;
134: }
135:
136: /**
137: * @param address - xs:anyURI
138: */
139: public void setAddress(String address) {
140: this .address = address;
141: }
142:
143: public ArrayList getAddressAttributes() {
144: return addressAttributes;
145: }
146:
147: public void setAddressAttributes(ArrayList al) {
148: addressAttributes = al;
149: }
150:
151: public ArrayList getMetadataAttributes() {
152: return metaDataAttributes;
153: }
154:
155: public void setMetadataAttributes(ArrayList al) {
156: metaDataAttributes = al;
157: }
158:
159: /**
160: * hasAnonymousAddress
161: *
162: * @return true if address is 'Anonymous URI'
163: */
164: public boolean hasAnonymousAddress() {
165: boolean result = (AddressingConstants.Final.WSA_ANONYMOUS_URL
166: .equals(address)
167: || AddressingConstants.Submission.WSA_ANONYMOUS_URL
168: .equals(address) ||
169:
170: //The following is added to give WS-RM anonymous a semantics to indicate
171: //that any response messages should be sent synchronously, using the
172: //transports back channel, as opposed to asynchronously. No other
173: //semantics normally associated with WS-Addressing anonymous values should
174: //be assumed, by it's presence here.
175: (address != null && address
176: .startsWith("http://docs.oasis-open.org/ws-rx/wsmc/200702/anonymous?id=")));
177: if (log.isTraceEnabled()) {
178: log.trace("hasAnonymousAddress: " + address
179: + " is Anonymous: " + result);
180: }
181: return result;
182: }
183:
184: /**
185: * hasNoneAddress
186: *
187: * @return true if the address is the 'None URI' from the final addressing spec.
188: */
189: public boolean hasNoneAddress() {
190: boolean result = AddressingConstants.Final.WSA_NONE_URI
191: .equals(address);
192: if (log.isTraceEnabled()) {
193: log.trace("hasNoneAddress: " + address + " is None: "
194: + result);
195: }
196: return result;
197: }
198:
199: /**
200: * @param localName
201: * @param ns
202: * @param value
203: */
204: public void addAttribute(String localName, OMNamespace ns,
205: String value) {
206: if (attributes == null) {
207: attributes = new ArrayList();
208: }
209: attributes.add(OMAbstractFactory.getOMFactory()
210: .createOMAttribute(localName, ns, value));
211: }
212:
213: public ArrayList getAttributes() {
214: return attributes;
215: }
216:
217: /**
218: * @param omAttribute
219: */
220: public void addAttribute(OMAttribute omAttribute) {
221: if (attributes == null) {
222: attributes = new ArrayList();
223: }
224: attributes.add(omAttribute);
225: }
226:
227: public ArrayList getExtensibleElements() {
228: return extensibleElements;
229: }
230:
231: /**
232: * {any}
233: *
234: * @param extensibleElements
235: */
236: public void setExtensibleElements(ArrayList extensibleElements) {
237: this .extensibleElements = extensibleElements;
238: }
239:
240: public void addExtensibleElement(OMElement extensibleElement) {
241: if (extensibleElement != null) {
242: if (this .extensibleElements == null) {
243: this .extensibleElements = new ArrayList();
244: }
245: this .extensibleElements.add(extensibleElement);
246: }
247: }
248:
249: public ArrayList getMetaData() {
250: return metaData;
251: }
252:
253: public void addMetaData(OMNode metaData) {
254: if (metaData != null) {
255: if (this .metaData == null) {
256: this .metaData = new ArrayList();
257: }
258: this .metaData.add(metaData);
259: }
260:
261: }
262:
263: /**
264: * @deprecated
265: */
266: public String getName() {
267: return name;
268: }
269:
270: /**
271: * @param name
272: * @deprecated
273: */
274: public void setName(String name) {
275: this .name = name;
276: }
277:
278: /**
279: * Set a Map with QName as the key and an OMElement
280: * as the value
281: *
282: * @param referenceParameters
283: */
284: public void setReferenceParameters(Map referenceParameters) {
285: this .referenceParameters = referenceParameters;
286: }
287:
288: /*
289: * (non-Javadoc)
290: * @see java.lang.Object#toString()
291: */
292: public String toString() {
293: StringBuffer buffer = new StringBuffer("Address: " + address);
294:
295: if (addressAttributes != null) {
296: buffer.append(", Address Attributes: ").append(
297: addressAttributes);
298: }
299:
300: if (metaData != null) {
301: buffer.append(", Metadata: ").append(metaData);
302: }
303:
304: if (referenceParameters != null) {
305: buffer.append(", Reference Parameters: ").append(
306: referenceParameters);
307: }
308:
309: if (extensibleElements != null) {
310: buffer.append(", Extensibility elements: ").append(
311: extensibleElements);
312: }
313:
314: if (attributes != null) {
315: buffer.append(", Attributes: ").append(attributes);
316: }
317:
318: return buffer.toString();
319: }
320:
321: /**
322: * @param eprOMElement
323: * @deprecated use {@link EndpointReferenceHelper#fromOM(OMElement)} instead.
324: */
325: public void fromOM(OMElement eprOMElement) {
326: OMElement addressElement = eprOMElement
327: .getFirstChildWithName(new QName("Address"));
328: setAddress(addressElement.getText());
329: Iterator allAddrAttributes = addressElement.getAllAttributes();
330: if (addressAttributes == null) {
331: addressAttributes = new ArrayList();
332: }
333:
334: while (allAddrAttributes.hasNext()) {
335: OMAttribute attribute = (OMAttribute) allAddrAttributes
336: .next();
337: addressAttributes.add(attribute);
338: }
339:
340: OMElement refParamElement = eprOMElement
341: .getFirstChildWithName(new QName(
342: AddressingConstants.EPR_REFERENCE_PARAMETERS));
343:
344: if (refParamElement != null) {
345: Iterator refParams = refParamElement.getChildElements();
346: while (refParams.hasNext()) {
347: OMElement omElement = (OMElement) refParams.next();
348: addReferenceParameter(omElement);
349: }
350: }
351:
352: OMElement metaDataElement = eprOMElement
353: .getFirstChildWithName(new QName(
354: AddressingConstants.Final.WSA_METADATA));
355: if (metaDataElement != null) {
356: Iterator children = metaDataElement.getChildren();
357: while (children.hasNext()) {
358: OMNode omNode = (OMNode) children.next();
359: addMetaData(omNode);
360: }
361: }
362:
363: setName(eprOMElement.getLocalName());
364:
365: Iterator allAttributes = eprOMElement.getAllAttributes();
366: if (attributes == null) {
367: attributes = new ArrayList();
368: }
369:
370: while (allAttributes.hasNext()) {
371: OMAttribute attribute = (OMAttribute) allAttributes.next();
372: attributes.add(attribute);
373: }
374:
375: Iterator childElements = eprOMElement.getChildElements();
376: while (childElements.hasNext()) {
377: OMElement eprChildElement = (OMElement) childElements
378: .next();
379: String localName = eprChildElement.getLocalName();
380: if (!localName.equals("Address")
381: && !localName
382: .equals(AddressingConstants.EPR_REFERENCE_PARAMETERS)
383: && !localName
384: .equals(AddressingConstants.Final.WSA_METADATA)) {
385: addExtensibleElement(eprChildElement);
386: }
387: }
388: }
389:
390: /**
391: * @param nsurl
392: * @param localName
393: * @param prefix
394: * @throws AxisFault
395: * @deprecated use {@link EndpointReferenceHelper#toOM(EndpointReference, QName, String)} instead.
396: */
397: public OMElement toOM(String nsurl, String localName, String prefix)
398: throws AxisFault {
399: OMFactory fac = OMAbstractFactory.getOMFactory();
400: if (prefix != null) {
401: OMNamespace wrapNs = fac.createOMNamespace(nsurl, prefix);
402: OMElement epr = fac.createOMElement(localName, wrapNs);
403: OMNamespace wsaNS = fac.createOMNamespace(
404: AddressingConstants.Final.WSA_NAMESPACE,
405: AddressingConstants.WSA_DEFAULT_PREFIX);
406: OMElement addressE = fac.createOMElement(
407: AddressingConstants.EPR_ADDRESS, wsaNS, epr);
408: addressE.setText(address);
409:
410: if (addressAttributes != null) {
411: Iterator attrIter = addressAttributes.iterator();
412: while (attrIter.hasNext()) {
413: OMAttribute omAttributes = (OMAttribute) attrIter
414: .next();
415: addressE.addAttribute(omAttributes);
416: }
417: }
418:
419: if (this .metaData != null) {
420: OMElement metadataE = fac.createOMElement(
421: AddressingConstants.Final.WSA_METADATA, wsaNS,
422: epr);
423: Iterator metadata = this .metaData.iterator();
424: while (metadata.hasNext()) {
425: metadataE.addChild((OMNode) metadata.next());
426: }
427: }
428:
429: if (this .referenceParameters != null) {
430: OMElement refParameterElement = fac.createOMElement(
431: AddressingConstants.EPR_REFERENCE_PARAMETERS,
432: wsaNS, epr);
433: Iterator refParms = referenceParameters.values()
434: .iterator();
435: while (refParms.hasNext()) {
436: refParameterElement.addChild((OMNode) refParms
437: .next());
438: }
439: }
440:
441: if (attributes != null) {
442: Iterator attrIter = attributes.iterator();
443: while (attrIter.hasNext()) {
444: OMAttribute omAttributes = (OMAttribute) attrIter
445: .next();
446: epr.addAttribute(omAttributes);
447: }
448: }
449:
450: // add xs:any
451: ArrayList omElements = extensibleElements;
452: if (omElements != null) {
453: for (int i = 0; i < omElements.size(); i++) {
454: epr.addChild((OMElement) omElements.get(i));
455: }
456: }
457:
458: return epr;
459: } else {
460: throw new AxisFault("prefix must be specified");
461: }
462: }
463:
464: /**
465: * Compares key parts of the state from the current instance of
466: * this class with the specified instance to see if they are
467: * equivalent.
468: * <p/>
469: * This differs from the java.lang.Object.equals() method in
470: * that the equals() method generally looks at both the
471: * object identity (location in memory) and the object state
472: * (data).
473: * <p/>
474: *
475: * @param epr The object to compare with
476: * @return TRUE if this object is equivalent with the specified object
477: * that is, key fields match
478: * FALSE, otherwise
479: */
480: public boolean isEquivalent(EndpointReference epr) {
481: // NOTE: the input object is expected to exist (ie, be non-null)
482:
483: if ((this .name != null) && (epr.getName() != null)) {
484: if (!this .name.equals(epr.getName())) {
485: return false;
486: }
487: } else if ((this .name == null) && (epr.getName() == null)) {
488: // continue
489: } else {
490: // mismatch
491: return false;
492: }
493:
494: if ((this .address != null) && (epr.getAddress() != null)) {
495: if (!this .address.equals(epr.getAddress())) {
496: return false;
497: }
498: } else if ((this .address == null) && (epr.getAddress() == null)) {
499: // continue
500: } else {
501: // mismatch
502: return false;
503: }
504:
505: // TODO: is a strict test ok to use?
506:
507: ArrayList eprMetaData = epr.getMetaData();
508:
509: if ((this .metaData != null) && (eprMetaData != null)) {
510: if (!this .metaData.equals(eprMetaData)) {
511: // This is a strict test
512: // Returns true if and only if the specified object
513: // is also a list, both lists have the same size, and
514: // all corresponding pairs of elements in the two lists
515: // are equal, ie, two lists are defined to be equal if
516: // they contain the same elements in the same order.
517:
518: return false;
519: }
520: } else if ((this .metaData == null) && (eprMetaData == null)) {
521: // keep going
522: } else {
523: // one of the lists is null
524: return false;
525: }
526:
527: ArrayList eprExtensibleElements = epr.getExtensibleElements();
528:
529: if ((this .extensibleElements != null)
530: && (eprExtensibleElements != null)) {
531: if (!this .extensibleElements.equals(eprExtensibleElements)) {
532: // This is a strict test
533: // Returns true if and only if the specified object
534: // is also a list, both lists have the same size, and
535: // all corresponding pairs of elements in the two lists
536: // are equal, ie, two lists are defined to be equal if
537: // they contain the same elements in the same order.
538:
539: return false;
540: }
541: } else if ((this .extensibleElements == null)
542: && (eprExtensibleElements == null)) {
543: // keep going
544: } else {
545: // one of the lists is null
546: return false;
547: }
548:
549: ArrayList eprAttributes = epr.getAttributes();
550:
551: if ((this .attributes != null) && (eprAttributes != null)) {
552: if (!this .attributes.equals(eprAttributes)) {
553: // This is a strict test
554: // Returns true if and only if the specified object
555: // is also a list, both lists have the same size, and
556: // all corresponding pairs of elements in the two lists
557: // are equal, ie, two lists are defined to be equal if
558: // they contain the same elements in the same order.
559:
560: return false;
561: }
562: } else if ((this .attributes == null) && (eprAttributes == null)) {
563: // keep going
564: } else {
565: // one of the lists is null
566: return false;
567: }
568:
569: // TODO: check the Map referenceParameters for equivalency
570:
571: return true;
572: }
573:
574: //REVIEW: The following code is rather heavyweight, because we have to build
575: // the OM tree -- it would probably be better to have two serialization/deserialization
576: // paths and therefore, for trivial EPRs, store a smaller amount of info
577:
578: /**
579: * Write the EPR to the specified OutputStream. Because of potential
580: * OMElements/Attributes, we need to actually serialize the OM structures
581: * (at least in some cases.)
582: */
583: private void writeObject(java.io.ObjectOutputStream out)
584: throws IOException {
585: String logCorrelationIDString = getLogCorrelationIDString();
586:
587: // String object id
588: ObjectStateUtils.writeString(out, logCorrelationIDString,
589: logCorrelationIDString + ".logCorrelationIDString");
590:
591: OMElement om = EndpointReferenceHelper.toOM(OMAbstractFactory
592: .getOMFactory(), this , new QName("urn:axis2", "omepr",
593: "ser"), AddressingConstants.Final.WSA_NAMESPACE);
594:
595: ByteArrayOutputStream baos = new ByteArrayOutputStream();
596:
597: try {
598: om.serialize(baos);
599: } catch (Exception e) {
600: IOException ioe = new IOException(
601: "Unable to serialize the EndpointReference with logCorrelationID ["
602: + logCorrelationIDString + "]");
603: ioe.initCause(e);
604:
605: if (log.isDebugEnabled()) {
606: log
607: .debug(
608: "writeObject(): Unable to serialize the EPR with logCorrelationID ["
609: + logCorrelationIDString
610: + "] original error ["
611: + e.getClass().getName()
612: + "] message ["
613: + e.getMessage() + "]", e);
614: }
615:
616: throw ioe;
617: }
618:
619: out.writeInt(baos.size());
620: out.write(baos.toByteArray());
621:
622: if (log.isDebugEnabled()) {
623: byte[] buffer = baos.toByteArray();
624: String content = new String(buffer);
625:
626: log.debug("writeObject(): EPR logCorrelationID ["
627: + logCorrelationIDString + "] "
628: + " EPR content size [" + baos.size() + "]"
629: + " EPR content [" + content + "]");
630: }
631:
632: }
633:
634: /**
635: * Read the EPR to the specified InputStream.
636: */
637: private void readObject(java.io.ObjectInputStream in)
638: throws IOException, ClassNotFoundException {
639:
640: // String object id
641: logCorrelationIDString = ObjectStateUtils.readString(in,
642: "EndpointReference.logCorrelationIDString");
643:
644: int numBytes = in.readInt();
645:
646: byte[] serBytes = new byte[numBytes];
647:
648: // read the data from the input stream
649:
650: int bytesRead = 0;
651: int numberOfBytesLastRead;
652:
653: while (bytesRead < numBytes) {
654: numberOfBytesLastRead = in.read(serBytes, bytesRead,
655: numBytes - bytesRead);
656:
657: if (numberOfBytesLastRead == -1) {
658: // TODO: What should we do if the reconstitution fails?
659: // For now, log the event and throw an exception
660: if (log.isDebugEnabled()) {
661: log
662: .debug("readObject(): EPR logCorrelationID ["
663: + logCorrelationIDString
664: + "] "
665: + " ***WARNING*** unexpected end to data: data read from input stream ["
666: + bytesRead
667: + "] expected data size ["
668: + numBytes + "]");
669: }
670:
671: IOException ioe = new IOException(
672: "Unable to deserialize the EndpointReference with logCorrelationID ["
673: + logCorrelationIDString
674: + "]"
675: + " Cause: Unexpected end to data from input stream");
676:
677: throw ioe;
678: }
679:
680: bytesRead += numberOfBytesLastRead;
681: }
682:
683: if (bytesRead == 0) {
684: IOException ioe = new IOException(
685: "Unable to deserialize the EndpointReference with logCorrelationID ["
686: + logCorrelationIDString + "]"
687: + " Cause: No data from input stream");
688:
689: throw ioe;
690: }
691:
692: ByteArrayInputStream bais = new ByteArrayInputStream(serBytes);
693:
694: if (log.isDebugEnabled()) {
695: String content = new String(serBytes);
696:
697: log.debug("readObject(): EPR logCorrelationID ["
698: + logCorrelationIDString + "] "
699: + " expected content size [" + numBytes + "]"
700: + " content size [" + content.length() + "]"
701: + " EPR buffered content [" + content + "]");
702: }
703:
704: XMLStreamReader xmlReader = null;
705:
706: try {
707: xmlReader = StAXUtils.createXMLStreamReader(bais);
708: StAXOMBuilder builder = new StAXOMBuilder(xmlReader);
709: OMElement om = builder.getDocumentElement();
710:
711: // expand the OM so we can close the stream reader
712: om.build();
713:
714: // trace point
715: if (log.isDebugEnabled()) {
716: log.debug(myClassName + ":readObject(): " + " EPR ["
717: + logCorrelationIDString + "]"
718: + " EPR OM content [" + om.toString() + "]");
719: }
720:
721: EndpointReferenceHelper.fromOM(this , om,
722: AddressingConstants.Final.WSA_NAMESPACE);
723:
724: } catch (Exception e) {
725: IOException ioe = new IOException(
726: "Unable to deserialize the EndpointReference with logCorrelationID ["
727: + logCorrelationIDString + "]");
728: ioe.initCause(e);
729:
730: if (log.isDebugEnabled()) {
731: log
732: .debug(
733: "readObject(): Unable to deserialize the EPR with logCorrelationID ["
734: + logCorrelationIDString
735: + "] original error ["
736: + e.getClass().getName()
737: + "] message ["
738: + e.getMessage() + "]", e);
739: }
740:
741: throw ioe;
742:
743: } finally {
744: // Make sure that the reader is properly closed
745: // Note that closing a ByteArrayInputStream has no effect
746:
747: if (xmlReader != null) {
748: try {
749: xmlReader.close();
750: } catch (Exception e2) {
751: IOException ioe2 = new IOException(
752: "Unable to close the XMLStreamReader for the EndpointReference with logCorrelationID ["
753: + logCorrelationIDString + "]");
754: ioe2.initCause(e2);
755:
756: if (log.isDebugEnabled()) {
757: log
758: .debug(
759: "readObject(): Unable to close the XMLStreamReader for the EPR with logCorrelationID ["
760: + logCorrelationIDString
761: + "] original error ["
762: + e2.getClass()
763: .getName()
764: + "] message ["
765: + e2.getMessage() + "]",
766: e2);
767: }
768:
769: throw ioe2;
770: }
771: }
772: }
773: }
774:
775: /**
776: * Get the ID associated with this object instance.
777: *
778: * @return A string that can be output to a log file as an identifier
779: * for this object instance. It is suitable for matching related log
780: * entries.
781: */
782: public String getLogCorrelationIDString() {
783: if (logCorrelationIDString == null) {
784: logCorrelationIDString = myClassName + "@"
785: + UUIDGenerator.getUUID();
786: }
787: return logCorrelationIDString;
788: }
789:
790: }
|