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.component.controlbus;
018
019import javax.management.MBeanServer;
020import javax.management.ObjectName;
021
022import org.apache.camel.AsyncCallback;
023import org.apache.camel.CamelContext;
024import org.apache.camel.Endpoint;
025import org.apache.camel.Exchange;
026import org.apache.camel.Expression;
027import org.apache.camel.Route;
028import org.apache.camel.ServiceStatus;
029import org.apache.camel.builder.ExpressionBuilder;
030import org.apache.camel.impl.DefaultAsyncProducer;
031import org.apache.camel.spi.Language;
032import org.apache.camel.util.CamelLogger;
033import org.apache.camel.util.ExchangeHelper;
034import org.apache.camel.util.ObjectHelper;
035
036/**
037 * The control bus producer.
038 */
039public class ControlBusProducer extends DefaultAsyncProducer {
040    private static final Expression ROUTE_ID_EXPRESSION = ExpressionBuilder.routeIdExpression();
041
042    private final CamelLogger logger;
043
044    public ControlBusProducer(Endpoint endpoint, CamelLogger logger) {
045        super(endpoint);
046        this.logger = logger;
047    }
048
049    @Override
050    public ControlBusEndpoint getEndpoint() {
051        return (ControlBusEndpoint) super.getEndpoint();
052    }
053
054    @Override
055    public boolean process(Exchange exchange, AsyncCallback callback) {
056        if (getEndpoint().getLanguage() != null) {
057            try {
058                processByLanguage(exchange, getEndpoint().getLanguage());
059            } catch (Exception e) {
060                exchange.setException(e);
061            }
062        } else if (getEndpoint().getAction() != null) {
063            try {
064                processByAction(exchange);
065            } catch (Exception e) {
066                exchange.setException(e);
067            }
068        }
069
070        callback.done(true);
071        return true;
072    }
073
074    protected void processByLanguage(Exchange exchange, Language language) throws Exception {
075        LanguageTask task = new LanguageTask(exchange, language);
076        if (getEndpoint().isAsync()) {
077            getEndpoint().getComponent().getExecutorService().submit(task);
078        } else {
079            task.run();
080        }
081    }
082
083    protected void processByAction(Exchange exchange) throws Exception {
084        ActionTask task = new ActionTask(exchange);
085        if (getEndpoint().isAsync()) {
086            getEndpoint().getComponent().getExecutorService().submit(task);
087        } else {
088            task.run();
089        }
090    }
091
092    /**
093     * Tasks to run when processing by language.
094     */
095    private final class LanguageTask implements Runnable {
096
097        private final Exchange exchange;
098        private final Language language;
099
100        private LanguageTask(Exchange exchange, Language language) {
101            this.exchange = exchange;
102            this.language = language;
103        }
104
105        @Override
106        public void run() {
107            String task = null;
108            Object result = null;
109
110            try {
111                // create dummy exchange
112                Exchange dummy = ExchangeHelper.createCopy(exchange, true);
113
114                task = dummy.getIn().getMandatoryBody(String.class);
115                if (task != null) {
116                    Expression exp = language.createExpression(task);
117                    result = exp.evaluate(dummy, Object.class);
118                }
119
120                if (result != null && !getEndpoint().isAsync()) {
121                    // can only set result on exchange if sync
122                    exchange.getIn().setBody(result);
123                }
124
125                if (task != null) {
126                    logger.log("ControlBus task done [" + task + "] with result -> " + (result != null ? result : "void"));
127                }
128            } catch (Exception e) {
129                logger.log("Error executing ControlBus task [" + task + "]. This exception will be ignored.", e);
130            }
131        }
132    }
133
134    /**
135     * Tasks to run when processing by route action.
136     */
137    private final class ActionTask implements Runnable {
138
139        private final Exchange exchange;
140
141        private ActionTask(Exchange exchange) {
142            this.exchange = exchange;
143        }
144
145        @Override
146        public void run() {
147            String action = getEndpoint().getAction();
148            String id = getEndpoint().getRouteId();
149
150            if (ObjectHelper.equal("current", id)) {
151                id = ROUTE_ID_EXPRESSION.evaluate(exchange, String.class);
152            }
153
154            Object result = null;
155            String task = action + " route " + id;
156
157            try {
158                if ("start".equals(action)) {
159                    log.debug("Starting route: {}", id);
160                    getEndpoint().getCamelContext().startRoute(id);
161                } else if ("stop".equals(action)) {
162                    log.debug("Stopping route: {}", id);
163                    getEndpoint().getCamelContext().stopRoute(id);
164                } else if ("suspend".equals(action)) {
165                    log.debug("Suspending route: {}", id);
166                    getEndpoint().getCamelContext().suspendRoute(id);
167                } else if ("resume".equals(action)) {
168                    log.debug("Resuming route: {}", id);
169                    getEndpoint().getCamelContext().resumeRoute(id);
170                } else if ("restart".equals(action)) {
171                    log.debug("Restarting route: {}", id);
172                    getEndpoint().getCamelContext().stopRoute(id);
173                    int delay = getEndpoint().getRestartDelay();
174                    if (delay > 0) {
175                        try {
176                            log.debug("Sleeping {} ms before starting route: {}", delay, id);
177                            Thread.sleep(delay);
178                        } catch (InterruptedException e) {
179                            // ignore
180                        }
181                    }
182                    getEndpoint().getCamelContext().startRoute(id);
183                } else if ("status".equals(action)) {
184                    log.debug("Route status: {}", id);
185                    ServiceStatus status = getEndpoint().getCamelContext().getRouteStatus(id);
186                    if (status != null) {
187                        result = status.name();
188                    }
189                } else if ("stats".equals(action)) {
190                    log.debug("Route stats: {}", id);
191
192                    // camel context or per route
193                    String name = getEndpoint().getCamelContext().getManagementName();
194                    if (name == null) {
195                        result = "JMX is disabled, cannot get stats";
196                    } else {
197                        ObjectName on;
198                        String operation;
199                        if (id == null) {
200                            CamelContext camelContext = getEndpoint().getCamelContext();
201                            on = getEndpoint().getCamelContext().getManagementStrategy().getManagementNamingStrategy().getObjectNameForCamelContext(camelContext);
202                            operation = "dumpRoutesStatsAsXml";
203                        } else {
204                            Route route = getEndpoint().getCamelContext().getRoute(id);
205                            on = getEndpoint().getCamelContext().getManagementStrategy().getManagementNamingStrategy().getObjectNameForRoute(route);
206                            operation = "dumpRouteStatsAsXml";
207                        }
208                        if (on != null) {
209                            MBeanServer server = getEndpoint().getCamelContext().getManagementStrategy().getManagementAgent().getMBeanServer();
210                            result = server.invoke(on, operation, new Object[]{true, true}, new String[]{"boolean", "boolean"});
211                        } else {
212                            result = "Cannot lookup route with id " + id;
213                        }
214                    }
215                }
216
217                if (result != null && !getEndpoint().isAsync()) {
218                    // can only set result on exchange if sync
219                    exchange.getIn().setBody(result);
220                }
221
222                logger.log("ControlBus task done [" + task + "] with result -> " + (result != null ? result : "void"));
223            } catch (Exception e) {
224                logger.log("Error executing ControlBus task [" + task + "]. This exception will be ignored.", e);
225            }
226        }
227    }
228
229}