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.processor; 018 019 import java.util.ArrayList; 020 import java.util.List; 021 022 import org.apache.camel.AsyncCallback; 023 import org.apache.camel.AsyncProcessor; 024 import org.apache.camel.Exchange; 025 import org.apache.camel.Navigate; 026 import org.apache.camel.Predicate; 027 import org.apache.camel.Processor; 028 import org.apache.camel.Traceable; 029 import org.apache.camel.support.ServiceSupport; 030 import org.apache.camel.util.AsyncProcessorConverterHelper; 031 import org.apache.camel.util.AsyncProcessorHelper; 032 import org.apache.camel.util.ServiceHelper; 033 import org.slf4j.Logger; 034 import org.slf4j.LoggerFactory; 035 036 /** 037 * Implements a Choice structure where one or more predicates are used which if 038 * they are true their processors are used, with a default otherwise clause used 039 * if none match. 040 * 041 * @version 042 */ 043 public class ChoiceProcessor extends ServiceSupport implements AsyncProcessor, Navigate<Processor>, Traceable { 044 private static final transient Logger LOG = LoggerFactory.getLogger(ChoiceProcessor.class); 045 private final List<FilterProcessor> filters; 046 private final AsyncProcessor otherwise; 047 048 public ChoiceProcessor(List<FilterProcessor> filters, Processor otherwise) { 049 this.filters = filters; 050 this.otherwise = otherwise != null ? AsyncProcessorConverterHelper.convert(otherwise) : null; 051 } 052 053 public void process(Exchange exchange) throws Exception { 054 AsyncProcessorHelper.process(this, exchange); 055 } 056 057 public boolean process(Exchange exchange, AsyncCallback callback) { 058 for (int i = 0; i < filters.size(); i++) { 059 FilterProcessor filter = filters.get(i); 060 Predicate predicate = filter.getPredicate(); 061 062 boolean matches = false; 063 try { 064 // ensure we handle exceptions thrown when matching predicate 065 if (predicate != null) { 066 matches = predicate.matches(exchange); 067 } 068 } catch (Throwable e) { 069 exchange.setException(e); 070 callback.done(true); 071 return true; 072 } 073 074 if (LOG.isDebugEnabled()) { 075 LOG.debug("#{} - {} matches: {} for: {}", new Object[]{i, predicate, matches, exchange}); 076 } 077 078 if (matches) { 079 // process next will also take care (has not null test) if next was a stop(). 080 // stop() has no processor to execute, and thus we will end in a NPE 081 return filter.processNext(exchange, callback); 082 } 083 } 084 if (otherwise != null) { 085 return AsyncProcessorHelper.process(otherwise, exchange, callback); 086 } else { 087 callback.done(true); 088 return true; 089 } 090 } 091 092 @Override 093 public String toString() { 094 StringBuilder builder = new StringBuilder("choice{"); 095 boolean first = true; 096 for (FilterProcessor processor : filters) { 097 if (first) { 098 first = false; 099 } else { 100 builder.append(", "); 101 } 102 builder.append("when "); 103 builder.append(processor.getPredicate().toString()); 104 builder.append(": "); 105 builder.append(processor.getProcessor()); 106 } 107 if (otherwise != null) { 108 builder.append(", otherwise: "); 109 builder.append(otherwise); 110 } 111 builder.append("}"); 112 return builder.toString(); 113 } 114 115 public String getTraceLabel() { 116 return "choice"; 117 } 118 119 public List<FilterProcessor> getFilters() { 120 return filters; 121 } 122 123 public Processor getOtherwise() { 124 return otherwise; 125 } 126 127 public List<Processor> next() { 128 if (!hasNext()) { 129 return null; 130 } 131 List<Processor> answer = new ArrayList<Processor>(); 132 if (filters != null) { 133 answer.addAll(filters); 134 } 135 if (otherwise != null) { 136 answer.add(otherwise); 137 } 138 return answer; 139 } 140 141 public boolean hasNext() { 142 return otherwise != null || (filters != null && !filters.isEmpty()); 143 } 144 145 protected void doStart() throws Exception { 146 ServiceHelper.startServices(filters, otherwise); 147 } 148 149 protected void doStop() throws Exception { 150 ServiceHelper.stopServices(otherwise, filters); 151 } 152 }