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 */ 017package org.apache.camel.processor.interceptor; 018 019import java.util.Date; 020import java.util.HashMap; 021import java.util.Map; 022 023import org.apache.camel.Endpoint; 024import org.apache.camel.Exchange; 025import org.apache.camel.Processor; 026import org.apache.camel.Producer; 027import org.apache.camel.Service; 028import org.apache.camel.impl.DefaultExchange; 029import org.apache.camel.model.ProcessorDefinition; 030import org.apache.camel.util.IntrospectionSupport; 031import org.apache.camel.util.ObjectHelper; 032import org.apache.camel.util.ServiceHelper; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036public class DefaultTraceEventHandler implements TraceEventHandler, Service { 037 private static final Logger LOG = LoggerFactory.getLogger(DefaultTraceEventHandler.class); 038 039 private Producer traceEventProducer; 040 private Class<?> jpaTraceEventMessageClass; 041 private String jpaTraceEventMessageClassName; 042 043 private final Tracer tracer; 044 045 public DefaultTraceEventHandler(Tracer tracer) { 046 this.tracer = tracer; 047 } 048 049 private synchronized void loadJpaTraceEventMessageClass(Exchange exchange) { 050 if (jpaTraceEventMessageClass == null) { 051 jpaTraceEventMessageClassName = tracer.getJpaTraceEventMessageClassName(); 052 } 053 if (jpaTraceEventMessageClass == null) { 054 jpaTraceEventMessageClass = exchange.getContext().getClassResolver().resolveClass(jpaTraceEventMessageClassName); 055 if (jpaTraceEventMessageClass == null) { 056 throw new IllegalArgumentException("Cannot find class: " + jpaTraceEventMessageClassName 057 + ". Make sure camel-jpa.jar is in the classpath."); 058 } 059 } 060 } 061 062 private synchronized Producer getTraceEventProducer(Exchange exchange) throws Exception { 063 if (traceEventProducer == null) { 064 // create producer when we have access the the camel context (we dont in doStart) 065 Endpoint endpoint = tracer.getDestination() != null ? tracer.getDestination() : exchange.getContext().getEndpoint(tracer.getDestinationUri()); 066 traceEventProducer = endpoint.createProducer(); 067 ServiceHelper.startService(traceEventProducer); 068 } 069 return traceEventProducer; 070 } 071 072 @Override 073 public void traceExchange(ProcessorDefinition<?> node, Processor target, TraceInterceptor traceInterceptor, Exchange exchange) throws Exception { 074 if (tracer.getDestination() != null || tracer.getDestinationUri() != null) { 075 076 // create event exchange and add event information 077 Date timestamp = new Date(); 078 Exchange event = new DefaultExchange(exchange); 079 event.setProperty(Exchange.TRACE_EVENT_NODE_ID, node.getId()); 080 event.setProperty(Exchange.TRACE_EVENT_TIMESTAMP, timestamp); 081 // keep a reference to the original exchange in case its needed 082 event.setProperty(Exchange.TRACE_EVENT_EXCHANGE, exchange); 083 084 // create event message to sent as in body containing event information such as 085 // from node, to node, etc. 086 TraceEventMessage msg = new DefaultTraceEventMessage(timestamp, node, exchange); 087 088 // should we use ordinary or jpa objects 089 if (tracer.isUseJpa()) { 090 if (LOG.isTraceEnabled()) { 091 LOG.trace("Using class: " + this.jpaTraceEventMessageClassName + " for tracing event messages"); 092 } 093 094 // load the jpa event message class 095 loadJpaTraceEventMessageClass(exchange); 096 // create a new instance of the event message class 097 Object jpa = ObjectHelper.newInstance(jpaTraceEventMessageClass); 098 099 // copy options from event to jpa 100 Map<String, Object> options = new HashMap<String, Object>(); 101 IntrospectionSupport.getProperties(msg, options, null); 102 IntrospectionSupport.setProperties(exchange.getContext().getTypeConverter(), jpa, options); 103 // and set the timestamp as its not a String type 104 IntrospectionSupport.setProperty(exchange.getContext().getTypeConverter(), jpa, "timestamp", msg.getTimestamp()); 105 106 event.getIn().setBody(jpa); 107 } else { 108 event.getIn().setBody(msg); 109 } 110 111 // marker property to indicate its a tracing event being routed in case 112 // new Exchange instances is created during trace routing so we can check 113 // for this marker when interceptor also kick in during routing of trace events 114 event.setProperty(Exchange.TRACE_EVENT, Boolean.TRUE); 115 try { 116 // process the trace route 117 getTraceEventProducer(exchange).process(event); 118 } catch (Exception e) { 119 // log and ignore this as the original Exchange should be allowed to continue 120 LOG.error("Error processing trace event (original Exchange will continue): " + event, e); 121 } 122 } 123 } 124 125 @Override 126 public Object traceExchangeIn(ProcessorDefinition<?> node, Processor target, TraceInterceptor traceInterceptor, Exchange exchange) throws Exception { 127 traceExchange(node, target, traceInterceptor, exchange); 128 return null; 129 } 130 131 @Override 132 public void traceExchangeOut(ProcessorDefinition<?> node, Processor target, TraceInterceptor traceInterceptor, Exchange exchange, Object traceState) throws Exception { 133 traceExchange(node, target, traceInterceptor, exchange); 134 } 135 136 @Override 137 public void start() throws Exception { 138 traceEventProducer = null; 139 } 140 141 @Override 142 public void stop() throws Exception { 143 if (traceEventProducer != null) { 144 ServiceHelper.stopService(traceEventProducer); 145 } 146 } 147 148}