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.directvm;
018
019import org.apache.camel.AsyncCallback;
020import org.apache.camel.Exchange;
021import org.apache.camel.impl.DefaultAsyncProducer;
022import org.apache.camel.util.StopWatch;
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025
026/**
027 * The direct producer.
028 * <p/>
029 * If blocking is enabled ({@code DirectEndpoint#isBlock}) then the DirectEndpoint will create an instance
030 * of this class instead of {@code DirectProducer}.
031 * This producers {@code process} method will block for the configured duration ({@code DirectEndpoint#getTimeout},
032 * default to 30 seconds). After which if a consumer is still unavailable a DirectConsumerNotAvailableException
033 * will be thrown.
034 * <p/>
035 * Implementation note: Concurrent Producers will block for the duration it takes to determine if a
036 * consumer is available, but actual consumer execution will happen concurrently.
037 */
038public class DirectVmBlockingProducer extends DefaultAsyncProducer {
039    private static final Logger LOG = LoggerFactory.getLogger(DirectVmBlockingProducer.class);
040    private final DirectVmEndpoint endpoint;
041
042    public DirectVmBlockingProducer(DirectVmEndpoint endpoint) {
043        super(endpoint);
044        this.endpoint = endpoint;
045    }
046
047    public void process(Exchange exchange) throws Exception {
048        getConsumer(exchange).getProcessor().process(exchange);
049    }
050
051    public boolean process(Exchange exchange, AsyncCallback callback) {
052        try {
053            return getConsumer(exchange).getAsyncProcessor().process(exchange, callback);
054        } catch (Exception e) {
055            exchange.setException(e);
056            callback.done(true);
057            return true;
058        }
059    }
060
061    protected DirectVmConsumer getConsumer(Exchange exchange) throws Exception {
062        DirectVmConsumer answer = endpoint.getConsumer();
063        if (answer == null) {
064            // okay then await until we have a consumer or we timed out
065            answer = awaitConsumer();
066            if (answer == null) {
067                throw new DirectVmConsumerNotAvailableException("No consumers available on endpoint: " + endpoint, exchange);
068            }
069        }
070
071        return answer;
072    }
073
074    private DirectVmConsumer awaitConsumer() throws InterruptedException {
075        DirectVmConsumer answer = null;
076
077        StopWatch watch = new StopWatch();
078        boolean done = false;
079        while (!done) {
080            // sleep a bit to give chance for the consumer to be ready
081            Thread.sleep(500);
082            if (LOG.isDebugEnabled()) {
083                LOG.debug("Waited {} for consumer to be ready", watch.taken());
084            }
085
086            answer = endpoint.getConsumer();
087            if (answer != null) {
088                return answer;
089            }
090            // we are done if we hit the timeout
091            done = watch.taken() >= endpoint.getTimeout();
092        }
093        return answer;
094    }
095
096}