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.converter;
018
019import java.util.regex.Matcher;
020import java.util.regex.Pattern;
021
022import org.apache.camel.Converter;
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025
026/**
027 * Converter from String syntax to milli seconds.
028 * Code is copied to org.apache.camel.catalog.TimePatternConverter in camel-catalog
029 */
030@Converter
031public final class TimePatternConverter {   
032    private static final Logger LOG = LoggerFactory.getLogger(TimePatternConverter.class);
033    private static final String NUMBERS_ONLY_STRING_PATTERN = "^[-]?(\\d)+$";
034    private static final String HOUR_REGEX_PATTERN = "((\\d)*(\\d))h(our(s)?)?";
035    private static final String MINUTES_REGEX_PATTERN = "((\\d)*(\\d))m(in(ute(s)?)?)?";
036    private static final String SECONDS_REGEX_PATTERN = "((\\d)*(\\d))s(ec(ond)?(s)?)?";
037
038    /**
039     * Utility classes should not have a public constructor.
040     */
041    private TimePatternConverter() {
042    }
043    
044    @Converter
045    public static long toMilliSeconds(String source) throws IllegalArgumentException {
046        long milliseconds = 0;
047        boolean foundFlag = false;
048
049        checkCorrectnessOfPattern(source);
050        Matcher matcher;
051
052        matcher = createMatcher(NUMBERS_ONLY_STRING_PATTERN, source);
053        if (matcher.find()) {
054            // Note: This will also be used for regular numeric strings. 
055            //       This String -> long converter will be used for all strings.
056            milliseconds = Long.valueOf(source);
057        } else {            
058            matcher = createMatcher(HOUR_REGEX_PATTERN, source);
059            if (matcher.find()) {
060                milliseconds = milliseconds + (3600000 * Long.valueOf(matcher.group(1)));
061                foundFlag = true;
062            }
063            
064            matcher = createMatcher(MINUTES_REGEX_PATTERN, source);
065            if (matcher.find()) {
066                long minutes = Long.valueOf(matcher.group(1));
067                if ((minutes > 59) && foundFlag) {
068                    throw new IllegalArgumentException("Minutes should contain a valid value between 0 and 59: " + source);
069                }
070                foundFlag = true;
071                milliseconds = milliseconds + (60000 * minutes);
072            }
073               
074            matcher = createMatcher(SECONDS_REGEX_PATTERN, source);
075            if (matcher.find()) {
076                long seconds = Long.valueOf(matcher.group(1));
077                if ((seconds > 59) && foundFlag) {
078                    throw new IllegalArgumentException("Seconds should contain a valid value between 0 and 59: " + source);
079                }
080                foundFlag = true;
081                milliseconds = milliseconds + (1000 * seconds);
082            }      
083            
084            // No pattern matched... initiating fallback check and conversion (if required). 
085            // The source at this point may contain illegal values or special characters 
086            if (!foundFlag) {
087                milliseconds = Long.valueOf(source);
088            }
089        }       
090        
091        LOG.trace("source: {} milliseconds: ", source, milliseconds);
092        
093        return milliseconds;
094    }
095
096    private static void checkCorrectnessOfPattern(String source) {
097        //replace only numbers once
098        Matcher matcher = createMatcher(NUMBERS_ONLY_STRING_PATTERN, source);
099        String replaceSource = matcher.replaceFirst("");
100
101        //replace hour string once
102        matcher = createMatcher(HOUR_REGEX_PATTERN, replaceSource);
103        if (matcher.find() && matcher.find()) {
104            throw new IllegalArgumentException("Hours should not be specified more then once: " + source);
105        }
106        replaceSource = matcher.replaceFirst("");
107
108        //replace minutes once
109        matcher = createMatcher(MINUTES_REGEX_PATTERN, replaceSource);
110        if (matcher.find() && matcher.find()) {
111            throw new IllegalArgumentException("Minutes should not be specified more then once: " + source);
112        }
113        replaceSource = matcher.replaceFirst("");
114
115        //replace seconds once
116        matcher = createMatcher(SECONDS_REGEX_PATTERN, replaceSource);
117        if (matcher.find() && matcher.find()) {
118            throw new IllegalArgumentException("Seconds should not be specified more then once: " + source);
119        }
120        replaceSource = matcher.replaceFirst("");
121
122        if (replaceSource.length() > 0) {
123            throw new IllegalArgumentException("Illegal characters: " + source);
124        }
125    }
126
127    private static Matcher createMatcher(String regexPattern, String source) {
128        Pattern pattern = Pattern.compile(regexPattern, Pattern.CASE_INSENSITIVE);
129        return pattern.matcher(source);        
130    }    
131}