001 /*
002 * Copyright 2007 - 2008 JEuclid, http://jeuclid.sf.net
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 /* $Id: Mml2xxx.java,v 06749543c58f 2008/08/22 13:26:52 maxberger $ */
018
019 package net.sourceforge.jeuclid.app;
020
021 import java.io.File;
022 import java.io.IOException;
023 import java.util.ArrayList;
024 import java.util.Arrays;
025 import java.util.List;
026 import java.util.Locale;
027
028 import net.sourceforge.jeuclid.LayoutContext;
029 import net.sourceforge.jeuclid.MutableLayoutContext;
030 import net.sourceforge.jeuclid.context.LayoutContextImpl;
031 import net.sourceforge.jeuclid.context.Parameter;
032 import net.sourceforge.jeuclid.context.typewrapper.EnumTypeWrapper;
033 import net.sourceforge.jeuclid.context.typewrapper.TypeWrapper;
034 import net.sourceforge.jeuclid.converter.Converter;
035 import net.sourceforge.jeuclid.converter.ConverterRegistry;
036
037 import org.apache.commons.cli.CommandLine;
038 import org.apache.commons.cli.GnuParser;
039 import org.apache.commons.cli.HelpFormatter;
040 import org.apache.commons.cli.Option;
041 import org.apache.commons.cli.Options;
042 import org.apache.commons.cli.ParseException;
043 import org.apache.commons.lang.StringUtils;
044
045 /**
046 * Utility class to be used from the command line to call the converters.
047 *
048 * @version $Revision: 06749543c58f $
049 */
050 // CHECKSTYLE:OFF
051 // Data abstraction coupling is too high. But it makes no sense to split up
052 // this class.
053 public final class Mml2xxx {
054 // CHECKSTYLE:ON
055
056 private static final String OUT_FILE_TYPE = "outFileType";
057
058 private static final String DEFAULT_TYPE = "image/png";
059
060 private Mml2xxx() {
061 // Empty on purpose
062 }
063
064 private static Options createOptions() {
065 final Options options = new Options();
066 final Option oft = new Option(Mml2xxx.OUT_FILE_TYPE, true,
067 "output file mime type [default: derived from the target file's extention]"
068 + "; available values are: "
069 + StringUtils.join(ConverterRegistry.getInstance()
070 .getAvailableOutfileTypes().iterator(), ' '));
071 options.addOption(oft);
072 final LayoutContext defaultCtx = LayoutContextImpl
073 .getDefaultLayoutContext();
074 for (final Parameter param : Parameter.values()) {
075 final TypeWrapper typeWrapper = param.getTypeWrapper();
076 final StringBuilder desc = new StringBuilder(param
077 .getOptionDesc());
078 final String defValue = param.toString(defaultCtx
079 .getParameter(param));
080 if (defValue != null) {
081 desc.append(" [default: ").append(defValue).append("]");
082 }
083 final Option o = new Option(param.getOptionName(), true, desc
084 .toString());
085 String argName = param.getTypeWrapper().getValueType()
086 .getSimpleName().toLowerCase(Locale.ENGLISH);
087 if (typeWrapper instanceof EnumTypeWrapper) {
088 argName = StringUtils.join(((EnumTypeWrapper) typeWrapper)
089 .values(), '|');
090 }
091 o.setArgName(argName);
092 options.addOption(o);
093 }
094 return options;
095 }
096
097 /**
098 * Main function for use from scripts.
099 *
100 * @param args
101 * command line arguments.
102 */
103 public static void main(final String[] args) {
104 final Options options = Mml2xxx.createOptions();
105 CommandLine cmdLine = null;
106 try {
107 cmdLine = new GnuParser().parse(options, args);
108
109 final List<String> files = Arrays.asList(cmdLine.getArgs());
110 if (files.size() < 2) {
111 throw new ParseException("Not enough arguments!");
112 }
113 final int sourceCount = files.size() - 1;
114 final File lastFile = new File(files.get(sourceCount));
115 final boolean multi = lastFile.isDirectory();
116 final List<File> sources = Mml2xxx.createListOfSourceFiles(files,
117 sourceCount);
118
119 final MutableLayoutContext ctx = Mml2xxx
120 .createLayoutContext(cmdLine);
121 if (multi) {
122 Mml2xxx.convertMultipleFiles(cmdLine, lastFile, sources, ctx);
123 } else {
124 if (sources.size() != 1) {
125 throw new ParseException(
126 "Too many file arguments. Did you want to add a target directory?");
127 }
128 final String outFileType = Mml2xxx.findOutfileType(cmdLine,
129 lastFile.getName());
130 Converter.getInstance().convert(sources.get(0), lastFile,
131 outFileType, ctx);
132 }
133 } catch (final ParseException pe) {
134 System.err.println(pe);
135 Mml2xxx.showUsage(options);
136 System.exit(1);
137 } catch (final IOException ioe) {
138 System.err.println("Error encountered during converion process");
139 ioe.printStackTrace(System.err);
140 System.exit(2);
141 } catch (final IllegalArgumentException iae) {
142 System.err.println(iae);
143 Mml2xxx.showUsage(options);
144 System.exit(1);
145 }
146 }
147
148 private static void convertMultipleFiles(final CommandLine cmdLine,
149 final File lastFile, final List<File> sources,
150 final MutableLayoutContext layoutContext) throws ParseException,
151 IOException {
152 final String outFileType = Mml2xxx.findOutfileType(cmdLine, null);
153 for (final File source : sources) {
154 final String fileName = source.getName();
155 final int dotpos = fileName.lastIndexOf('.');
156 final String baseName;
157 if (dotpos >= 0) {
158 baseName = fileName.substring(0, dotpos);
159 } else {
160 baseName = fileName;
161 }
162 final File target = new File(lastFile, baseName
163 + '.'
164 + ConverterRegistry.getInstance().getSuffixForMimeType(
165 outFileType));
166 Converter.getInstance().convert(source, target, outFileType,
167 layoutContext);
168 }
169 }
170
171 private static List<File> createListOfSourceFiles(
172 final List<String> files, final int count) throws ParseException {
173 final List<File> sources = new ArrayList<File>(count);
174 for (int i = 0; i < count; i++) {
175 final String current = files.get(i);
176 final File source = new File(current);
177 if (!source.isFile() || !source.canRead()) {
178 throw new ParseException(current
179 + " is not a file or not readable");
180 }
181 sources.add(source);
182 }
183 return sources;
184 }
185
186 private static String findOutfileType(final CommandLine cmdLine,
187 final String fileName) throws ParseException {
188 String outFileType = cmdLine.getOptionValue(Mml2xxx.OUT_FILE_TYPE);
189 final String isNotSupported = " is not supported";
190 if ((outFileType == null) && (fileName != null)) {
191 final int dot = fileName.lastIndexOf('.');
192 if (dot != -1 && dot != fileName.length() - 1) {
193 final String extension = fileName.substring(dot + 1);
194 outFileType = ConverterRegistry.getInstance()
195 .getMimeTypeForSuffix(extension);
196 }
197 }
198 if (outFileType == null) {
199 System.out.println("No ouput type could be detected, assuming "
200 + Mml2xxx.DEFAULT_TYPE);
201 outFileType = Mml2xxx.DEFAULT_TYPE;
202 } else {
203 if (!ConverterRegistry.getInstance().getAvailableOutfileTypes()
204 .contains(outFileType)) {
205 throw new IllegalArgumentException("Output type "
206 + outFileType + isNotSupported);
207 }
208 }
209 return outFileType;
210 }
211
212 private static MutableLayoutContext createLayoutContext(
213 final CommandLine cmdLine) {
214 final MutableLayoutContext ctx = new LayoutContextImpl(
215 LayoutContextImpl.getDefaultLayoutContext());
216 for (final Parameter param : Parameter.values()) {
217 final String value = cmdLine
218 .getOptionValue(param.getOptionName());
219 if (value != null) {
220 ctx.setParameter(param, param.fromString(value));
221 }
222 }
223 return ctx;
224 }
225
226 private static void showUsage(final Options options) {
227 final HelpFormatter hf = new HelpFormatter();
228 final String lineSep = hf.getNewLine();
229 hf
230 .printHelp(
231 "mml2xxx <source file(s)> <target file/directory> [options]",
232 "source is the path to the source file (MathML or ODF format)"
233 + lineSep
234 + "target is the path to the target file / directory"
235 + lineSep
236 + "If multiple source files are given, target must be a directory",
237 options,
238 "Example: mml2xxx a.mml a.png -backgroundColor white");
239 }
240
241 }