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 }