if(observer != null) observer.passDown(evt);
    public void down(Event evt) {        if(evt.getType() != Event.MSG) {  // unless it is a message handle it and respond            handleDownEvent(evt);            return;        }        Message msg=(Message)evt.getArg();        if(header != null) {            // added patch by Roland Kurmann (March 20 2003)            // msg.putHeader(name, new TpHeader(channel_name));            msg.putHeader(name, header);        }        // Because we don't call Protocol.passDown(), we notify the observer directly (e.g. PerfObserver).        // This way, we still have performance numbers for TP        if(observer != null)            observer.passDown(evt);        setSourceAddress(msg); // very important !! listToBuffer() will fail with a null src address !!        if(trace) {            StringBuilder sb=new StringBuilder("sending msg to ").append(msg.getDest()).                    append(" (src=").append(msg.getSrc()).append("), headers are ").append(msg.getHeaders());            log.trace(sb.toString());        }        // Don't send if destination is local address. Instead, switch dst and src and put in up_queue.        // If multicast message, loopback a copy directly to us (but still multicast). Once we receive this,        // we will discard our own multicast message        Address dest=msg.getDest();        boolean multicast=dest == null || dest.isMulticastAddress();        if(loopback && (multicast || dest.equals(local_addr))) {            // we *have* to make a copy, or else passUp() might remove headers from msg which will then *not*            // be available for marshalling further down (when sending the message)            Message copy=msg.copy();            if(trace) log.trace(new StringBuffer("looping back message ").append(copy));            passUp(new Event(Event.MSG, copy));            if(!multicast)                return;        }        try {            send(msg, dest, multicast);        }        catch(InterruptedException interruptedEx) {            Thread.currentThread().interrupt(); // let someone else handle the interrupt        }        catch(Throwable e) {            if(log.isErrorEnabled()) {                String dst=msg.getDest() == null? "null" : msg.getDest().toString();                log.error("failed sending message to " + dst + " (" + msg.getLength() + " bytes)", e.getCause());            }        }    }