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