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.impl; 018 019import java.lang.reflect.Method; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.Map; 023import java.util.function.Supplier; 024 025import org.apache.camel.Endpoint; 026import org.apache.camel.Exchange; 027import org.apache.camel.InvokeOnHeader; 028import org.apache.camel.InvokeOnHeaders; 029import org.apache.camel.Message; 030import org.apache.camel.NoSuchHeaderException; 031import org.apache.camel.Processor; 032import org.apache.camel.util.ObjectHelper; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036/** 037 * A selector-based produced which uses an header value to determine which processor 038 * should be invoked. 039 */ 040public class HeaderSelectorProducer extends BaseSelectorProducer { 041 private static final Logger LOGGER = LoggerFactory.getLogger(HeaderSelectorProducer.class); 042 043 private final Supplier<String> headerSupplier; 044 private final Supplier<String> defaultHeaderValueSupplier; 045 private final Object target; 046 private Map<String, Processor> handlers; 047 048 public HeaderSelectorProducer(Endpoint endpoint, Supplier<String> headerSupplier) { 049 this(endpoint, headerSupplier, () -> null, null); 050 } 051 052 public HeaderSelectorProducer(Endpoint endpoint, String header) { 053 this(endpoint, () -> header, () -> null, null); 054 } 055 056 public HeaderSelectorProducer(Endpoint endpoint, String header, Object target) { 057 this(endpoint, () -> header, () -> null, target); 058 } 059 060 public HeaderSelectorProducer(Endpoint endpoint, Supplier<String> headerSupplier, Object target) { 061 this(endpoint, headerSupplier, () -> null, target); 062 } 063 064 public HeaderSelectorProducer(Endpoint endpoint, String header, String defaultHeaderValue) { 065 this(endpoint, () -> header, () -> defaultHeaderValue, null); 066 } 067 068 public HeaderSelectorProducer(Endpoint endpoint, String header, Supplier<String> defaultHeaderValueSupplier) { 069 this(endpoint, () -> header, defaultHeaderValueSupplier, null); 070 } 071 072 public HeaderSelectorProducer(Endpoint endpoint, Supplier<String> headerSupplier, Supplier<String> defaultHeaderValueSupplier) { 073 this(endpoint, headerSupplier, defaultHeaderValueSupplier, null); 074 } 075 076 public HeaderSelectorProducer(Endpoint endpoint, String header, String defaultHeaderValue, Object target) { 077 this(endpoint, () -> header, () -> defaultHeaderValue, target); 078 } 079 080 public HeaderSelectorProducer(Endpoint endpoint, Supplier<String> headerSupplier, Supplier<String> defaultHeaderValueSupplier, Object target) { 081 super(endpoint); 082 083 this.headerSupplier = ObjectHelper.notNull(headerSupplier, "headerSupplier"); 084 this.defaultHeaderValueSupplier = ObjectHelper.notNull(defaultHeaderValueSupplier, "defaultHeaderValueSupplier"); 085 this.target = target != null ? target : this; 086 this.handlers = new HashMap<>(); 087 } 088 089 @Override 090 protected void doStart() throws Exception { 091 for (final Method method : target.getClass().getDeclaredMethods()) { 092 InvokeOnHeaders annotation = method.getAnnotation(InvokeOnHeaders.class); 093 if (annotation != null) { 094 for (InvokeOnHeader processor : annotation.value()) { 095 bind(processor, method); 096 } 097 } else { 098 bind(method.getAnnotation(InvokeOnHeader.class), method); 099 } 100 } 101 102 handlers = Collections.unmodifiableMap(handlers); 103 104 super.doStart(); 105 } 106 107 @Override 108 protected Processor getProcessor(Exchange exchange) throws Exception { 109 String header = headerSupplier.get(); 110 String action = exchange.getIn().getHeader(header, String.class); 111 112 if (action == null) { 113 action = defaultHeaderValueSupplier.get(); 114 } 115 if (action == null) { 116 throw new NoSuchHeaderException(exchange, header, String.class); 117 } 118 119 return handlers.get(action); 120 } 121 122 protected void onMissingProcessor(Exchange exchange) throws Exception { 123 throw new IllegalStateException( 124 "Unsupported operation " + exchange.getIn().getHeader(headerSupplier.get()) 125 ); 126 } 127 128 protected final void bind(String key, Processor processor) { 129 if (handlers.containsKey(key)) { 130 LOGGER.warn("A processor is already set for action {}", key); 131 } 132 133 this.handlers.put(key, processor); 134 } 135 136 private void bind(InvokeOnHeader handler, final Method method) { 137 if (handler != null && method.getParameterCount() == 1) { 138 method.setAccessible(true); 139 140 final Class<?> type = method.getParameterTypes()[0]; 141 142 LOGGER.debug("bind key={}, class={}, method={}, type={}", 143 handler.value(), this.getClass(), method.getName(), type); 144 145 if (Message.class.isAssignableFrom(type)) { 146 bind(handler.value(), e -> method.invoke(target, e.getIn())); 147 } else { 148 bind(handler.value(), e -> method.invoke(target, e)); 149 } 150 } 151 } 152}