blob: c7e20d8a006e46301047013dfa3577d2d5bb6043 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
package org.eclipse.mdm.mdfsorter;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import java.util.zip.DataFormatException;
import org.eclipse.mdm.mdfsorter.mdf3.MDF3GenBlock;
import org.eclipse.mdm.mdfsorter.mdf3.MDF3ProcessWriter;
import org.eclipse.mdm.mdfsorter.mdf4.MDF4GenBlock;
import org.eclipse.mdm.mdfsorter.mdf4.MDF4ProcessWriter;
/**
* Main class of this MDF4Sorter, with all publicly accessible interfaces:
* <code>main()</code> for command line use, <code>sortMDF()</code> for java
* use.
*
* @author Tobias Leemann
*
*/
abstract public class MDFSorter {
/**
* Version of this tool as String. (Used in the file Header)
*/
public static final String VERSIONSTRING = "1.0.3";
/**
* The logger for this application
*/
public static Logger log;
/**
* Command-Line Interface of this tool. Please note the following syntax:
*
* @param args
* <br>
* args[0] = Path to the inputfile; <br>
* args[1] = Path were the output shall be written; <br>
* args[2-n] = Flags. the following flags are valid: <br>
* -zip: Zip all Data found. <br>
* -unzip: Unzip all Data found.<br>
* -maxblocksize=Value: Maximum size of a DataBlock. e.g. "200M",
* "3K", "1G"<br>
*
* example call: file1.mf4 file2.mf4 -unzip -maxblocksize=800M
* @throws IOException
* If any in/output errors occur.
*/
public static void main(String[] args) throws IOException {
if (args == null || args.length == 0) {
System.out.println("At least one argument has to be provided.");
printUsage();
} else {
try {
switch (args[0]) {
case "help":
printUsage();
return;
case "check":
ArgumentStruct structchk = ArgumentStruct.parseArgsCheck(args);
checkForProblems(structchk.inputname, structchk.maxblocksize, structchk.unzip);
return;
case "process":
setUpLogging();
ArgumentStruct struct = ArgumentStruct.parseArgs(args);
handleCall(struct);
break;
default:
System.out.println("Unknown command.");
printUsage();
}
} catch (MDFSorterArgException e) {
System.err.println(e.getMessage());
e.printStackTrace();
printUsage();
}
}
}
/**
* PUBLIC: This method processes an MDF4-File. It resolves all Linked Data
* lists and Zipped Data blocks (DZBLOCK) were possible.
*
* @param inputfile
* The Path to the file to be processed.
* @param outputfile
* The Path were the output should be written.
* @param maxblocksize
* maximum size of a data block. (Must not be larger than 4MB if
* unzip==false)
* @param unzip
* True if all data should be unzipped in the output file. False
* if all data should be Zipped (Stored in DZBlocks) in the
* output file.
*/
public static void sortMDF(String inputfile, String outputfile, long maxblocksize, boolean unzip) {
setUpLogging();
ArgumentStruct struct = new ArgumentStruct();
struct.inputname = inputfile;
struct.outputname = outputfile;
struct.maxblocksize = maxblocksize;
struct.unzip = unzip;
// Larger blocks cannot be zipped (see Specification of MDF4.1)
if (!unzip && maxblocksize > 4L * 1024L * 1024L) {
log.log(Level.WARNING, "Setting maxblocksize to 4MB. Larger blocks are not allowed for zipped data.");
struct.maxblocksize = 4L * 1024L * 1024L;
}
handleCall(struct);
}
/**
* PUBLIC: Method to check, it processing of a file is needed, or if the
* file can just be passed to the ODS Server.
*
* @param inputfile
* Path to the input file.
* @param maxblocksize
* The maximum size a block may have.
* @param unzip
* True, if zipped data needs to be unzipped. False, if the file
* can legally contain zipped data blocks.
* @return True, if problems were found in this file. False if no problems
* were found.
* @throws IOException
* (File not found)
*/
public static boolean checkForProblems(String inputfile, long maxblocksize, boolean unzip) throws IOException {
setUpLogging();
// wrap arguments.
ArgumentStruct args = new ArgumentStruct();
args.unzip = unzip;
args.maxblocksize = maxblocksize;
args.inputname = inputfile;
// 2. Check for Problems.
return checkForProblems(args);
}
/**
* PUBLIC: Method to check, it processing of a file is needed, or if the
* file can just be passed to the ODS Server.
*
* @param inputfile
* Path to the input file.
* @param maxblocksize
* True, if zipped data needs to be unzipped. False, if the file
* can legally contain zipped data blocks.
* @return True, if problems were found in this file. False if no problems
* werde found.
* @throws IOException
* (File not found)
*/
public static boolean checkForProblems(String inputfile, long maxblocksize) throws IOException {
return checkForProblems(inputfile, maxblocksize, true);
}
/**
* Internally called Method that really performs the "check" operation.
*
* @param struct
* The Arguments for this call
* @return True, if problems were found, false if not.
* @throws IOException
* If an I/O error occurs.
*/
static boolean checkForProblems(ArgumentStruct struct) throws IOException {
setUpLogging();
FileInputStream bufstream;
bufstream = new FileInputStream(struct.inputname);
log.log(Level.INFO, "File opened.");
// 1. Parse file and get Content-Struct
MDFFileContent<? extends MDFGenBlock> con = MDFParser.serializeFile(bufstream.getChannel());
// 2. Check for Problems.
boolean ret = false;
if (!con.isMDF3()) {
@SuppressWarnings("unchecked")
MDF4ProcessWriter pw = new MDF4ProcessWriter((MDFFileContent<MDF4GenBlock>) con, struct);
ret = pw.checkProblems();
} else {
@SuppressWarnings("unchecked")
MDF3ProcessWriter pw = new MDF3ProcessWriter((MDFFileContent<MDF3GenBlock>) con, struct);
ret = pw.checkProblems();
}
if (ret) {
log.info("Problems were found. Processing file recommended.");
} else {
log.info("No problems were found. This file needn't be processed.");
}
bufstream.close();
return ret;
}
/**
* Internal method called from the Java and the command line interface. Does
* the Main work for the "Process" command.
*
* @param struct
* The Arguments of this program call.
*/
@SuppressWarnings("unchecked")
static void handleCall(ArgumentStruct struct) {
if (struct.verbose) {
log.setLevel(Level.FINE);
log.getHandlers()[0].setLevel(Level.FINE);
}
FileInputStream bufstream;
try {
bufstream = new FileInputStream(struct.inputname);
log.log(Level.INFO, "File opened.");
// 1. Parse file and get Content-Struct
MDFFileContent<? extends MDFGenBlock> con = MDFParser.serializeFile(bufstream.getChannel());
// 2. Init processing and write out
@SuppressWarnings("rawtypes")
MDFAbstractProcessWriter processorwriter;
if (con.isMDF3()) {
processorwriter = new MDF3ProcessWriter((MDFFileContent<MDF3GenBlock>) con, struct);
} else {
processorwriter = new MDF4ProcessWriter((MDFFileContent<MDF4GenBlock>) con, struct);
}
processorwriter.processAndWriteOut();
bufstream.close();
} catch (IOException e) {
System.err.println(e);
log.severe("Aborted. IOException encountered.");
} catch (DataFormatException e) {
e.printStackTrace();
log.severe("Aborted. DataFormatException encountered.");
}
}
/**
* Configures the logger for this application.
*/
static void setUpLogging() {
// Set up logger
log = Logger.getLogger("org.eclipse.mdm.mdfsorter");
log.setUseParentHandlers(false);
for (Handler h : log.getHandlers()) {
if (!(h instanceof MemorizingHandler)) {
log.removeHandler(h);
}
}
// Force immediate output
Handler h = new StreamHandler(System.out, new SimpleFormatter()) {
@Override
public void publish(LogRecord record) {
super.publish(record);
flush();
}
};
log.addHandler(h);
h.setLevel(Level.INFO);
// Do not touch, it is important for testing that all messages are
// logged.
log.setLevel(Level.ALL);
}
/**
* Prints a meaningful usage message.
*/
private static void printUsage() {
System.out.println("Usage: MDF4Sorter <command> [<parameters>]");
System.out.println();
System.out.println("Valid commands are:");
System.out.println("\"process\":");
System.out.println(
"\tProcess an MDF4 file for usage with an ASAM ODS Server.\n\tThis call requires the following parameters:\n\t <inputfile> <outputfile> [<flags>]");
System.out.println("\tInputfile: The MDF4-File to process");
System.out.println("\tOutputfile: The MDF-File where the output will be written.");
System.out.println("\tFlags: Other parameters. Ordering of flags is not important.");
System.out.println("\t\t-zip: Zip all Data found. ");
System.out.println("\t\t-unzip: Unzip all Data found.");
System.out
.println("\t\t-maxblocksize=<Value>: Maximum size of a DataBlock. \n\t\te.g. \"200M\", \"3K\", \"1G\"");
System.out.println("\tExample: process infile.mf4 outfile.mf4 -maxblocksize=20m -zip");
System.out.println("\"check\":");
System.out.println(
"\tCheck if processing an MDF4 file for usage with an ASAM ODS Server\n\tis necessary. This call requires the following parameters:\n\t <inputfile> [<maxblocksize>] [<zipflag>]");
System.out.println("\tInputfile: The MDF4-File to process");
System.out
.println("\t\t-maxblocksize=<Value>: Maximum size of a DataBlock. \n\t\te.g. \"200M\", \"3K\", \"1G\"");
System.out.println(
"\tzipflag: \"-zip\" or \"-unzip\", zip if all data will be zipped,\n\t\tunzipped if all data block will be unzipped.");
System.out.println("\tExample: check infile.mf4 4M -zip");
System.out.println("\"help\":");
System.out.println("\tPrint this info.");
}
}