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     */
017    package org.apache.commons.cli2.builder;
018    
019    import java.util.Iterator;
020    import java.util.LinkedHashSet;
021    import java.util.Set;
022    
023    import org.apache.commons.cli2.Argument;
024    import org.apache.commons.cli2.Option;
025    import org.apache.commons.cli2.validation.ClassValidator;
026    import org.apache.commons.cli2.validation.DateValidator;
027    import org.apache.commons.cli2.validation.FileValidator;
028    import org.apache.commons.cli2.validation.NumberValidator;
029    import org.apache.commons.cli2.validation.UrlValidator;
030    import org.apache.commons.cli2.validation.Validator;
031    
032    /**
033     * Builds Options using a String pattern
034     */
035    //TODO Document and link to the acceptable patterns
036    public class PatternBuilder {
037    
038        private final GroupBuilder gbuilder;
039        private final DefaultOptionBuilder obuilder;
040        private final ArgumentBuilder abuilder;
041    
042        /**
043         * Creates a new PatternBuilder
044         */
045        public PatternBuilder() {
046            this(
047                new GroupBuilder(),
048                new DefaultOptionBuilder(),
049                new ArgumentBuilder());
050        }
051    
052        /**
053         * Creates a new PatternBuilder
054         * @param gbuilder the GroupBuilder to use
055         * @param obuilder the DefaultOptionBuilder to use
056         * @param abuilder the ArgumentBuilder to use
057         */
058        public PatternBuilder(
059            final GroupBuilder gbuilder,
060            final DefaultOptionBuilder obuilder,
061            final ArgumentBuilder abuilder) {
062            this.gbuilder = gbuilder;
063            this.obuilder = obuilder;
064            this.abuilder = abuilder;
065        }
066    
067        private final Set options = new LinkedHashSet();
068    
069        /**
070         * Creates a new Option instance.
071         * @return a new Option instance
072         */
073        public Option create() {
074            final Option option;
075    
076            if (options.size() == 1) {
077                option = (Option)options.iterator().next();
078            }
079            else {
080                gbuilder.reset();
081                for (final Iterator i = options.iterator(); i.hasNext();) {
082                    gbuilder.withOption((Option)i.next());
083                }
084                option = gbuilder.create();
085            }
086    
087            reset();
088    
089            return option;
090        }
091    
092        /**
093         * Resets this builder.
094         * @return this builder
095         */
096        public PatternBuilder reset() {
097            options.clear();
098            return this;
099        }
100    
101        private void createOption(
102            final char type,
103            final boolean required,
104            final char opt) {
105            final Argument argument;
106            if (type != ' ') {
107                abuilder.reset();
108                abuilder.withValidator(validator(type));
109                if (required) {
110                    abuilder.withMinimum(1);
111                }
112                if (type != '*') {
113                    abuilder.withMaximum(1);
114                }
115                argument = abuilder.create();
116            }
117            else {
118                argument = null;
119            }
120    
121            obuilder.reset();
122            obuilder.withArgument(argument);
123            obuilder.withShortName(String.valueOf(opt));
124            obuilder.withRequired(required);
125    
126            options.add(obuilder.create());
127        }
128    
129        /**
130         * Builds an Option using a pattern string.
131         * @param pattern the pattern to build from
132         */
133        public void withPattern(final String pattern) {
134            int sz = pattern.length();
135    
136            char opt = ' ';
137            char ch = ' ';
138            char type = ' ';
139            boolean required = false;
140    
141            for (int i = 0; i < sz; i++) {
142                ch = pattern.charAt(i);
143    
144                switch (ch) {
145                    case '!' :
146                        required = true;
147                        break;
148                    case '@' :
149                    case ':' :
150                    case '%' :
151                    case '+' :
152                    case '#' :
153                    case '<' :
154                    case '>' :
155                    case '*' :
156                    case '/' :
157                        type = ch;
158                        break;
159                    default :
160                        if (opt != ' ') {
161                            createOption(type, required, opt);
162                            required = false;
163                            type = ' ';
164                        }
165    
166                        opt = ch;
167                }
168            }
169    
170            if (opt != ' ') {
171                createOption(type, required, opt);
172            }
173        }
174    
175        private static Validator validator(final char c) {
176            switch (c) {
177                case '@' :
178                    final ClassValidator classv = new ClassValidator();
179                    classv.setInstance(true);
180                    return classv;
181                case '+' :
182                    final ClassValidator instancev = new ClassValidator();
183                    return instancev;
184                    //case ':':// no validator needed for a string
185                case '%' :
186                    return NumberValidator.getNumberInstance();
187                case '#' :
188                    return DateValidator.getDateInstance();
189                case '<' :
190                    final FileValidator existingv = new FileValidator();
191                    existingv.setExisting(true);
192                    existingv.setFile(true);
193                    return existingv;
194                case '>' :
195                case '*' :
196                    return new FileValidator();
197                case '/' :
198                    return new UrlValidator();
199                default :
200                    return null;
201            }
202        }
203    }