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 org.apache.openmeetings.cli; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionGroup; import org.apache.commons.cli.Options; public class OmHelpFormatter extends HelpFormatter { private static String GENERAL_OPTION_GROUP = ""; private int maxPrefixLength = 0; @SuppressWarnings("unchecked") private static List<OmOption> getReqOptions(Options opts) { //suppose we have only 1 group (for now) OptionGroup g = ((List<OptionGroup>) opts.getRequiredOptions()).get(0); List<OmOption> result = new ArrayList<OmOption>(); for (Option o : g.getOptions()) { result.add((OmOption) o); } Collections.sort(result, new Comparator<OmOption>() { @Override public int compare(OmOption o1, OmOption o2) { return o1.getOrder() - o2.getOrder(); } }); return result; } private LinkedHashMap<String, List<OmOption>> getOptions(Options opts, int leftPad) { final String longOptSeparator = " "; final String lpad = createPadding(leftPad); final String lpadParam = createPadding(leftPad + 2); List<OmOption> reqOptions = getReqOptions(opts); LinkedHashMap<String, List<OmOption>> map = new LinkedHashMap<String, List<OmOption>>(reqOptions.size()); map.put(GENERAL_OPTION_GROUP, new ArrayList<OmOption>()); for (OmOption o : reqOptions) { map.put(o.getOpt(), new ArrayList<OmOption>()); } for (Option _o : opts.getOptions()) { OmOption o = (OmOption) _o; //TODO need better check (required option should go first and should not be duplicated boolean skipOption = map.containsKey(o.getOpt()); boolean mainOption = skipOption || o.getGroup() == null; // first create list containing only <lpad>-a,--aaa where // -a is opt and --aaa is long opt; in parallel look for // the longest opt string this list will be then used to // sort options ascending StringBuilder optBuf = new StringBuilder(); if (o.getOpt() == null) { optBuf.append(mainOption ? lpad : lpadParam).append(" ").append(getLongOptPrefix()) .append(o.getLongOpt()); } else { optBuf.append(mainOption ? lpad : lpadParam).append(getOptPrefix()).append(o.getOpt()); if (o.hasLongOpt()) { optBuf.append(',').append(getLongOptPrefix()).append(o.getLongOpt()); } } if (o.hasArg()) { String argName = o.getArgName(); if (argName != null && argName.length() == 0) { // if the option has a blank argname optBuf.append(' '); } else { optBuf.append(o.hasLongOpt() ? longOptSeparator : " "); optBuf.append("<").append(argName != null ? o.getArgName() : getArgName()).append(">"); } } o.setHelpPrefix(optBuf); maxPrefixLength = Math.max(optBuf.length(), maxPrefixLength); if (skipOption) { //TODO need better check (required option should go first and should not be duplicated continue; } String grp = o.getGroup(); grp = grp == null ? GENERAL_OPTION_GROUP : grp; String[] grps = grp.split(","); for (String g : grps) { map.get(g).add(o); } } for (Map.Entry<String, List<OmOption>> me : map.entrySet()) { final String key = me.getKey(); List<OmOption> options = me.getValue(); Collections.sort(options, new Comparator<OmOption>() { @Override public int compare(OmOption o1, OmOption o2) { boolean o1opt = !o1.isOptional(key); boolean o2opt = !o2.isOptional(key); return (o1opt && o2opt || !o1opt && !o2opt) ? (o1.getOpt() == null ? 1 : -1) : (o1opt ? -1 : 1); } }); if (opts.hasOption(key)) { options.add(0, (OmOption) opts.getOption(key)); } } return map; } private static StringBuilder getReqOptionsString(Options opts) { String delim = ""; StringBuilder result = new StringBuilder(); for (Option o : getReqOptions(opts)) { result.append(delim).append("-").append(o.getOpt()); delim = "|"; } return result; } @Override protected StringBuffer renderOptions(StringBuffer sb, int width, Options options, int leftPad, int descPad) { final String dpad = createPadding(descPad); final String optional = "(optional) "; LinkedHashMap<String, List<OmOption>> optList = getOptions(options, leftPad); char[] delimiter = new char[width - 2]; Arrays.fill(delimiter, '-'); for (Entry<String, List<OmOption>> me : optList.entrySet()) { if (GENERAL_OPTION_GROUP.equals(me.getKey())) { sb.append("General options:").append(getNewLine()); } for (OmOption option : me.getValue()) { StringBuilder optBuf = new StringBuilder(option.getHelpPrefix()); if (optBuf.length() < maxPrefixLength) { optBuf.append(createPadding(maxPrefixLength - optBuf.length())); } optBuf.append(dpad); int nextLineTabStop = maxPrefixLength + descPad; if (option.isOptional(me.getKey())) { optBuf.append(optional); } if (option.getDescription() != null) { optBuf.append(option.getDescription()); } renderWrappedText(sb, width, nextLineTabStop, optBuf.toString()); sb.append(getNewLine()); } sb.append(delimiter).append(getNewLine()); } return sb; } @Override public void printHelp(PrintWriter pw, int width, String cmdLineSyntax, String header, Options options, int leftPad, int descPad, String footer, boolean autoUsage) { if ((cmdLineSyntax == null) || (cmdLineSyntax.length() == 0)) { throw new IllegalArgumentException("cmdLineSyntax not provided"); } printUsage(pw, width, cmdLineSyntax, options); if ((header != null) && (header.trim().length() > 0)) { printWrapped(pw, width, header); } printOptions(pw, width, options, leftPad, descPad); if ((footer != null) && (footer.trim().length() > 0)) { printWrapped(pw, width, footer); } } @Override public void printUsage(PrintWriter pw, int width, String app, Options opts) { pw.println(String.format("usage: %1$s [%2$s] [options]", app, getReqOptionsString(opts))); } }