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 */ 017 package org.apache.camel.builder; 018 019 import java.util.ArrayList; 020 import java.util.Iterator; 021 import java.util.List; 022 023 import org.apache.camel.Endpoint; 024 import org.apache.camel.model.FromDefinition; 025 import org.apache.camel.model.ProcessorDefinition; 026 import org.apache.camel.model.ProcessorDefinitionHelper; 027 import org.apache.camel.model.RouteDefinition; 028 import org.apache.camel.util.EndpointHelper; 029 import org.slf4j.Logger; 030 import org.slf4j.LoggerFactory; 031 032 /** 033 * {@link AdviceWithTask} tasks which are used by the {@link AdviceWithRouteBuilder}. 034 */ 035 public final class AdviceWithTasks { 036 037 private static final Logger LOG = LoggerFactory.getLogger(AdviceWithTasks.class); 038 039 private AdviceWithTasks() { 040 // utility class 041 } 042 043 /** 044 * Match by is used for pluggable match by logic. 045 */ 046 private interface MatchBy { 047 048 String getId(); 049 050 boolean match(ProcessorDefinition<?> processor); 051 } 052 053 /** 054 * Will match by id of the processor. 055 */ 056 private static final class MatchById implements MatchBy { 057 058 private final String id; 059 060 private MatchById(String id) { 061 this.id = id; 062 } 063 064 public String getId() { 065 return id; 066 } 067 068 public boolean match(ProcessorDefinition<?> processor) { 069 if (id.equals("*")) { 070 // make sure the processor which id isn't be set is matched. 071 return true; 072 } 073 return EndpointHelper.matchPattern(processor.getId(), id); 074 } 075 } 076 077 /** 078 * Will match by the to string representation of the processor. 079 */ 080 private static final class MatchByToString implements MatchBy { 081 082 private final String toString; 083 084 private MatchByToString(String toString) { 085 this.toString = toString; 086 } 087 088 public String getId() { 089 return toString; 090 } 091 092 public boolean match(ProcessorDefinition<?> processor) { 093 return EndpointHelper.matchPattern(processor.toString(), toString); 094 } 095 } 096 097 /** 098 * Will match by the type of the processor. 099 */ 100 private static final class MatchByType implements MatchBy { 101 102 private final Class<?> type; 103 104 private MatchByType(Class<?> type) { 105 this.type = type; 106 } 107 108 public String getId() { 109 return type.getSimpleName(); 110 } 111 112 public boolean match(ProcessorDefinition<?> processor) { 113 return type.isAssignableFrom(processor.getClass()); 114 } 115 } 116 117 public static AdviceWithTask replaceByToString(final RouteDefinition route, final String toString, final ProcessorDefinition<?> replace, 118 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 119 MatchBy matchBy = new MatchByToString(toString); 120 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 121 return doReplace(route, new MatchByToString(toString), replace, it); 122 } 123 124 public static AdviceWithTask replaceById(final RouteDefinition route, final String id, final ProcessorDefinition<?> replace, 125 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 126 MatchBy matchBy = new MatchById(id); 127 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 128 return doReplace(route, matchBy, replace, it); 129 } 130 131 public static AdviceWithTask replaceByType(final RouteDefinition route, final Class<?> type, final ProcessorDefinition<?> replace, 132 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 133 MatchBy matchBy = new MatchByType(type); 134 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 135 return doReplace(route, matchBy, replace, it); 136 } 137 138 private static AdviceWithTask doReplace(final RouteDefinition route, final MatchBy matchBy, final ProcessorDefinition<?> replace, 139 final Iterator<ProcessorDefinition<?>> it) { 140 return new AdviceWithTask() { 141 public void task() throws Exception { 142 boolean match = false; 143 while (it.hasNext()) { 144 ProcessorDefinition<?> output = it.next(); 145 if (matchBy.match(output)) { 146 ProcessorDefinition<?> parent = output.getParent(); 147 if (parent != null) { 148 int index = parent.getOutputs().indexOf(output); 149 if (index != -1) { 150 match = true; 151 parent.getOutputs().add(index + 1, replace); 152 Object old = parent.getOutputs().remove(index); 153 LOG.info("AdviceWith (" + matchBy.getId() + ") : [" + old + "] --> replace [" + replace + "]"); 154 } 155 } 156 } 157 } 158 159 if (!match) { 160 throw new IllegalArgumentException("There are no outputs which matches: " + matchBy.getId() + " in the route: " + route); 161 } 162 } 163 }; 164 } 165 166 public static AdviceWithTask removeByToString(final RouteDefinition route, final String toString, 167 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 168 MatchBy matchBy = new MatchByToString(toString); 169 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 170 return doRemove(route, matchBy, it); 171 } 172 173 public static AdviceWithTask removeById(final RouteDefinition route, final String id, 174 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 175 MatchBy matchBy = new MatchById(id); 176 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 177 return doRemove(route, matchBy, it); 178 } 179 180 public static AdviceWithTask removeByType(final RouteDefinition route, final Class<?> type, 181 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 182 MatchBy matchBy = new MatchByType(type); 183 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 184 return doRemove(route, matchBy, it); 185 } 186 187 private static AdviceWithTask doRemove(final RouteDefinition route, final MatchBy matchBy, 188 final Iterator<ProcessorDefinition<?>> it) { 189 return new AdviceWithTask() { 190 public void task() throws Exception { 191 boolean match = false; 192 while (it.hasNext()) { 193 ProcessorDefinition<?> output = it.next(); 194 if (matchBy.match(output)) { 195 ProcessorDefinition<?> parent = output.getParent(); 196 if (parent != null) { 197 int index = parent.getOutputs().indexOf(output); 198 if (index != -1) { 199 match = true; 200 Object old = parent.getOutputs().remove(index); 201 LOG.info("AdviceWith (" + matchBy.getId() + ") : [" + old + "] --> remove"); 202 } 203 } 204 } 205 } 206 207 if (!match) { 208 throw new IllegalArgumentException("There are no outputs which matches: " + matchBy.getId() + " in the route: " + route); 209 } 210 } 211 }; 212 } 213 214 public static AdviceWithTask beforeByToString(final RouteDefinition route, final String toString, final ProcessorDefinition<?> before, 215 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 216 MatchBy matchBy = new MatchByToString(toString); 217 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 218 return doBefore(route, matchBy, before, it); 219 } 220 221 public static AdviceWithTask beforeById(final RouteDefinition route, final String id, final ProcessorDefinition<?> before, 222 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 223 MatchBy matchBy = new MatchById(id); 224 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 225 return doBefore(route, matchBy, before, it); 226 } 227 228 public static AdviceWithTask beforeByType(final RouteDefinition route, final Class<?> type, final ProcessorDefinition<?> before, 229 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 230 MatchBy matchBy = new MatchByType(type); 231 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 232 return doBefore(route, matchBy, before, it); 233 } 234 235 private static AdviceWithTask doBefore(final RouteDefinition route, final MatchBy matchBy, final ProcessorDefinition<?> before, 236 final Iterator<ProcessorDefinition<?>> it) { 237 return new AdviceWithTask() { 238 public void task() throws Exception { 239 boolean match = false; 240 while (it.hasNext()) { 241 ProcessorDefinition<?> output = it.next(); 242 if (matchBy.match(output)) { 243 ProcessorDefinition<?> parent = output.getParent(); 244 if (parent != null) { 245 int index = parent.getOutputs().indexOf(output); 246 if (index != -1) { 247 match = true; 248 Object existing = parent.getOutputs().get(index); 249 parent.getOutputs().add(index, before); 250 LOG.info("AdviceWith (" + matchBy.getId() + ") : [" + existing + "] --> before [" + before + "]"); 251 } 252 } 253 } 254 } 255 256 if (!match) { 257 throw new IllegalArgumentException("There are no outputs which matches: " + matchBy.getId() + " in the route: " + route); 258 } 259 } 260 }; 261 } 262 263 public static AdviceWithTask afterByToString(final RouteDefinition route, final String toString, final ProcessorDefinition<?> after, 264 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 265 MatchBy matchBy = new MatchByToString(toString); 266 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 267 return doAfter(route, matchBy, after, it); 268 } 269 270 public static AdviceWithTask afterById(final RouteDefinition route, final String id, final ProcessorDefinition<?> after, 271 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 272 MatchBy matchBy = new MatchById(id); 273 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 274 return doAfter(route, matchBy, after, it); 275 } 276 277 public static AdviceWithTask afterByType(final RouteDefinition route, final Class<?> type, final ProcessorDefinition<?> after, 278 boolean selectFirst, boolean selectLast, int selectFrom, int selectTo) { 279 MatchBy matchBy = new MatchByType(type); 280 Iterator<ProcessorDefinition<?>> it = AdviceWithTasks.createMatchByIterator(route, matchBy, selectFirst, selectLast, selectFrom, selectTo); 281 return doAfter(route, matchBy, after, it); 282 } 283 284 private static AdviceWithTask doAfter(final RouteDefinition route, final MatchBy matchBy, final ProcessorDefinition<?> after, 285 final Iterator<ProcessorDefinition<?>> it) { 286 return new AdviceWithTask() { 287 public void task() throws Exception { 288 boolean match = false; 289 while (it.hasNext()) { 290 ProcessorDefinition<?> output = it.next(); 291 if (matchBy.match(output)) { 292 293 ProcessorDefinition<?> parent = output.getParent(); 294 if (parent != null) { 295 int index = parent.getOutputs().indexOf(output); 296 if (index != -1) { 297 match = true; 298 Object existing = parent.getOutputs().get(index); 299 parent.getOutputs().add(index + 1, after); 300 LOG.info("AdviceWith (" + matchBy.getId() + ") : [" + existing + "] --> after [" + after + "]"); 301 } 302 } 303 } 304 } 305 306 if (!match) { 307 throw new IllegalArgumentException("There are no outputs which matches: " + matchBy.getId() + " in the route: " + route); 308 } 309 } 310 }; 311 } 312 313 public static AdviceWithTask replaceFromWith(final RouteDefinition route, final String uri) { 314 return new AdviceWithTask() { 315 public void task() throws Exception { 316 FromDefinition from = route.getInputs().get(0); 317 LOG.info("AdviceWith replace input from [{}] --> [{}]", from.getUriOrRef(), uri); 318 from.setEndpoint(null); 319 from.setRef(null); 320 from.setUri(uri); 321 } 322 }; 323 } 324 325 public static AdviceWithTask replaceFrom(final RouteDefinition route, final Endpoint endpoint) { 326 return new AdviceWithTask() { 327 public void task() throws Exception { 328 FromDefinition from = route.getInputs().get(0); 329 LOG.info("AdviceWith replace input from [{}] --> [{}]", from.getUriOrRef(), endpoint.getEndpointUri()); 330 from.setRef(null); 331 from.setUri(null); 332 from.setEndpoint(endpoint); 333 } 334 }; 335 } 336 337 /** 338 * Create iterator which walks the route, and only returns nodes which matches the given set of criteria. 339 * 340 * @param route the route 341 * @param matchBy match by which must match 342 * @param selectFirst optional to select only the first 343 * @param selectLast optional to select only the last 344 * @param selectFrom optional to select index/range 345 * @param selectTo optional to select index/range 346 * 347 * @return the iterator 348 */ 349 private static Iterator<ProcessorDefinition<?>> createMatchByIterator(final RouteDefinition route, final MatchBy matchBy, 350 final boolean selectFirst, final boolean selectLast, 351 final int selectFrom, final int selectTo) { 352 353 // first iterator and apply match by 354 List<ProcessorDefinition<?>> matched = new ArrayList<ProcessorDefinition<?>>(); 355 356 @SuppressWarnings("rawtypes") 357 Iterator<ProcessorDefinition> itAll = ProcessorDefinitionHelper.filterTypeInOutputs(route.getOutputs(), ProcessorDefinition.class); 358 while (itAll.hasNext()) { 359 ProcessorDefinition<?> next = itAll.next(); 360 if (matchBy.match(next)) { 361 matched.add(next); 362 } 363 } 364 365 // and then apply the selector iterator 366 return createSelectorIterator(matched, selectFirst, selectLast, selectFrom, selectTo); 367 } 368 369 private static Iterator<ProcessorDefinition<?>> createSelectorIterator(final List<ProcessorDefinition<?>> list, final boolean selectFirst, 370 final boolean selectLast, final int selectFrom, final int selectTo) { 371 return new Iterator<ProcessorDefinition<?>>() { 372 private int current; 373 private boolean done; 374 375 @Override 376 public boolean hasNext() { 377 if (list.isEmpty() || done) { 378 return false; 379 } 380 381 if (selectFirst) { 382 done = true; 383 // spool to first 384 current = 0; 385 return true; 386 } 387 388 if (selectLast) { 389 done = true; 390 // spool to last 391 current = list.size() - 1; 392 return true; 393 } 394 395 if (selectFrom >= 0 && selectTo >= 0) { 396 // check for out of bounds 397 if (selectFrom >= list.size() || selectTo >= list.size()) { 398 return false; 399 } 400 if (current < selectFrom) { 401 // spool to beginning of range 402 current = selectFrom; 403 } 404 return current >= selectFrom && current <= selectTo; 405 } 406 407 return current < list.size(); 408 } 409 410 @Override 411 public ProcessorDefinition<?> next() { 412 ProcessorDefinition<?> answer = list.get(current); 413 current++; 414 return answer; 415 } 416 417 @Override 418 public void remove() { 419 // noop 420 } 421 }; 422 } 423 424 }