package geniusweb.logconverter; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import org.apache.commons.cli.BasicParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import geniusweb.actions.PartyId; import geniusweb.protocol.NegoState; import geniusweb.protocol.session.SessionResult; import tudelft.utilities.logging.Reporter; /** * Utility class with command line options and main program. Converts a * NegoState into a file (CSV, JSON) with utilities for each session. Contacts * the actual profileservers/profile files to do so. */ public class Convert { private static final String JSON = ".json"; private final static ObjectMapper jackson = new ObjectMapper(); private final Reporter reporter; private final File source; private final File output; private final Format format; /** * How {@link SessionResultWithUtils} is written to the output */ enum Format { CSV, // for each party write sessionnr, partyname, profilename, final // util JSON // jackson serializes it }; /** * @param sourcedir a directory or file to convert. If directory, converts * all json files in the dir. * @param level the debug {@link Level}. Debug messages at or above this * level go to stderr. * @param outputf the output file or directory to write results to. null= * write to stdout. If output=file then input must be also * a single file. * @throws IOException * @throws JsonMappingException * @throws JsonParseException */ public Convert(File source, Level level, File outputf, Format format, Reporter reporter) throws JsonParseException, JsonMappingException, IOException { this.source = source; this.format = format; this.output = outputf; this.reporter = reporter; if (outputf != null) { if (outputf.exists()) { if (!outputf.isDirectory()) throw new IOException("Output " + outputf + " exists but is not a directory"); if (!outputf.canWrite()) throw new IOException("" + outputf + " is write protected"); } if (source.isDirectory() && !outputf.isDirectory()) throw new IOException( "Source is a directory, output must also be a directory but got " + output); } if (source.isDirectory()) { File filesList[] = source.listFiles(); for (File file : filesList) { if (file.getName().endsWith(JSON)) { output(file, convertFile(file)); } } } else { output(source, convertFile(source)); } } /** * Writes converted file to the {@link #output}, or stdout if null. The * destination file will match the source file. Destination file must not * exist. * * If {@link #output} is a dir , the name of the source file is used for the * destination file. The extension is replaced with {@link #format}. * * @param src the source {@link File}. May be used to generate output * filename. * @param res the result to write to the output. */ private void output(File src, List res) { String text = ""; switch (format) { case CSV: text = "session,party,profile,utility\n"; long sessionnr = 0; for (SessionResultWithUtils r : res) { for (PartyId party : r.getParticipants().keySet()) { text = text + "" + sessionnr + "," + r.getParticipants().get(party).getParty() .getPartyRef().getURI() + "," + r.getParticipants().get(party).getProfile() .getURI() + "," + r.getUtilities().get(party) + "\n"; } sessionnr++; } break; case JSON: try { text = jackson.writeValueAsString(res); } catch (JsonProcessingException e) { reporter.log(Level.SEVERE, fullMessage("Failed to convert result to json:", e)); } } if (output == null) { System.out.println(text); } else { File outfile; if (output.exists()) { // must be dir String destfilename = src.getName(); if (destfilename.endsWith(JSON)) { destfilename = destfilename.substring(0, destfilename.length() - 4) + format; } outfile = new File(output.getAbsolutePath(), destfilename); } else { // we assume output is just the file to write to. outfile = output; } try { if (outfile.exists()) throw new IOException( "destination file already exists:" + outfile); BufferedWriter writer = new BufferedWriter( new FileWriter(outfile)); writer.write(text); writer.close(); } catch (IOException e) { reporter.log(Level.SEVERE, fullMessage( "Failed to write result to file " + outfile, e)); } } } /** @return all messages from stacktraces */ private String fullMessage(String msg, Throwable e) { while (e != null) { msg = msg + ":" + e.getMessage(); e = e.getCause(); } return msg; } private List convertFile(File file) throws JsonParseException, JsonMappingException, IOException { NegoState state = jackson.readValue(file, NegoState.class); List results = new LinkedList<>(); for (SessionResult res : state.getResults()) { results.add(SessionResultWithUtils.create(res, reporter)); } return results; } /** * * @param args first arg must be folder containing .json files containing * NegoState objects. All objects are parsed, getResults() is * called, and all results are converted to * SessionResultWithUtils. */ public static void main(String[] args) { CommandLineParser parser = new BasicParser(); // use to read Command Line Arguments HelpFormatter formatter = new HelpFormatter(); // // Use to Format CommandLine cmd = null; Options options = getOpts(); try { cmd = parser.parse(options, args); // it will parse according to the // options and parse option // value String source = cmd.getOptionValue("source"); String output = cmd.getOptionValue("output"); Level level = Level.parse(cmd.getOptionValue("level", "WARNING")); Format format = Format .valueOf(cmd.getOptionValue("format", "JSON")); new Convert(new File(source), level, output == null ? null : new File(output), format, new StdOutReporter(level)); } catch (ParseException e) { System.out.println(e.getMessage()); formatter.printHelp("Convert", options); } catch (IOException e) { e.printStackTrace(); } } private static Options getOpts() { Options options = new Options(); // Options Arguments which are // Acceptable By Program. Option source = new Option("s", "source", true, "source file path. If dir, all json files in the dir are converted"); source.setRequired(true); options.addOption(source); Option destination = new Option("o", "output", true, "Destination file/dir (must exist and be writable; must be dir if source is dir)"); options.addOption(destination); Option debuglevel = new Option("l", "debuglevel", true, "Debug level (WARNING, SEVERE, INFO, FINE, FINEST) "); options.addOption(debuglevel); Option format = new Option("f", "format", true, "output format " + Arrays.toString(Format.values())); options.addOption(format); return options; } } class StdOutReporter implements Reporter { private final Level level; public StdOutReporter(Level level) { this.level = level; } @Override public void log(Level level, String msg) { if (level.intValue() >= this.level.intValue()) System.err.println(level + ":" + msg); } @Override public void log(Level arg0, String msg, Throwable arg2) { log(arg0, msg); } }