]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/cbjx/CbJxTransport.java
remove mediastreamer2 and add it as a submodule instead.
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / impl / src / net / jxta / impl / endpoint / cbjx / CbJxTransport.java
1 /*
2  * Copyright (c) 2001-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
12  *  2. Redistributions in binary form must reproduce the above copyright notice, 
13  *     this list of conditions and the following disclaimer in the documentation 
14  *     and/or other materials provided with the distribution.
15  *  
16  *  3. The end-user documentation included with the redistribution, if any, must 
17  *     include the following acknowledgment: "This product includes software 
18  *     developed by Sun Microsystems, Inc. for JXTA(TM) technology." 
19  *     Alternately, this acknowledgment may appear in the software itself, if 
20  *     and wherever such third-party acknowledgments normally appear.
21  *  
22  *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must 
23  *     not be used to endorse or promote products derived from this software 
24  *     without prior written permission. For written permission, please contact 
25  *     Project JXTA at http://www.jxta.org.
26  *  
27  *  5. Products derived from this software may not be called "JXTA", nor may 
28  *     "JXTA" appear in their name, without prior written permission of Sun.
29  *  
30  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
32  *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN 
33  *  MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
35  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
36  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
37  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
38  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
39  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
44  *  Please see the license information page at :
45  *  <http://www.jxta.org/project/www/license.html> for instructions on use of 
46  *  the license in source files.
47  *  
48  *  ====================================================================
49  *  
50  *  This software consists of voluntary contributions made by many individuals 
51  *  on behalf of Project JXTA. For more information on Project JXTA, please see 
52  *  http://www.jxta.org.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56
57 package net.jxta.impl.endpoint.cbjx;
58
59
60 import net.jxta.document.Advertisement;
61 import net.jxta.document.MimeMediaType;
62 import net.jxta.document.TextDocument;
63 import net.jxta.endpoint.ByteArrayMessageElement;
64 import net.jxta.endpoint.EndpointAddress;
65 import net.jxta.endpoint.EndpointListener;
66 import net.jxta.endpoint.EndpointService;
67 import net.jxta.endpoint.Message;
68 import net.jxta.endpoint.MessageElement;
69 import net.jxta.endpoint.MessageFilterListener;
70 import net.jxta.endpoint.MessageReceiver;
71 import net.jxta.endpoint.MessageSender;
72 import net.jxta.endpoint.Messenger;
73 import net.jxta.endpoint.TextDocumentMessageElement;
74 import net.jxta.endpoint.WireFormatMessage;
75 import net.jxta.endpoint.WireFormatMessageFactory;
76 import net.jxta.exception.PeerGroupException;
77 import net.jxta.id.ID;
78 import net.jxta.id.IDFactory;
79 import net.jxta.impl.endpoint.JxtaMessageMessageElement;
80 import net.jxta.impl.membership.pse.PSECredential;
81 import net.jxta.impl.membership.pse.PSEMembershipService;
82 import net.jxta.impl.membership.pse.PSEUtils;
83 import net.jxta.logging.Logging;
84 import net.jxta.membership.MembershipService;
85 import net.jxta.peer.PeerID;
86 import net.jxta.peergroup.PeerGroup;
87 import net.jxta.platform.Module;
88 import net.jxta.protocol.ModuleImplAdvertisement;
89
90 import java.io.IOException;
91 import java.security.cert.Certificate;
92 import java.security.interfaces.RSAPublicKey;
93 import java.util.Collections;
94 import java.util.Iterator;
95 import java.util.logging.Level;
96 import java.util.logging.Logger;
97
98
99 /**
100  * A JXTA {@link net.jxta.endpoint.MessageTransport} implementation which
101  * which provides message verification by examining message signatures. A
102  * virtual transport, the messages are transfered between peers using some
103  * other message transport.
104  */
105 public class CbJxTransport implements Module, MessageSender, MessageReceiver, EndpointListener {
106
107     /**
108      * Logger
109      */
110     private final static Logger LOG = Logger.getLogger(CbJxTransport.class.getName());
111
112     /**
113      * the name of the cbjx valid element
114      */
115     public static final String CBJX_MSG_NS = "cbjx";
116
117     /**
118      * the name of the cbjx crypto element
119      */
120     static final String CBJX_MSG_INFO = "CryptoInfo";
121
122     /**
123      * the name of the cbjx body element
124      */
125     static final String CBJX_MSG_BODY = "Body";
126
127     /**
128      * the name of the cbjx body element
129      */
130     static final String CBJX_MSG_SIG = "Signature";
131
132     /**
133      * the cbjx protocol name
134      */
135     static final String cbjxProtocolName = "cbjx";
136
137     /**
138      * the cbjx service name
139      */
140     static final String cbjxServiceName = "CbJxTransport";
141
142     /**
143      * the local peer ID
144      */
145     static PeerID localPeerID = null;
146
147     /**
148      * the endpoint address of this peer
149      */
150     static EndpointAddress localPeerAddr = null;
151
152     /**
153      * the peer group to which this module belongs
154      */
155     PeerGroup group = null;
156
157     /**
158      * the endpoint service in my group
159      */
160     EndpointService endpoint = null;
161
162     /**
163      * the membership service in my group
164      */
165     PSEMembershipService membership = null;
166
167     /**
168      * Default constructor
169      */
170     public CbJxTransport() {}
171
172     /**
173      * {@inheritDoc}
174      */
175     public void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException {
176         this.group = group;
177
178         ModuleImplAdvertisement implAdvertisement = (ModuleImplAdvertisement) impl;
179
180         localPeerID = group.getPeerID();
181
182         CbJxTransport.localPeerAddr = new EndpointAddress(cbjxProtocolName, group.getPeerID().getUniqueValue().toString(), null
183                 ,
184                 null);
185
186         if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
187             StringBuilder configInfo = new StringBuilder("Configuring CBJX Message Transport : " + assignedID);
188
189             if (implAdvertisement != null) {
190                 configInfo.append("\n\tImplementation :");
191                 configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID());
192                 configInfo.append("\n\t\tImpl Description : ").append(implAdvertisement.getDescription());
193                 configInfo.append("\n\t\tImpl URI : ").append(implAdvertisement.getUri());
194                 configInfo.append("\n\t\tImpl Code : ").append(implAdvertisement.getCode());
195             }
196
197             configInfo.append("\n\tGroup Params :");
198             configInfo.append("\n\t\tGroup : ").append(group);
199             configInfo.append("\n\t\tPeer ID : ").append(group.getPeerID());
200
201             configInfo.append("\n\tConfiguration :");
202             configInfo.append("\n\t\tPublic Address : ").append(CbJxTransport.localPeerAddr);
203
204             LOG.config(configInfo.toString());
205         }
206     }
207
208     /**
209      * {@inheritDoc}
210      */
211     public int startApp(String[] arg) {
212
213         endpoint = group.getEndpointService();
214
215         if (null == endpoint) {
216             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
217                 LOG.warning("Stalled until there is an endpoint service");
218             }
219             return START_AGAIN_STALLED;
220         }
221
222         MembershipService groupMembership = group.getMembershipService();
223
224         if (null == groupMembership) {
225             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
226                 LOG.warning("Stalled until there is a membership service");
227             }
228             return START_AGAIN_STALLED;
229         }
230
231         if (!(groupMembership instanceof PSEMembershipService)) {
232             if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
233                 LOG.severe("CBJX Transport requires PSE Membership Service");
234             }
235             return -1;
236         }
237
238         membership = (PSEMembershipService) groupMembership;
239
240         if (endpoint.addMessageTransport(this) == null) {
241             if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
242                 LOG.severe("Transport registration refused");
243             }
244             return -1;
245         }
246
247         // XXX bondolo@jxta.org 20030526 check for errors
248
249         endpoint.addIncomingMessageListener(this, cbjxServiceName, null);
250
251         endpoint.addIncomingMessageFilterListener(new CbJxInputFilter(), null, null);
252         // endpoint.addOutgoingMessageFilterListener( new CbJxOutputFilter(), null, null );
253
254         if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
255             LOG.info("CbJxTransport started");
256         }
257
258         return 0;
259     }
260
261     /**
262      * {@inheritDoc}
263      */
264     public void stopApp() {
265
266         if (endpoint != null) {
267             // FIXME 20030516 bondolo@jxta.org remove filters and listener
268
269             endpoint.removeMessageTransport(this);
270             endpoint = null;
271         }
272
273         if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
274             LOG.info("CbJxTransport stopped");
275         }
276     }
277
278     /**
279      * {@inheritDoc}
280      */
281     public EndpointAddress getPublicAddress() {
282         return CbJxTransport.localPeerAddr;
283     }
284
285     /**
286      * {@inheritDoc}
287      */
288     public boolean isConnectionOriented() {
289         // since we rely on other endpoint protocol we are not connection oriented
290         return false;
291     }
292
293     /**
294      * {@inheritDoc}
295      */
296     public boolean allowsRouting() {
297         // since we are using the endpoint router
298         // the endpoint router cannot use our endpoint to send messages
299         return false;
300     }
301
302     /**
303      * {@inheritDoc}
304      */
305     public EndpointService getEndpointService() {
306         return (EndpointService) endpoint.getInterface();
307     }
308
309     /**
310      * {@inheritDoc}
311      */
312     public Object transportControl(Object operation, Object value) {
313         return null;
314     }
315
316     /**
317      * {@inheritDoc}
318      */
319     public Iterator getPublicAddresses() {
320         return Collections.singletonList(getPublicAddress()).iterator();
321     }
322
323     /**
324      * {@inheritDoc}
325      */
326     public String getProtocolName() {
327         return cbjxProtocolName;
328     }
329
330     /**
331      * {@inheritDoc}
332      */
333     public Messenger getMessenger(EndpointAddress dest, Object hintIgnored) {
334         try {
335             return new CbJxMessenger(this, dest, hintIgnored);
336         } catch (IOException failed) {
337             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
338                 LOG.log(Level.WARNING, "Failed to create cbjx messenger", failed);
339             }
340             return null;
341         }
342     }
343
344     /**
345      * {@inheritDoc}
346      */
347     @Deprecated
348     public boolean ping(EndpointAddress addr) {
349         Messenger messenger = getMessenger(addr, null);
350
351         boolean reachable = (null != messenger);
352
353         if (messenger != null) {
354             messenger.close();
355         }
356
357         return reachable;
358     }
359
360     /**
361      * {@inheritDoc}
362      */
363     public void processIncomingMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) {
364         if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
365             LOG.fine("processIncomingMessage : Received message from: " + srcAddr);
366         }
367
368         // extract the Crypto info from the message
369         MessageElement cryptoElement = message.getMessageElement(CBJX_MSG_NS, CBJX_MSG_INFO);
370
371         if (cryptoElement == null) {
372             if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
373                 LOG.fine("processIncomingMessage : No \'" + CBJX_MSG_INFO + "\' in the message");
374             }
375             return;
376         }
377         message.removeMessageElement(cryptoElement);
378
379         // the cbjx message info
380         CbJxMessageInfo cryptoInfo = null;
381
382         try {
383             cryptoInfo = new CbJxMessageInfo(cryptoElement.getStream(), cryptoElement.getMimeType());
384         } catch (Throwable e) {
385             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
386                 LOG.log(Level.WARNING
387                         ,
388                         "processIncomingMessage : Couldn\'t retrieve CbJxMessageInfo from \'" + CBJX_MSG_INFO + "\' element", e);
389             }
390             return;
391         }
392
393         Message submessage = checkCryptoInfo(message, cryptoElement, cryptoInfo);
394
395         if (null == submessage) {
396             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
397                 LOG.warning("processIncomingMessage : discarding message from " + srcAddr);
398             }
399             return;
400         }
401
402         // give back the message to the endpoint
403         try {
404             if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
405                 LOG.fine("processIncomingMessage: delivering " + submessage + " to: " + cryptoInfo.getDestinationAddress());
406             }
407
408             endpoint.processIncomingMessage(submessage, cryptoInfo.getSourceAddress(), cryptoInfo.getDestinationAddress());
409         } catch (Throwable all) {
410             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
411                 LOG.log(Level.WARNING, "processIncomingMessage: endpoint failed to demux message", all);
412             }
413         }
414     }
415
416     /**
417      * add the CryptoInfo into the message
418      *
419      * @param submessage  the message
420      * @param destAddress the destination
421      * @return Message the message with the CbJxMessageInfo added
422      */
423     public Message addCryptoInfo(Message submessage, EndpointAddress destAddress) throws IOException {
424         if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
425             LOG.fine("Building CBJX wrapper for " + submessage);
426         }
427
428         // Remove all existing CbJx Elements from source
429         Iterator eachCbJxElement = submessage.getMessageElementsOfNamespace(CbJxTransport.CBJX_MSG_NS);
430
431         while (eachCbJxElement.hasNext()) {
432             MessageElement aMessageElement = (MessageElement) eachCbJxElement.next();
433
434             eachCbJxElement.remove();
435         }
436
437         Message message = new Message();
438
439         CbJxMessageInfo cryptoInfo = new CbJxMessageInfo();
440
441         // set the source Id of the message
442         cryptoInfo.setSourceID(localPeerID);
443         cryptoInfo.setSourceAddress(localPeerAddr);
444         cryptoInfo.setDestinationAddress(destAddress);
445
446         // add the root cert into the message info
447         PSECredential cred = (PSECredential) membership.getDefaultCredential();
448
449         if (null == cred) {
450             throw new IOException("No authentication available for message signing.");
451         }
452
453         Certificate cert = cred.getCertificate();
454
455         cryptoInfo.setPeerCert(cert);
456
457         // compute the signature of the message body
458         TextDocument infoDoc = (TextDocument) cryptoInfo.getDocument(MimeMediaType.XMLUTF8);
459         byte[] infoSignature = null;
460
461         try {
462             infoSignature = PSEUtils.computeSignature(CbJxDefs.signAlgoName, cred.getPrivateKey(), infoDoc.getStream());
463         } catch (Throwable e) {
464             if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
465                 LOG.log(Level.FINE, "failed to sign " + submessage, e);
466             }
467             return null;
468         }
469
470         // add the cbjx:CryptoInfo into the message
471         MessageElement infoSigElement = new ByteArrayMessageElement(CBJX_MSG_SIG, MimeMediaType.AOS, infoSignature, null);
472
473         // add the cbjx:CryptoInfo into the message
474         MessageElement cryptoInfoElement = new TextDocumentMessageElement(CBJX_MSG_INFO, infoDoc, infoSigElement);
475
476         message.addMessageElement(CBJX_MSG_NS, cryptoInfoElement);
477
478         // Compute the signature of the encapsulated message and append it to
479         // the container.
480
481         // serialize the container
482         WireFormatMessage subserial = WireFormatMessageFactory.toWire(submessage, WireFormatMessageFactory.DEFAULT_WIRE_MIME, null);
483
484         // calculate the signature
485         byte[] bodySignature = null;
486
487         try {
488             bodySignature = PSEUtils.computeSignature(CbJxDefs.signAlgoName, cred.getPrivateKey(), subserial.getStream());
489         } catch (Throwable e) {
490             if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
491                 LOG.log(Level.FINE, "failed to sign" + submessage, e);
492             }
493             return null;
494         }
495
496         subserial = null;
497
498         // Make the signature into an element
499         MessageElement bodySigElement = new ByteArrayMessageElement(CBJX_MSG_SIG, MimeMediaType.AOS, bodySignature, null);
500
501         // Add the encapsulated body into the container message.
502         message.addMessageElement(CBJX_MSG_NS
503                 ,
504                 new JxtaMessageMessageElement(CBJX_MSG_BODY, new MimeMediaType("application/x-jxta-msg"), submessage
505                 ,
506                 bodySigElement));
507
508         return message;
509     }
510
511     public Message checkCryptoInfo(Message message, MessageElement cryptoElement, CbJxMessageInfo cryptoInfo) {
512
513         // extract the body element  from the message
514         JxtaMessageMessageElement bodyElement = (JxtaMessageMessageElement) message.getMessageElement(CBJX_MSG_NS, CBJX_MSG_BODY);
515
516         if (null == bodyElement) {
517             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
518                 LOG.warning("No \'" + CBJX_MSG_BODY + "\' in " + message);
519             }
520             return null;
521         }
522         message.removeMessageElement(bodyElement);
523
524         // extract the peer certificate
525         Certificate peerCert = cryptoInfo.getPeerCert();
526
527         // and from it the public key
528         // the public key from the message
529         RSAPublicKey publicKey = (RSAPublicKey) peerCert.getPublicKey();
530
531         // check the cert validity
532         try {
533             peerCert.verify(publicKey);
534         } catch (Exception e) {
535             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
536                 LOG.log(Level.WARNING, "Invalid peer cert", e);
537             }
538             return null;
539         }
540
541         // check the cbid
542         try {
543             net.jxta.impl.id.CBID.PeerID srcPeerID = (net.jxta.impl.id.CBID.PeerID) cryptoInfo.getSourceID();
544
545             byte[] pub_der = peerCert.getPublicKey().getEncoded();
546             net.jxta.impl.id.CBID.PeerID genID = (net.jxta.impl.id.CBID.PeerID) IDFactory.newPeerID(group.getPeerGroupID()
547                     ,
548                     pub_der);
549
550             if (!srcPeerID.getUUID().equals(genID.getUUID())) {
551                 // the cbid is not valid. Discard the message
552                 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
553                     LOG.warning("CBID of " + message + " is not valid : " + srcPeerID + " != " + genID);
554                 }
555                 return null;
556             }
557
558             if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
559                 LOG.fine("CBID of the message is valid");
560             }
561         } catch (Throwable e) {
562             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
563                 LOG.log(Level.WARNING, "failed to verify cbid", e);
564             }
565             return null;
566         }
567
568         // verify the signature of the cryptinfo message
569         try {
570             boolean valid = PSEUtils.verifySignature(CbJxDefs.signAlgoName, peerCert, cryptoElement.getSignature().getBytes(false)
571                     ,
572                     cryptoElement.getStream());
573
574             if (!valid) {
575                 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
576                     LOG.warning("Failed to verify the signature of cryptinfo for " + message);
577                 }
578                 return null;
579             }
580         } catch (Throwable e) {
581             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
582                 LOG.log(Level.WARNING, "Failed to verify the signature of cryptinfo for " + message, e);
583             }
584             return null;
585         }
586
587         // then verify the signature
588         if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
589             LOG.warning("verifying signature");
590         }
591
592         // verify the signature of the message
593         try {
594             boolean valid = PSEUtils.verifySignature(CbJxDefs.signAlgoName, peerCert, bodyElement.getSignature().getBytes(false)
595                     ,
596                     bodyElement.getStream());
597
598             if (!valid) {
599                 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
600                     LOG.warning("failed to verify the signature of " + message);
601                 }
602                 return null;
603             }
604         } catch (Throwable e) {
605             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
606                 LOG.log(Level.WARNING, "failed to verify the signature of " + message, e);
607             }
608             return null;
609         }
610
611         // the message is valid
612         return bodyElement.getMessage();
613     }
614
615     /**
616      * this class filters incoming messages.
617      * it checks if messages are valid and if not discard them
618      */
619     public class CbJxInputFilter implements MessageFilterListener {
620         public CbJxInputFilter() {
621             super();
622         }
623
624         /**
625          * {@inheritDoc}
626          */
627         public Message filterMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) {
628
629             if (dstAddr.getProtocolAddress().equals(getProtocolName())) {
630                 // extract the Crypto info from the message
631                 MessageElement cryptoElement = message.getMessageElement(CBJX_MSG_NS, CBJX_MSG_INFO);
632
633                 if (cryptoElement == null) {
634                     if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
635                         LOG.fine("No \'" + CBJX_MSG_INFO + "\' in the message");
636                     }
637                     return null;
638                 }
639                 message.removeMessageElement(cryptoElement);
640
641                 // the cbjx message info
642                 CbJxMessageInfo cryptoInfo = null;
643
644                 try {
645                     cryptoInfo = new CbJxMessageInfo(cryptoElement.getStream(), cryptoElement.getMimeType());
646                 } catch (Throwable e) {
647                     if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
648                         LOG.log(Level.WARNING, "Couldn\'t retrieve CbJxMessageInfo from \'" + CBJX_MSG_INFO + "\' element", e);
649                     }
650                     return null;
651                 }
652
653                 return checkCryptoInfo(message, cryptoElement, cryptoInfo);
654             }
655
656             return message;
657         }
658     }
659
660
661     /**
662      * this class filters all outgoing messages that are not sent with
663      * messengers. (that is propagate messages). It adds CbJxInformation
664      * into to messages.
665      */
666     public class CbJxOutputFilter implements MessageFilterListener {
667
668         /**
669          * Default constructor
670          */
671         public CbJxOutputFilter() {
672             super();
673         }
674
675         /**
676          * {@inheritDoc}
677          */
678         public Message filterMessage(Message message, EndpointAddress srcAddr, EndpointAddress dstAddr) {
679             Message msg = message.clone();
680
681             if (null == msg.getMessageElement(CBJX_MSG_NS, CBJX_MSG_INFO)) {
682                 try {
683                     msg = addCryptoInfo(msg, dstAddr);
684                 } catch (IOException failed) {
685                     return null;
686                 }
687             }
688
689             return msg;
690         }
691     }
692 }