001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.jbi.messaging;
018
019 import java.io.Externalizable;
020 import java.io.IOException;
021 import java.io.ObjectInput;
022 import java.io.ObjectOutput;
023 import java.net.URI;
024 import java.util.Comparator;
025 import java.util.Set;
026
027 import javax.jbi.messaging.ExchangeStatus;
028 import javax.jbi.messaging.Fault;
029 import javax.jbi.messaging.MessageExchange;
030 import javax.jbi.messaging.MessagingException;
031 import javax.jbi.messaging.NormalizedMessage;
032 import javax.jbi.servicedesc.ServiceEndpoint;
033 import javax.transaction.Transaction;
034 import javax.xml.namespace.QName;
035 import javax.xml.transform.dom.DOMSource;
036
037 import org.w3c.dom.Node;
038
039 import org.apache.commons.logging.Log;
040 import org.apache.commons.logging.LogFactory;
041 import org.apache.servicemix.JbiConstants;
042 import org.apache.servicemix.jbi.container.ActivationSpec;
043 import org.apache.servicemix.jbi.framework.ComponentContextImpl;
044 import org.apache.servicemix.jbi.framework.ComponentNameSpace;
045 import org.apache.servicemix.jbi.jaxp.SourceTransformer;
046
047 /**
048 * A simple message exchange declaration. This is partial, just giving us enough
049 * ME function for the doodle. This doesn't add anything new to the current
050 * MessageExchange definition.
051 *
052 * @version $Revision: 564607 $
053 */
054 public abstract class MessageExchangeImpl implements MessageExchange, Externalizable {
055
056 public static final String IN = "in";
057
058 public static final String OUT = "out";
059
060 public static final String FAULT = "fault";
061
062 public static final int MAX_MSG_DISPLAY_SIZE = 1500;
063
064 public static final boolean PRESERVE_CONTENT = Boolean.getBoolean("org.apache.servicemix.preserveContent");
065
066 public static final int SYNC_STATE_ASYNC = 0;
067
068 public static final int SYNC_STATE_SYNC_SENT = 1;
069
070 public static final int SYNC_STATE_SYNC_RECEIVED = 2;
071
072 /**
073 * Exchange is not transactional
074 */
075 public static final int TX_STATE_NONE = 0;
076
077 /**
078 * Exchange has been enlisted in the current transaction. This means that
079 * the transaction must be commited for the exchange to be delivered.
080 */
081 public static final int TX_STATE_ENLISTED = 1;
082
083 /**
084 * Transaction is being conveyed by the exchange. The transaction context
085 * will be given to the target component.
086 */
087 public static final int TX_STATE_CONVEYED = 2;
088
089 protected static final int CAN_SET_IN_MSG = 0x00000001;
090
091 protected static final int CAN_SET_OUT_MSG = 0x00000002;
092
093 protected static final int CAN_SET_FAULT_MSG = 0x00000004;
094
095 protected static final int CAN_PROVIDER = 0x00000008;
096
097 protected static final int CAN_CONSUMER = 0x00000000;
098
099 protected static final int CAN_SEND = 0x00000010;
100
101 protected static final int CAN_STATUS_ACTIVE = 0x00000040;
102
103 protected static final int CAN_STATUS_DONE = 0x00000080;
104
105 protected static final int CAN_STATUS_ERROR = 0x00000100;
106
107 protected static final int CAN_OWNER = 0x00000200;
108
109 protected static final int STATES_CANS = 0;
110
111 protected static final int STATES_NEXT_OUT = 1;
112
113 protected static final int STATES_NEXT_FAULT = 2;
114
115 protected static final int STATES_NEXT_ERROR = 3;
116
117 protected static final int STATES_NEXT_DONE = 4;
118
119 private static final long serialVersionUID = -3639175136897005605L;
120
121 private static final Log LOG = LogFactory.getLog(MessageExchangeImpl.class);
122
123 protected ComponentContextImpl sourceContext;
124
125 protected ExchangePacket packet;
126
127 protected PojoMarshaler marshaler;
128
129 protected int state;
130
131 protected int syncState = SYNC_STATE_ASYNC;
132
133 protected int txState = TX_STATE_NONE;
134
135 protected int[][] states;
136
137 protected MessageExchangeImpl mirror;
138
139 protected transient boolean pushDeliver;
140
141 protected transient Object txLock;
142
143 protected transient String key;
144
145 /**
146 * Constructor
147 *
148 * @param exchangeId
149 * @param pattern
150 */
151 public MessageExchangeImpl(String exchangeId, URI pattern, int[][] states) {
152 this.states = states;
153 this.packet = new ExchangePacket();
154 this.packet.setExchangeId(exchangeId);
155 this.packet.setPattern(pattern);
156 }
157
158 protected MessageExchangeImpl(ExchangePacket packet, int[][] states) {
159 this.states = states;
160 this.packet = packet;
161 }
162
163 protected MessageExchangeImpl() {
164 }
165
166 protected void copyFrom(MessageExchangeImpl me) {
167 if (this != me) {
168 this.packet = me.packet;
169 this.state = me.state;
170 this.mirror.packet = me.packet;
171 this.mirror.state = me.mirror.state;
172 }
173 }
174
175 protected boolean can(int c) {
176 return (this.states[state][STATES_CANS] & c) == c;
177 }
178
179 /**
180 * Returns the activation spec that was provided when the component was
181 * registered
182 *
183 * @return the spec
184 */
185 public ActivationSpec getActivationSpec() {
186 if (sourceContext != null) {
187 return sourceContext.getActivationSpec();
188 }
189 return null;
190 }
191
192 /**
193 * Returns the context which created the message exchange which can then be
194 * used for routing
195 *
196 * @return the context
197 */
198 public ComponentContextImpl getSourceContext() {
199 return sourceContext;
200 }
201
202 /**
203 * Set the context
204 *
205 * @param sourceContext
206 */
207 public void setSourceContext(ComponentContextImpl sourceContext) {
208 this.sourceContext = sourceContext;
209 this.mirror.sourceContext = sourceContext;
210 }
211
212 /**
213 * @return the packet
214 */
215 public ExchangePacket getPacket() {
216 return packet;
217 }
218
219 /**
220 * @return URI of pattern exchange
221 */
222 public URI getPattern() {
223 return packet.getPattern();
224 }
225
226 /**
227 * @return the exchange Id
228 */
229 public String getExchangeId() {
230 return packet.getExchangeId();
231 }
232
233 /**
234 * @return the processing status of the exchange
235 */
236 public ExchangeStatus getStatus() {
237 if (this.packet.isAborted()) {
238 return ExchangeStatus.ERROR;
239 }
240 return this.packet.getStatus();
241 }
242
243 /**
244 * set the processing status
245 *
246 * @param exchangeStatus
247 * @throws MessagingException
248 */
249 public void setStatus(ExchangeStatus exchangeStatus) throws MessagingException {
250 if (!can(CAN_OWNER)) {
251 throw new IllegalStateException("component is not owner");
252 }
253 this.packet.setStatus(exchangeStatus);
254
255 }
256
257 /**
258 * set the source of a failure
259 *
260 * @param exception
261 */
262 public void setError(Exception exception) {
263 if (!can(CAN_OWNER)) {
264 throw new IllegalStateException("component is not owner when trying to set error: " + exception, exception);
265 }
266 this.packet.setError(exception);
267 }
268
269 /**
270 * @return the exception describing a processing error
271 */
272 public Exception getError() {
273 return packet.getError();
274 }
275
276 /**
277 * @return the fault message for an exchange
278 */
279 public Fault getFault() {
280 return packet.getFault();
281 }
282
283 /**
284 * set the fault message for the exchange
285 *
286 * @param fault
287 * @throws MessagingException
288 */
289 public void setFault(Fault fault) throws MessagingException {
290 setMessage(fault, FAULT);
291 }
292
293 /**
294 * @return a new message
295 * @throws MessagingException
296 */
297 public NormalizedMessage createMessage() throws MessagingException {
298 return new NormalizedMessageImpl(this);
299 }
300
301 /**
302 * factory method for fault objects
303 *
304 * @return a new fault
305 * @throws MessagingException
306 */
307 public Fault createFault() throws MessagingException {
308 return new FaultImpl();
309 }
310
311 /**
312 * get a NormalizedMessage based on the message reference
313 *
314 * @param name
315 * @return a NormalizedMessage
316 */
317 public NormalizedMessage getMessage(String name) {
318 if (IN.equals(name)) {
319 return packet.getIn();
320 } else if (OUT.equals(name)) {
321 return packet.getOut();
322 } else if (FAULT.equals(name)) {
323 return packet.getFault();
324 } else {
325 return null;
326 }
327 }
328
329 /**
330 * set a NormalizedMessage with a named reference
331 *
332 * @param message
333 * @param name
334 * @throws MessagingException
335 */
336 public void setMessage(NormalizedMessage message, String name) throws MessagingException {
337 if (!can(CAN_OWNER)) {
338 throw new IllegalStateException("component is not owner");
339 }
340 if (message == null) {
341 throw new IllegalArgumentException("message should not be null");
342 }
343 if (name == null) {
344 throw new IllegalArgumentException("name should not be null");
345 }
346 if (IN.equalsIgnoreCase(name)) {
347 if (!can(CAN_SET_IN_MSG)) {
348 throw new MessagingException("In not supported");
349 }
350 if (packet.getIn() != null) {
351 throw new MessagingException("In message is already set");
352 }
353 ((NormalizedMessageImpl) message).exchange = this;
354 packet.setIn((NormalizedMessageImpl) message);
355 } else if (OUT.equalsIgnoreCase(name)) {
356 if (!can(CAN_SET_OUT_MSG)) {
357 throw new MessagingException("Out not supported");
358 }
359 if (packet.getOut() != null) {
360 throw new MessagingException("Out message is already set");
361 }
362 ((NormalizedMessageImpl) message).exchange = this;
363 packet.setOut((NormalizedMessageImpl) message);
364 } else if (FAULT.equalsIgnoreCase(name)) {
365 if (!can(CAN_SET_FAULT_MSG)) {
366 throw new MessagingException("Fault not supported");
367 }
368 if (!(message instanceof Fault)) {
369 throw new MessagingException("Setting fault, but message is not a fault");
370 }
371 if (packet.getFault() != null) {
372 throw new MessagingException("Fault message is already set");
373 }
374 ((NormalizedMessageImpl) message).exchange = this;
375 packet.setFault((FaultImpl) message);
376 } else {
377 throw new MessagingException("Message name must be in, out or fault");
378 }
379 }
380
381 /**
382 * @param name
383 * @return the property from the exchange
384 */
385 public Object getProperty(String name) {
386 if (JTA_TRANSACTION_PROPERTY_NAME.equals(name)) {
387 return packet.getTransactionContext();
388 } else if (JbiConstants.PERSISTENT_PROPERTY_NAME.equals(name)) {
389 return packet.getPersistent();
390 } else {
391 return packet.getProperty(name);
392 }
393 }
394
395 /**
396 * set a named property on the exchange
397 *
398 * @param name
399 * @param value
400 */
401 public void setProperty(String name, Object value) {
402 if (!can(CAN_OWNER)) {
403 throw new IllegalStateException("component is not owner");
404 }
405 if (name == null) {
406 throw new IllegalArgumentException("name should not be null");
407 }
408 if (JTA_TRANSACTION_PROPERTY_NAME.equals(name)) {
409 packet.setTransactionContext((Transaction) value);
410 } else if (JbiConstants.PERSISTENT_PROPERTY_NAME.equals(name)) {
411 packet.setPersistent((Boolean) value);
412 } else {
413 packet.setProperty(name, value);
414 }
415 }
416
417 /**
418 * @return property names
419 */
420 public Set getPropertyNames() {
421 return packet.getPropertyNames();
422 }
423
424 /**
425 * Set an endpoint
426 *
427 * @param endpoint
428 */
429 public void setEndpoint(ServiceEndpoint endpoint) {
430 packet.setEndpoint(endpoint);
431 }
432
433 /**
434 * set a service
435 *
436 * @param name
437 */
438 public void setService(QName name) {
439 packet.setServiceName(name);
440 }
441
442 /**
443 * set an operation
444 *
445 * @param name
446 */
447 public void setOperation(QName name) {
448 packet.setOperationName(name);
449 }
450
451 /**
452 * set an interface
453 *
454 * @param name
455 */
456 public void setInterfaceName(QName name) {
457 packet.setInterfaceName(name);
458 }
459
460 /**
461 * @return the endpoint
462 */
463 public ServiceEndpoint getEndpoint() {
464 return packet.getEndpoint();
465 }
466
467 /**
468 * @return the service
469 */
470 public QName getService() {
471 return packet.getServiceName();
472 }
473
474 /**
475 * @return the interface name
476 */
477 public QName getInterfaceName() {
478 return packet.getInterfaceName();
479 }
480
481 /**
482 * @return the operation
483 */
484 public QName getOperation() {
485 return packet.getOperationName();
486 }
487
488 /**
489 * @return the transaction context
490 */
491 public Transaction getTransactionContext() {
492 return packet.getTransactionContext();
493 }
494
495 /**
496 * set the transaction
497 *
498 * @param transaction
499 * @throws MessagingException
500 */
501 public void setTransactionContext(Transaction transaction) throws MessagingException {
502 packet.setTransactionContext(transaction);
503 }
504
505 /**
506 * @return true if transacted
507 */
508 public boolean isTransacted() {
509 return this.packet.getTransactionContext() != null;
510 }
511
512 /**
513 * @return the Role of this exchange
514 */
515 public Role getRole() {
516 return can(CAN_PROVIDER) ? Role.PROVIDER : Role.CONSUMER;
517 }
518
519 /**
520 * @return the in message
521 */
522 public NormalizedMessage getInMessage() {
523 return this.packet.getIn();
524 }
525
526 /**
527 * set the in message
528 *
529 * @param message
530 * @throws MessagingException
531 */
532 public void setInMessage(NormalizedMessage message) throws MessagingException {
533 setMessage(message, IN);
534 }
535
536 /**
537 * @return the out message
538 */
539 public NormalizedMessage getOutMessage() {
540 return getMessage(OUT);
541 }
542
543 /**
544 * set the out message
545 *
546 * @param message
547 * @throws MessagingException
548 */
549 public void setOutMessage(NormalizedMessage message) throws MessagingException {
550 setMessage(message, OUT);
551 }
552
553 /**
554 * @return Returns the sourceId.
555 */
556 public ComponentNameSpace getSourceId() {
557 return packet.getSourceId();
558 }
559
560 /**
561 * @param sourceId
562 * The sourceId to set.
563 */
564 public void setSourceId(ComponentNameSpace sourceId) {
565 packet.setSourceId(sourceId);
566 }
567
568 /**
569 * @return Returns the destinationId.
570 */
571 public ComponentNameSpace getDestinationId() {
572 return packet.getDestinationId();
573 }
574
575 /**
576 * @param destinationId
577 * The destinationId to set.
578 */
579 public void setDestinationId(ComponentNameSpace destinationId) {
580 packet.setDestinationId(destinationId);
581 }
582
583 public Boolean getPersistent() {
584 return packet.getPersistent();
585 }
586
587 public void setPersistent(Boolean persistent) {
588 packet.setPersistent(persistent);
589 }
590
591 public PojoMarshaler getMarshaler() {
592 if (marshaler == null) {
593 marshaler = new DefaultMarshaler();
594 }
595 return marshaler;
596 }
597
598 public void setMarshaler(PojoMarshaler marshaler) {
599 this.marshaler = marshaler;
600 }
601
602 public abstract void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
603
604 public void writeExternal(ObjectOutput out) throws IOException {
605 packet.writeExternal(out);
606 out.write(state);
607 out.write(mirror.state);
608 out.writeBoolean(can(CAN_PROVIDER));
609 }
610
611 public void handleSend(boolean sync) throws MessagingException {
612 // Check if send / sendSync is legal
613 if (!can(CAN_SEND)) {
614 throw new MessagingException("illegal call to send / sendSync");
615 }
616 if (sync && getStatus() != ExchangeStatus.ACTIVE) {
617 throw new MessagingException("illegal call to sendSync");
618 }
619 this.syncState = sync ? SYNC_STATE_SYNC_SENT : SYNC_STATE_ASYNC;
620 // Check status
621 ExchangeStatus status = getStatus();
622 if (status == ExchangeStatus.ACTIVE && !can(CAN_STATUS_ACTIVE)) {
623 throw new MessagingException("illegal exchange status: active");
624 }
625 if (status == ExchangeStatus.DONE && !can(CAN_STATUS_DONE)) {
626 throw new MessagingException("illegal exchange status: done");
627 }
628 if (status == ExchangeStatus.ERROR && !can(CAN_STATUS_ERROR)) {
629 throw new MessagingException("illegal exchange status: error");
630 }
631 // Check message
632 // Change state
633 if (status == ExchangeStatus.ACTIVE && packet.getFault() == null) {
634 this.state = this.states[this.state][STATES_NEXT_OUT];
635 } else if (status == ExchangeStatus.ACTIVE && packet.getFault() != null) {
636 this.state = this.states[this.state][STATES_NEXT_FAULT];
637 } else if (status == ExchangeStatus.ERROR) {
638 this.state = this.states[this.state][STATES_NEXT_ERROR];
639 } else if (status == ExchangeStatus.DONE) {
640 this.state = this.states[this.state][STATES_NEXT_DONE];
641 } else {
642 throw new IllegalStateException("unknown status");
643 }
644 if (this.state < 0 || this.state >= this.states.length) {
645 throw new IllegalStateException("next state is illegal");
646 }
647 }
648
649 public void handleAccept() throws MessagingException {
650 // Change state
651 ExchangeStatus status = getStatus();
652 int nextState;
653 if (status == ExchangeStatus.ACTIVE && packet.getFault() == null) {
654 nextState = this.states[this.state][STATES_NEXT_OUT];
655 } else if (status == ExchangeStatus.ACTIVE && packet.getFault() != null) {
656 nextState = this.states[this.state][STATES_NEXT_FAULT];
657 } else if (status == ExchangeStatus.ERROR) {
658 nextState = this.states[this.state][STATES_NEXT_ERROR];
659 } else if (status == ExchangeStatus.DONE) {
660 nextState = this.states[this.state][STATES_NEXT_DONE];
661 } else {
662 throw new IllegalStateException("unknown status");
663 }
664 if (nextState < 0 || nextState >= this.states.length) {
665 throw new IllegalStateException("next state is illegal");
666 }
667 this.state = nextState;
668 }
669
670 public MessageExchangeImpl getMirror() {
671 return mirror;
672 }
673
674 public int getSyncState() {
675 return syncState;
676 }
677
678 public void setSyncState(int syncState) {
679 this.syncState = syncState;
680 }
681
682 /**
683 * @return the txState
684 */
685 public int getTxState() {
686 return txState;
687 }
688
689 /**
690 * @param txState
691 * the txState to set
692 */
693 public void setTxState(int txState) {
694 this.txState = txState;
695 }
696
697 public boolean isPushDelivery() {
698 return this.pushDeliver;
699 }
700
701 public void setPushDeliver(boolean b) {
702 this.pushDeliver = true;
703 }
704
705 /**
706 * @return the txLock
707 */
708 public Object getTxLock() {
709 return txLock;
710 }
711
712 /**
713 * @param txLock
714 * the txLock to set
715 */
716 public void setTxLock(Object txLock) {
717 this.txLock = txLock;
718 }
719
720 public String toString() {
721 try {
722 StringBuffer sb = new StringBuffer();
723 String name = getClass().getName();
724 name = name.substring(name.lastIndexOf('.') + 1, name.length() - 4);
725 sb.append(name);
726 sb.append("[\n");
727 sb.append(" id: ").append(getExchangeId()).append('\n');
728 sb.append(" status: ").append(getStatus()).append('\n');
729 sb.append(" role: ").append(getRole() == Role.CONSUMER ? "consumer" : "provider").append('\n');
730 if (getInterfaceName() != null) {
731 sb.append(" interface: ").append(getInterfaceName()).append('\n');
732 }
733 if (getService() != null) {
734 sb.append(" service: ").append(getService()).append('\n');
735 }
736 if (getEndpoint() != null) {
737 sb.append(" endpoint: ").append(getEndpoint().getEndpointName()).append('\n');
738 }
739 if (getOperation() != null) {
740 sb.append(" operation: ").append(getOperation()).append('\n');
741 }
742 SourceTransformer st = new SourceTransformer();
743 display("in", sb, st);
744 display("out", sb, st);
745 display("fault", sb, st);
746 if (getError() != null) {
747 sb.append(" error: ");
748 sb.append(getError());
749 sb.append('\n');
750 }
751 sb.append("]");
752 return sb.toString();
753 } catch (Exception e) {
754 LOG.trace("Error caught in toString", e);
755 return super.toString();
756 }
757 }
758
759 private void display(String msg, StringBuffer sb, SourceTransformer st) {
760 if (getMessage(msg) != null) {
761 sb.append(" ").append(msg).append(": ");
762 try {
763 if (getMessage(msg).getContent() != null) {
764 if (PRESERVE_CONTENT) {
765 sb.append(getMessage(msg).getContent().getClass());
766 } else {
767 Node node = st.toDOMNode(getMessage(msg).getContent());
768 getMessage(msg).setContent(new DOMSource(node));
769 String str = st.toString(node);
770 if (str.length() > MAX_MSG_DISPLAY_SIZE) {
771 sb.append(str.substring(0, MAX_MSG_DISPLAY_SIZE)).append("...");
772 } else {
773 sb.append(str);
774 }
775 }
776 } else {
777 sb.append("null");
778 }
779 } catch (Exception e) {
780 sb.append("Unable to display: ").append(e);
781 }
782 sb.append('\n');
783 }
784 }
785
786 /**
787 * Compute a unique key for this exchange proxy. It has to be different for
788 * the two sides of the exchange, so we include the role + the exchange id.
789 * Obviously, it works, because the role never change for a given proxy.
790 *
791 * @return
792 */
793 public String getKey() {
794 if (key == null) {
795 key = (getRole() == Role.CONSUMER ? "consumer:" : "provider:") + getExchangeId();
796 }
797 return key;
798 }
799
800 /**
801 * Comparator that can be used to sort exchanges according to their "age" in
802 * their processing: i.e.: a newly created exchange will be more than a DONE
803 * exchange ... If the arguments are not instances of MessageExchangeImpl,
804 * returns 0.
805 */
806 public static class AgeComparator implements Comparator<MessageExchangeImpl> {
807 public int compare(MessageExchangeImpl m0, MessageExchangeImpl m1) {
808 int i0 = (m0.state * 4) / (m0.states.length - 1);
809 int i1 = (m1.state * 4) / (m1.states.length - 1);
810 if (i0 < i1) {
811 return +1;
812 } else if (i0 == i1) {
813 return 0;
814 } else {
815 return -1;
816 }
817 }
818 }
819 }