Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package candr.yoclip; import candr.yoclip.annotation.Options; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.text.StrBuilder; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import java.util.Collections; import java.util.LinkedList; import java.util.List; /** * The default implementation of the {@link ParserHelpFactory} API. */ public class DefaultParserHelpFactory<T> implements ParserHelpFactory<T> { protected static final String DEFAULT_HEADER = "Options:"; @Override public String createUsage(ParserOptions<T> optionParameters) { if (null == optionParameters) { throw new IllegalArgumentException("OptionParameters cannot be null."); } int optionCount = 0; boolean hasRequiredOption = false; boolean hasArguments = false; boolean hasRequiredArguments = false; for (final ParserOption<T> optionParameter : optionParameters.get()) { if (optionParameter.isArguments()) { hasArguments = true; if (optionParameter.isRequired()) { hasRequiredArguments = true; } } else { optionCount++; if (optionParameter.isRequired()) { hasRequiredOption = true; } } } final StrBuilder builder = new StrBuilder(); if (optionCount > 0) { if (hasRequiredOption) { builder.append("OPTION"); if (optionCount > 1) { builder.append(" [OPTION ...]"); } } else if (optionCount == 1) { builder.append("[OPTION]"); } else { builder.append("[OPTION [OPTION ...]]"); } } if (hasArguments) { if (builder.length() > 0) { builder.append(' '); } if (hasRequiredArguments) { builder.append("ARGS"); } else { builder.append("[ARGS]"); } } return builder.toString(); } @Override public String getHeaderDescription(ParserOptions<T> optionParameters) { if (null == optionParameters) { throw new IllegalArgumentException("OptionParameters cannot be null."); } String header = optionParameters.getHeader(); if (StringUtils.isEmpty(header)) { header = DEFAULT_HEADER; } return header; } @Override public String getTrailerDescription(ParserOptions<T> optionParameters) { if (null == optionParameters) { throw new IllegalArgumentException("OptionParameters cannot be null."); } return optionParameters.getTrailer(); } @Override public List<Pair<String, String>> getOptionPropertyDescriptions(ParserOption<T> parserOption) { if (null == parserOption) { throw new IllegalArgumentException("ParserOption cannot be null."); } List<Pair<String, String>> propertyDescriptions = parserOption.getPropertyDescriptions(); if (propertyDescriptions.isEmpty()) { return Collections.emptyList(); } List<Pair<String, String>> optionPropertiesHelp = new LinkedList<Pair<String, String>>(); for (final Pair<String, String> propertyDescription : propertyDescriptions) { String synopsis = propertyDescription.getKey(); if (StringUtils.isEmpty(synopsis)) { synopsis = "key"; } String details = propertyDescription.getValue(); if (StringUtils.isEmpty(details)) { details = String.format("An option property value for %s.", parserOption); } optionPropertiesHelp.add(ImmutablePair.of(synopsis, details)); } return optionPropertiesHelp; } @Override public Pair<String, String> getOptionDescription(String prefix, String separator, ParserOption<T> parserOption) { if (null == parserOption) { throw new IllegalArgumentException("ParserOption cannot be null."); } String usage = parserOption.getUsage(); if (StringUtils.isEmpty(usage)) { usage = createParserParameterUsage(prefix, separator, parserOption); } String description = parserOption.getDescription(); if (StringUtils.isEmpty(description)) { description = createParserParameterDescription(parserOption); } return ImmutablePair.of(usage, description); } @Override public String wrap(String text, int width) { return hangingIndentWrap(text, 0, width); } @Override public String hangingIndentWrap(String text, int hangingIndent, int width) { if (StringUtils.isEmpty(text)) { return StringUtils.EMPTY; } // make sure the hanging indent is reasonable hangingIndent = Math.max(hangingIndent, 0); int availableTextWidth = width - hangingIndent; if (availableTextWidth < 1) { final String error = String.format("Indent (%d) too large for width (%d).", hangingIndent, width); throw new OptionsParseException(error); } final StrBuilder builder = new StrBuilder(); // break the string into pieces based on the new line marker boolean builderWhitespaceOnly = true; final String[] lines = StringUtils.splitByWholeSeparatorPreserveAllTokens(text, Options.LINE_BREAK); for (int lineIndex = 0; lineIndex < lines.length; lineIndex++) { // account for the new line markers if (lineIndex > 0) { builder.appendNewLine(); } // for each line make sure it is wrapped to the line width String line = lines[lineIndex]; for (int wrapCount = 0; !StringUtils.isEmpty(line); wrapCount++) { // account for the text being wrapped if (wrapCount > 0) { builder.appendNewLine(); } // once text is added to the builder the line width changes based on the hanging indent int lineWidth; if (builderWhitespaceOnly) { lineWidth = width; builderWhitespaceOnly = false; } else { lineWidth = availableTextWidth; if (hangingIndent > 0) { builder.appendPadding(hangingIndent, ' '); } } if (line.length() <= lineWidth) { builder.append(line); break; } // look for a natural break in the text, otherwise force one int wrapPosition = line.lastIndexOf(' ', lineWidth); if (wrapPosition < 0) { wrapPosition = lineWidth; } builder.append(line.substring(0, wrapPosition)); line = line.substring(wrapPosition).trim(); } } return builder.toString(); } /** * Creates a usage description from the parser parameter. * * @param prefix The parser parameter prefix (see {@link ParserOptions#getPrefix() getPrefix()} for more * information). * @param separator The parser parameter name and value separator (see {@link ParserOptions#getSeparator() * getSeparator()} for more information}. * @param parserOption The parser parameter a usage will be generated for. * @return a usage string for the parser parameter. * @throws IllegalArgumentException if the {@code prefix} or {@code separator} parameter values are empty. * @throws NullPointerException if the parser parameter is null. */ protected String createParserParameterUsage(final String prefix, final String separator, final ParserOption<T> parserOption) { if (StringUtils.isEmpty(prefix)) { throw new IllegalArgumentException("The ParserOption prefix cannot be empty."); } if (StringUtils.isEmpty(separator)) { throw new IllegalArgumentException("The ParserOption separator cannot be empty."); } final StrBuilder usage = new StrBuilder(); if (parserOption.isProperties()) { final String name = parserOption.getNames()[0]; usage.append(prefix).append(name).append("KEY=VALUE"); } else if (parserOption.isArguments()) { usage.append("ARG"); } else { final String[] names = parserOption.getNames(); for (int i = 0; i < names.length; i++) { if (i > 0) { usage.append("|"); } usage.append(prefix).append(names[i]); } if (parserOption.hasValue()) { usage.append(separator); final String typeDescription = ClassUtils.getShortClassName(parserOption.getType()); usage.append(typeDescription.toUpperCase()); } } return usage.toString(); } /** * Creates a description for the parser parameter. * * @param parserOption The parser parameter a description will be created for. * @return a description of the parser parameter. */ protected String createParserParameterDescription(final ParserOption<T> parserOption) { if (null == parserOption) { throw new IllegalArgumentException("ParserOption cannot be null."); } String description; if (parserOption.isProperties()) { description = String.format("Sets a property and value into the '%s' Map field.", parserOption.getUniqueId()); } else if (parserOption.isArguments()) { description = String.format("Sets an argument into the '%s' List field.", parserOption.getUniqueId()); } else { description = String.format("Sets the '%s' field option.", parserOption.getUniqueId()); } if (parserOption.isRequired()) { description = description.concat(" This option is required."); } return description; } }