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