001    /*
002     * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003     * Copyright (C) 2011 NightLabs Consulting GmbH
004     *
005     * This program is free software: you can redistribute it and/or modify
006     * it under the terms of the GNU Affero General Public License as
007     * published by the Free Software Foundation, either version 3 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU Affero General Public License for more details.
014     *
015     * You should have received a copy of the GNU Affero General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    package org.cumulus4j.keymanager.cli;
019    
020    import org.kohsuke.args4j.CmdLineException;
021    import org.kohsuke.args4j.CmdLineParser;
022    import org.kohsuke.args4j.Option;
023    import org.kohsuke.args4j.OptionDef;
024    import org.kohsuke.args4j.spi.OneArgumentOptionHandler;
025    import org.kohsuke.args4j.spi.Setter;
026    
027    /**
028     * <p>
029     * Option handler implementation to interprete a time period (e.g. "5 minutes".
030     * </p>
031     * <p>
032     * The time period is specified in the command line by writing a number
033     * directly followed (no space!) by a unit. For example 5 minutes could be
034     * written as "5min" or "300s" (300 seconds are 5 minutes).
035     * </p>
036     * <p>
037     * This handler can be chosen for every <code>long</code> property using
038     * the {@link Option} annotation like this:
039     * </p>
040     * <pre>
041     * &#64;Option(name="-myArg", handler=TimePeriodOptionHandler.class)
042     * private long myArg;
043     * </pre>
044     * <p>
045     * The <code>long</code> property will be set to the milliseconds value.
046     * For example, if the command line user passes "5min", the <code>long</code> value
047     * will be 300000 (5 min * 60 s * 1000 ms).
048     * </p>
049     *
050     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
051     */
052    public class TimePeriodOptionHandler extends OneArgumentOptionHandler<Long>
053    {
054            /**
055             * Units based on <a target="_blank" href="http://en.wikipedia.org/wiki/ISO_31-1">ISO 31-1</a> (where it exists).
056             *
057             * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
058             */
059            public static enum Unit {
060                    /**
061                     * Millisecond.
062                     */
063                    ms("Millisecond", 1L),
064    
065                    /**
066                     * Second.
067                     */
068                    s("Second", 1000L),
069    
070                    /**
071                     * Minute.
072                     */
073                    min("Minute", 60L * s.msec),
074    
075                    /**
076                     * Hour.
077                     */
078                    h("Hour", 60L * min.msec),
079    
080                    /**
081                     * Day.
082                     */
083                    d("Day", 24L * h.msec),
084    
085                    /**
086                     * Year. <a target="_blank" href="http://en.wikipedia.org/wiki/Year">Abbreviation from latin "annus".</a>
087                     */
088                    a("Year", 365L * d.msec),
089    
090                    /**
091                     * Year (alternative for convenience).
092                     */
093                    y("Year", 365L * d.msec)
094                    ;
095    
096                    private String displayName;
097                    private long msec;
098    
099                    private Unit(String displayName, long msec)
100                    {
101                            this.displayName = displayName;
102                            this.msec = msec;
103                    }
104    
105                    public long toMSec(long value)
106                    {
107                            return value * msec;
108                    }
109    
110                    public String getDisplayName() {
111                            return displayName;
112                    }
113    
114                    public static String getAllUnitsWithDisplayName()
115                    {
116                            return getAllUnitsWithDisplayName(", ");
117                    }
118    
119                    public static String getAllUnitsWithDisplayName(String separator)
120                    {
121                            return getAllUnitsWithDisplayName("%s (%s)", separator);
122                    }
123    
124                    public static String getAllUnitsWithDisplayName(String unitFormat, String separator)
125                    {
126                            StringBuilder sb = new StringBuilder();
127    
128                            for (Unit u : values()) {
129                                    if (sb.length() > 0)
130                                            sb.append(separator);
131    
132                                    sb.append(String.format(unitFormat, u.name(), u.getDisplayName()));
133                            }
134    
135                            return sb.toString();
136                    }
137            }
138    
139            public TimePeriodOptionHandler(CmdLineParser parser, OptionDef option, Setter<Long> setter)
140            {
141                    super(parser, option, setter);
142            }
143    
144            @Override
145            protected Long parse(String argument) throws NumberFormatException, CmdLineException
146            {
147                    Unit unit = null;
148                    for (Unit u : Unit.values()) {
149                            if (argument.endsWith(u.name()) && (unit == null || unit.name().length() < u.name().length()))
150                                    unit = u;
151                    }
152    
153                    if (unit == null)
154                            throw new CmdLineException(owner, "Argument '" + argument + "' does not end with one of the following unit-suffixes: " + Unit.getAllUnitsWithDisplayName());
155    
156                    String numberVal = argument.substring(0, argument.length() - unit.name().length()).trim();
157                    long valueMSec = Long.parseLong(numberVal);
158                    return unit.toMSec(valueMSec);
159            }
160    
161    }