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.timer;
018
019import java.text.SimpleDateFormat;
020import java.util.Collection;
021import java.util.Date;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.Timer;
025import java.util.concurrent.atomic.AtomicInteger;
026
027import org.apache.camel.Endpoint;
028import org.apache.camel.impl.UriEndpointComponent;
029
030/**
031 * The <a href="http://camel.apache.org/timer.html">Timer Component</a> is for generating message exchanges when a timer fires.
032 *
033 * Represents the component that manages {@link TimerEndpoint}.  It holds the
034 * list of {@link TimerConsumer} objects that are started.
035 *
036 * @version 
037 */
038public class TimerComponent extends UriEndpointComponent {
039    private final Map<String, Timer> timers = new HashMap<>();
040    private final Map<String, AtomicInteger> refCounts = new HashMap<>();
041
042    public TimerComponent() {
043        super(TimerEndpoint.class);
044    }
045
046    public Timer getTimer(TimerConsumer consumer) {
047        String key = consumer.getEndpoint().getTimerName();
048        if (!consumer.getEndpoint().isDaemon()) {
049            key = "nonDaemon:" + key;
050        }
051
052        Timer answer;
053        synchronized (timers) {
054            answer = timers.get(key);
055            if (answer == null) {
056                // the timer name is also the thread name, so lets resolve a name to be used
057                String name = consumer.getEndpoint().getCamelContext().getExecutorServiceManager().resolveThreadName("timer://" + consumer.getEndpoint().getTimerName());
058                answer = new Timer(name, consumer.getEndpoint().isDaemon());
059                timers.put(key, answer);
060                // store new reference counter
061                refCounts.put(key, new AtomicInteger(1));
062            } else {
063                // increase reference counter
064                AtomicInteger counter = refCounts.get(key);
065                if (counter != null) {
066                    counter.incrementAndGet();
067                }
068            }
069        }
070        return answer;
071    }
072
073    public void removeTimer(TimerConsumer consumer) {
074        String key = consumer.getEndpoint().getTimerName();
075        if (!consumer.getEndpoint().isDaemon()) {
076            key = "nonDaemon:" + key;
077        }
078
079        synchronized (timers) {
080            // decrease reference counter
081            AtomicInteger counter = refCounts.get(key);
082            if (counter != null && counter.decrementAndGet() <= 0) {
083                refCounts.remove(key);
084                // remove timer as its no longer in use
085                Timer timer = timers.remove(key);
086                if (timer != null) {
087                    timer.cancel();
088                }
089            }
090        }
091    }
092
093    @Override
094    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
095        TimerEndpoint answer = new TimerEndpoint(uri, this, remaining);
096
097        // convert time from String to a java.util.Date using the supported patterns
098        String time = getAndRemoveOrResolveReferenceParameter(parameters, "time", String.class);
099        String pattern = getAndRemoveOrResolveReferenceParameter(parameters, "pattern", String.class);
100        if (time != null) {
101            SimpleDateFormat sdf;
102            if (pattern != null) {
103                sdf = new SimpleDateFormat(pattern);
104            } else if (time.contains("T")) {
105                sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
106            } else {
107                sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
108            }
109            Date date = sdf.parse(time);
110            answer.setTime(date);
111            answer.setPattern(pattern);
112        }
113
114        setProperties(answer, parameters);
115        return answer;
116    }
117
118    @Override
119    protected void doStop() throws Exception {
120        Collection<Timer> collection = timers.values();
121        for (Timer timer : collection) {
122            timer.cancel();
123        }
124        timers.clear();
125        refCounts.clear();
126    }
127}