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 }