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 Apache.CLI; 018 019import java.io.File; 020import java.io.FileInputStream; 021import java.net.URL; 022import java.util.Date; 023 024/** 025 * Allows Options to be created from a single String. The pattern contains various single character flags and via an 026 * optional punctuation character, their expected type. 027 * 028 * <BR /><BR />Here is an Overview of PatternOptionBuilder patterns 029 * 030 * <BR /><BR /><TABLE CLASS=JDBriefTable> 031 * <TR> 032 * <TD>a</TD> 033 * <TD>-a flag</TD> 034 * </TR> 035 * <TR> 036 * <TD>b@</TD> 037 * <TD>-b [class name]</TD> 038 * </TR> 039 * <TR> 040 * <TD>c></TD> 041 * <TD>-c [file name]</TD> 042 * </TR> 043 * <TR> 044 * <TD>d+</TD> 045 * <TD>-d [class name] (creates object via empty constructor)</TD> 046 * </TR> 047 * <TR> 048 * <TD>e%</TD> 049 * <TD>-e [number] (creates Double/Long instance depending on existing of a '.')</TD> 050 * </TR> 051 * <TR> 052 * <TD>f/</TD> 053 * <TD>-f [URL]</TD> 054 * </TR> 055 * <TR> 056 * <TD>g:</TD> 057 * <TD>-g [string]</TD> 058 * </TR> 059 * </TABLE> 060 * 061 * <BR />For example, the following allows command line flags of 062 * {@code '-v -p string-value -f /dir/file'}. 063 * 064 * <BR /><BR />The exclamation mark precede a mandatory option. 065 * 066 * <BR /><BR /><DIV CLASS=SNIP>{@code 067 * Options options = PatternOptionBuilder.parsePattern("vp:!f/"); 068 * }</DIV> 069 * 070 * <BR /><BR /><B CLASS=JDDescLabel>Apache Commons To-Do:</B> 071 * 072 * <BR />TO-DO These need to break out to {@code OptionType} and also to be pluggable. 073 */ 074@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="LICENSE") 075public class PatternOptionBuilder 076{ 077 /** String class */ 078 public static final Class<String> STRING_VALUE = String.class; 079 080 /** Object class */ 081 public static final Class<Object> OBJECT_VALUE = Object.class; 082 083 /** Number class */ 084 public static final Class<Number> NUMBER_VALUE = Number.class; 085 086 /** Date class */ 087 public static final Class<Date> DATE_VALUE = Date.class; 088 089 /** Class class */ 090 public static final Class<?> CLASS_VALUE = Class.class; 091 092 /// can we do this one?? 093 // is meant to check that the file exists, else it errors. 094 // ie) it's for reading not writing. 095 096 /** FileInputStream class */ 097 public static final Class<FileInputStream> EXISTING_FILE_VALUE = FileInputStream.class; 098 099 /** File class */ 100 public static final Class<File> FILE_VALUE = File.class; 101 102 /** File array class */ 103 public static final Class<File[]> FILES_VALUE = File[].class; 104 105 /** URL class */ 106 public static final Class<URL> URL_VALUE = URL.class; 107 108 /** 109 * Retrieve the class that {@code ch} represents. 110 * @param ch the specified character 111 * @return The class that {@code ch} represents 112 */ 113 public static Object getValueClass(final char ch) 114 { 115 switch (ch) 116 { 117 case '@': return PatternOptionBuilder.OBJECT_VALUE; 118 case ':': return PatternOptionBuilder.STRING_VALUE; 119 case '%': return PatternOptionBuilder.NUMBER_VALUE; 120 case '+': return PatternOptionBuilder.CLASS_VALUE; 121 case '#': return PatternOptionBuilder.DATE_VALUE; 122 case '<': return PatternOptionBuilder.EXISTING_FILE_VALUE; 123 case '>': return PatternOptionBuilder.FILE_VALUE; 124 case '*': return PatternOptionBuilder.FILES_VALUE; 125 case '/': return PatternOptionBuilder.URL_VALUE; 126 } 127 128 return null; 129 } 130 131 /** 132 * Returns whether {@code ch} is a value code, i.e. whether it represents a class in a pattern. 133 * @param ch the specified character 134 * @return true if {@code ch} is a value code, otherwise false. 135 */ 136 public static boolean isValueCode(final char ch) 137 { 138 return ch == '@' || ch == ':' || ch == '%' || ch == '+' || ch == '#' || ch == '<' || 139 ch == '>' || ch == '*' || ch == '/' || ch == '!'; 140 } 141 142 /** 143 * Returns the {@link Options} instance represented by {@code pattern}. 144 * @param pattern the pattern string 145 * @return The {@link Options} instance 146 */ 147 public static Options parsePattern(final String pattern) 148 { 149 char opt = ' '; 150 boolean required = false; 151 Class<?> type = null; 152 153 final Options options = new Options(); 154 155 for (int i = 0; i < pattern.length(); i++) 156 { 157 final char ch = pattern.charAt(i); 158 159 // a value code comes after an option and specifies 160 // details about it 161 if (!isValueCode(ch)) 162 { 163 if (opt != ' ') 164 { 165 final Option option = Option 166 .builder(String.valueOf(opt)) 167 .hasArg(type != null) 168 .required(required) 169 .type(type) 170 .build(); 171 172 // we have a previous one to deal with 173 options.addOption(option); 174 175 required = false; 176 type = null; 177 } 178 179 opt = ch; 180 } 181 182 else if (ch == '!') required = true; 183 else type = (Class<?>) getValueClass(ch); 184 } 185 186 if (opt != ' ') 187 { 188 final Option option = Option 189 .builder(String.valueOf(opt)) 190 .hasArg(type != null) 191 .required(required) 192 .type(type) 193 .build(); 194 195 // we have a final one to deal with 196 options.addOption(option); 197 } 198 199 return options; 200 } 201}