1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  package cz.hobrasoft.pdfmu;
18  
19  import static cz.hobrasoft.pdfmu.error.ErrorType.INPUT_NOT_FOUND;
20  import static cz.hobrasoft.pdfmu.error.ErrorType.PARSER_EXPECTED_ONE_ARGUMENT;
21  import static cz.hobrasoft.pdfmu.error.ErrorType.PARSER_INVALID_CHOICE;
22  import static cz.hobrasoft.pdfmu.error.ErrorType.PARSER_TOO_FEW_ARGUMENTS;
23  import static cz.hobrasoft.pdfmu.error.ErrorType.PARSER_UNKNOWN;
24  import static cz.hobrasoft.pdfmu.error.ErrorType.PARSER_UNRECOGNIZED_ARGUMENT;
25  import static cz.hobrasoft.pdfmu.error.ErrorType.PARSER_UNRECOGNIZED_COMMAND;
26  import cz.hobrasoft.pdfmu.operation.Operation;
27  import cz.hobrasoft.pdfmu.operation.OperationAttach;
28  import cz.hobrasoft.pdfmu.operation.OperationException;
29  import cz.hobrasoft.pdfmu.operation.OperationInspect;
30  import cz.hobrasoft.pdfmu.operation.metadata.OperationMetadataSet;
31  import cz.hobrasoft.pdfmu.operation.signature.OperationSignatureAdd;
32  import cz.hobrasoft.pdfmu.operation.version.OperationVersionSet;
33  import java.io.IOException;
34  import java.io.InputStream;
35  import static java.nio.charset.StandardCharsets.US_ASCII;
36  import java.util.ArrayList;
37  import java.util.Arrays;
38  import java.util.HashSet;
39  import java.util.LinkedHashMap;
40  import java.util.Map;
41  import java.util.Properties;
42  import java.util.Set;
43  import java.util.logging.LogManager;
44  import java.util.logging.Logger;
45  import net.sourceforge.argparse4j.ArgumentParsers;
46  import net.sourceforge.argparse4j.impl.Arguments;
47  import net.sourceforge.argparse4j.inf.ArgumentParser;
48  import net.sourceforge.argparse4j.inf.ArgumentParserException;
49  import net.sourceforge.argparse4j.inf.Namespace;
50  import net.sourceforge.argparse4j.inf.Subparsers;
51  import net.sourceforge.argparse4j.internal.HelpScreenException;
52  import net.sourceforge.argparse4j.internal.UnrecognizedArgumentException;
53  import net.sourceforge.argparse4j.internal.UnrecognizedCommandException;
54  import org.apache.commons.io.IOUtils;
55  
56  
57  
58  
59  
60  
61  public class Main {
62  
63      private static void disableLoggers() {
64          
65          LogManager.getLogManager().reset(); 
66      }
67  
68      private static final Logger logger = Logger.getLogger(Main.class.getName());
69  
70      static {
71          
72          
73          
74          
75          
76          System.setProperty("java.util.logging.SimpleFormatter.format", "%4$s: %5$s%n");
77      }
78  
79      private static ArgumentParser createBasicParser() {
80          
81          ArgumentParser parser = ArgumentParsers.newArgumentParser("pdfmu")
82                  .description("PDF Manipulation Utility")
83                  .defaultHelp(true);
84  
85          parser.version(getProjectVersion());
86          parser.addArgument("-v", "--version")
87                  .help("show version and exit")
88                  .action(Arguments.version());
89  
90          parser.addArgument("--legal-notice")
91                  .help("show legal notice and exit")
92                  .action(new PrintAndExitAction(getLegalNotice()));
93  
94          
95          parser.addArgument("--output-format")
96                  .choices("text", "json")
97                  .setDefault("text")
98                  .type(String.class)
99                  .help("format of stderr output");
100 
101         return parser;
102     }
103 
104     private static final String POM_PROPERTIES_RESOURCE_NAME = "pom.properties";
105     private static final Properties POM_PROPERTIES = new Properties();
106 
107     private static void loadPomProperties() {
108         ClassLoader classLoader = Main.class.getClassLoader();
109         InputStream in = classLoader.getResourceAsStream(POM_PROPERTIES_RESOURCE_NAME);
110         if (in != null) {
111             try {
112                 POM_PROPERTIES.load(in);
113             } catch (IOException ex) {
114                 logger.severe(String.format("Could not load the POM properties file: %s", ex));
115             }
116             try {
117                 in.close();
118             } catch (IOException ex) {
119                 logger.severe(String.format("Could not close the POM properties file: %s", ex));
120             }
121         } else {
122             logger.severe("Could not open the POM properties file.");
123         }
124     }
125 
126     private static final String LEGAL_NOTICE_RESOURCE_NAME = "cz/hobrasoft/pdfmu/legalNotice.txt";
127     private static String legalNotice;
128 
129     private static void loadLegalNotice() {
130         ClassLoader classLoader = Main.class.getClassLoader();
131         InputStream in = classLoader.getResourceAsStream(LEGAL_NOTICE_RESOURCE_NAME);
132         if (in != null) {
133             try {
134                 legalNotice = IOUtils.toString(in, US_ASCII);
135             } catch (IOException ex) {
136                 logger.severe(String.format("Could not load the legal notice file: %s", ex));
137             }
138             try {
139                 in.close();
140             } catch (IOException ex) {
141                 logger.severe(String.format("Could not close the legal notice file: %s", ex));
142             }
143         } else {
144             logger.severe("Could not open the legal notice file.");
145         }
146     }
147 
148     static {
149         loadPomProperties();
150         loadLegalNotice();
151         assert legalNotice != null;
152     }
153 
154     public static String getProjectVersion() {
155         return POM_PROPERTIES.getProperty("projectVersion");
156     }
157 
158     public static String getProjectCopyright() {
159         return POM_PROPERTIES.getProperty("copyright");
160     }
161 
162     public static String getLegalNotice() {
163         return String.format("%1$s\n\n%2$s", getProjectCopyright(), legalNotice);
164     }
165 
166     
167 
168 
169 
170 
171 
172 
173     private static ArgumentParser createFullParser(Map<String, Operation> operations) {
174         
175         ArgumentParser parser = createBasicParser();
176 
177         
178         Subparsers subparsers = parser.addSubparsers()
179                 .title("operations")
180                 .metavar("OPERATION")
181                 .help("operation to execute")
182                 .dest("operation");
183 
184         
185         for (Map.Entry<String, Operation> e : operations.entrySet()) {
186             String name = e.getKey();
187             Operation operation = e.getValue();
188             operation.configureSubparser(subparsers.addParser(name));
189         }
190 
191         return parser;
192     }
193 
194     private static OperationException apeToOe(ArgumentParserException e) {
195         Set<ExceptionMessagePattern> patterns = new HashSet<>();
196 
197         patterns.add(new ExceptionMessagePattern(INPUT_NOT_FOUND,
198                 "argument (?<argument>.*): Insufficient permissions to read file: \'(?<file>.*)\'",
199                 Arrays.asList(new String[]{"argument", "file"})));
200 
201         
202         patterns.add(new ExceptionMessagePattern(PARSER_UNRECOGNIZED_ARGUMENT,
203                 "unrecognized arguments: '(?<argument>.*)'",
204                 Arrays.asList(new String[]{"argument"})));
205 
206         
207         patterns.add(new ExceptionMessagePattern(PARSER_INVALID_CHOICE,
208                 "argument (?<argument>.*): invalid choice: '(?<choice>.*)' \\(choose from \\{(?<validChoices>.*)\\}\\)",
209                 Arrays.asList(new String[]{"argument", "choice", "validChoices"})));
210 
211         
212         patterns.add(new ExceptionMessagePattern(PARSER_UNRECOGNIZED_COMMAND,
213                 "invalid choice: '(?<command>.*)' \\(choose from (?<validCommands>.*)\\)",
214                 Arrays.asList(new String[]{"command", "validCommands"})));
215 
216         
217         patterns.add(new ExceptionMessagePattern(PARSER_TOO_FEW_ARGUMENTS,
218                 "too few arguments",
219                 new ArrayList<String>()));
220 
221         patterns.add(new ExceptionMessagePattern(PARSER_EXPECTED_ONE_ARGUMENT,
222                 "argument (?<argument>.*): expected one argument",
223                 Arrays.asList(new String[]{"argument"})));
224 
225         OperationException oe = null;
226         for (ExceptionMessagePattern p : patterns) {
227             oe = p.getOperationException(e);
228             if (oe != null) {
229                 break;
230             }
231         }
232 
233         if (oe == null) {
234             
235             oe = new OperationException(PARSER_UNKNOWN, e);
236         }
237 
238         assert oe != null;
239         return oe;
240     }
241 
242     
243 
244 
245 
246 
247     public static void main(String[] args) {
248         int exitStatus = 0; 
249 
250         
251         Map<String, Operation> operations = new LinkedHashMap<>();
252         operations.put("inspect", OperationInspect.getInstance());
253         operations.put("update-version", OperationVersionSet.getInstance());
254         operations.put("update-properties", OperationMetadataSet.getInstance());
255         operations.put("attach", OperationAttach.getInstance());
256         operations.put("sign", OperationSignatureAdd.getInstance());
257 
258         
259         ArgumentParser parser = createFullParser(operations);
260 
261         
262         Namespace namespace = null;
263         try {
264             
265             
266             
267             
268             
269             namespace = parser.parseArgs(args);
270         } catch (HelpScreenException e) {
271             parser.handleError(e); 
272         } catch (UnrecognizedCommandException e) {
273             exitStatus = PARSER_UNRECOGNIZED_COMMAND.getCode();
274             parser.handleError(e); 
275         } catch (UnrecognizedArgumentException e) {
276             exitStatus = PARSER_UNRECOGNIZED_ARGUMENT.getCode();
277             parser.handleError(e); 
278         } catch (ArgumentParserException ape) {
279             OperationException oe = apeToOe(ape);
280             exitStatus = oe.getCode();
281             
282             
283             
284 
285             parser.handleError(ape); 
286         }
287 
288         if (namespace == null) {
289             System.exit(exitStatus);
290         }
291 
292         assert exitStatus == 0;
293 
294         
295         WritingMapper wm = null;
296 
297         
298         String operationName = namespace.getString("operation");
299         assert operationName != null; 
300 
301         
302         assert operations.containsKey(operationName); 
303         Operation operation = operations.get(operationName);
304         assert operation != null;
305 
306         
307         String outputFormat = namespace.getString("output_format");
308         switch (outputFormat) {
309             case "json":
310                 
311                 disableLoggers();
312                 
313                 wm = new WritingMapper();
314                 operation.setWritingMapper(wm); 
315                 break;
316             case "text":
317                 
318                 TextOutput to = new TextOutput(System.err); 
319                 operation.setTextOutput(to); 
320                 break;
321             default:
322                 assert false; 
323         }
324 
325         
326         try {
327             operation.execute(namespace);
328         } catch (OperationException ex) {
329             exitStatus = ex.getCode();
330 
331             
332             logger.severe(ex.getLocalizedMessage());
333             Throwable cause = ex.getCause();
334             if (cause != null && cause.getMessage() != null) {
335                 logger.severe(cause.getLocalizedMessage());
336             }
337 
338             if (wm != null) {
339                 
340                 ex.writeInWritingMapper(wm);
341             }
342         }
343         System.exit(exitStatus);
344     }
345 }