blob: 1fae547ac9188474ffaf374a15700d8aaab0748d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010-2014, Abel Hegedus, Istvan Rath and Daniel Varro
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Abel Hegedus - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra.modelobfuscator.application.common;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.viatra.modelobfuscator.xml.XMLModelObfuscator;
import org.eclipse.viatra.modelobfuscator.xml.XMLModelObfuscatorBuilder;
import org.eclipse.viatra.modelobfuscator.xml.XMLSchemaConfiguration;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
/**
* @author Abel Hegedus
*
*/
public class ModelObfuscatorHeadless {
/*
* Command line parameters
*/
private static String configParam = "-c";
private static String configLongParam = "--config";
private static String seedParam = "-s";
private static String saltParam = "--salt";
/*
* Property keys
*/
private static final String PROPERTY_PREFIX = "org.eclipse.viatra.modelobfuscator/";
private static final String OBFUSCATION_MODE_PROPERTY = PROPERTY_PREFIX + "mode";
private static final String XML_OBFUSCATION_MODE = "xml";
private static final String EMF_OBFUSCATION_MODE= "emf";
private static final String OBFUSCATION_INPUT_PROPERTY = PROPERTY_PREFIX + "input";
private static final String OBFUSCATION_OUTPUT_PROPERTY = PROPERTY_PREFIX + "output";
private static final String OBFUSCATION_ECORE_PROPERTY = PROPERTY_PREFIX + "ecore";
private static final String OBFUSCATION_TAGS_PROPERTY = PROPERTY_PREFIX + "tags";
private static final String OBFUSCATION_ATTRIBUTES_PROPERTY = PROPERTY_PREFIX + "attributes";
/**
* @param args
* @return
*/
public Integer performHeadlessObfuscation(String[] args) {
String config = null;
String seed = null;
String salt = null;
if (args == null || args.length == 0) {
reportError("Configuration parameter not set");
}
int i = 0;
while (i < args.length) {
if (args[i].equals(configLongParam)) {
config = args[i + 1];
i += 2;
} else if (args[i].equals(configParam)) {
config = args[i + 1];
i += 2;
} else if (args[i].equals(seedParam)) {
seed = args[i + 1];
i += 2;
} else if (args[i].equals(saltParam)) {
salt = args[i + 1];
i += 2;
} else {
i++;
}
}
System.out.println("Obfuscation called with:\n"
+ " Config : " + Strings.nullToEmpty(config) + "\n"
+ " Seed : " + Strings.nullToEmpty(seed) + "\n"
+ " Salt : " + Strings.nullToEmpty(salt));
if (config == null) {
reportError("Configuration parameter not set");
}
Properties configuration = null;
// load configuration file
try {
configuration = loadConfigurationPropertyFile(config);
} catch (FileNotFoundException e) {
reportError("Could not find configuration file");
} catch (IOException e) {
reportError("Could not read configuration file");
}
String mode = getPropertyValue(configuration, OBFUSCATION_MODE_PROPERTY);
if(mode.equals(EMF_OBFUSCATION_MODE)) {
// TODO handle EMF obfuscation
// check input file existence
// ensure output directory existence
// load ecore models into registry
// load inputs into resource set
// initialize obfuscator
// perform obfuscation
// save models to output directory
} else if(mode.equals(XML_OBFUSCATION_MODE)) {
// ensure output directory existence
File outputDirectory = checkOutputDirectory(configuration);
// check input file existence
Map<String,FileInputStream> inputs = Maps.newHashMap();
prepareInputStreams(configuration, inputs);
// parse schema configuration
XMLSchemaConfiguration schemaConfiguration = prepareSchemaConfiguration(configuration);
// initialize obfuscator
XMLModelObfuscatorBuilder obfuscatorBuilder = XMLModelObfuscatorBuilder.create().setSchemaConfiguration(schemaConfiguration);
if(seed != null) {
obfuscatorBuilder.setSeed(seed);
}
System.out.println("Obfuscating using seed: " + obfuscatorBuilder.getSeed());
if(salt != null) {
obfuscatorBuilder.setSalt(salt);
System.out.println("Obfuscating using salt: " + obfuscatorBuilder.getSalt());
}
performObfuscation(outputDirectory, inputs, obfuscatorBuilder);
} else {
reportError("Unknown mode " + mode + " selected in configuration");
}
return IApplication.EXIT_OK;
}
/**
* @param outputDirectory
* @param inputs
* @param obfuscatorBuilder
*/
private void performObfuscation(File outputDirectory, Map<String, FileInputStream> inputs,
XMLModelObfuscatorBuilder obfuscatorBuilder) {
for (Entry<String, FileInputStream> input : inputs.entrySet()) {
BufferedInputStream bufferedInputStream = new BufferedInputStream(input.getValue());
obfuscatorBuilder.setInput(bufferedInputStream);
String fileName = input.getKey();
File output = new File(outputDirectory, fileName);
BufferedOutputStream bufferedOutputStream;
try {
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(output));
obfuscatorBuilder.setOutput(bufferedOutputStream);
XMLModelObfuscator obfuscator = obfuscatorBuilder.build();
System.out.println("Obfuscating " + fileName);
obfuscator.obfuscate();
bufferedOutputStream.close();
bufferedInputStream.close();
} catch (FileNotFoundException e) {
reportError("Could not ouput to file " + output.getPath());
} catch (IOException e) {
reportError("Could not close output file " + output.getPath());
}
}
}
private Properties loadConfigurationPropertyFile(String configPath) throws FileNotFoundException, IOException {
Properties bundle = new Properties();
FileInputStream fis = new FileInputStream(configPath);
try {
bundle.load(fis);
} finally {
fis.close();
}
return bundle;
}
/**
* @param configuration
*/
private File checkOutputDirectory(Properties configuration) {
String output = getPropertyValue(configuration, OBFUSCATION_OUTPUT_PROPERTY);
File outputFile = new File(output);
if(!outputFile.exists()) {
boolean directoryCreated = outputFile.mkdir();
if(!directoryCreated) {
reportError("Output " + output + " specified in configuration could not be created");
}
} else if(!outputFile.isDirectory()) {
reportError("Output " + output + " specified in configuration is not a directory");
}
return outputFile;
}
private void prepareInputStreams(Properties configuration, Map<String, FileInputStream> inputs) {
String input = getPropertyValue(configuration, OBFUSCATION_INPUT_PROPERTY);
StringTokenizer inputTokenizer = new StringTokenizer(input,";");
while (inputTokenizer.hasMoreTokens()) {
String inputPath = (String) inputTokenizer.nextToken();
// create input stream for input files
File file = new File(inputPath);
createFileInputStreams(inputs, file);
}
}
/**
* @param inputs
* @param inputPath
*/
private void createFileInputStreams(Map<String, FileInputStream> inputs, File file) {
if(!file.exists()) {
reportError("Input " + file.getPath() + " specified in configuration could not be found");
}
if(file.isFile()) {
try {
FileInputStream fileInputStream = new FileInputStream(file);
String fileName = file.getName();
if(inputs.containsKey(fileName)) {
reportError("Multiple files with the same name " + fileName + " in configuration");
}
inputs.put(fileName,fileInputStream);
} catch (FileNotFoundException e) {
reportError("Input " + file.getPath() + " specified in configuration could not be found, although it exists");
}
} else if(file.isDirectory()) {
/*
* TODO we could support directories, either processing only directly contained files or all transitive
* files. However, we would need to take care in putting the directory structure into the output, handle
* symbolic and hard links, etc.
*/
reportError("Input" + file.getPath() + " specified in configuration is a directory");
}
}
/**
* @param configuration
* @return
*/
private XMLSchemaConfiguration prepareSchemaConfiguration(Properties configuration) {
Optional<String> tags = getOptionalPropertyValue(configuration, OBFUSCATION_TAGS_PROPERTY);
Optional<String> attributes = getOptionalPropertyValue(configuration, OBFUSCATION_ATTRIBUTES_PROPERTY);
if(!tags.isPresent() && !attributes.isPresent()) {
reportError("No schema configuration provided, nothing to obfuscate");
}
Set<String> tagSet = Sets.newHashSet();
if(tags.isPresent()) {
StringTokenizer tagTokenizer = new StringTokenizer(tags.get(), ";");
while (tagTokenizer.hasMoreTokens()) {
String tag = tagTokenizer.nextToken();
tagSet.add(tag);
}
}
Multimap<String, String> attributeMultimap = HashMultimap.create();
if(attributes.isPresent()) {
StringTokenizer attributeTokenizer = new StringTokenizer(attributes.get(), ";");
while (attributeTokenizer.hasMoreTokens()) {
String tagAttributes = attributeTokenizer.nextToken();
try {
StringTokenizer tagAttributeTokenizer = new StringTokenizer(tagAttributes, ":");
String tagName = tagAttributeTokenizer.nextToken();
String attributeList = tagAttributeTokenizer.nextToken();
StringTokenizer attributeListTokenizer = new StringTokenizer(attributeList, ",");
while (attributeListTokenizer.hasMoreTokens()) {
String attributeName = attributeListTokenizer.nextToken();
attributeMultimap.put(tagName, attributeName);
}
} catch (NoSuchElementException e) {
reportError("Incorrect syntax in attributes value of schema configuration when processing: " + tagAttributes);
}
}
}
XMLSchemaConfiguration schemaConfiguration = new XMLSchemaConfiguration(attributeMultimap, tagSet);
return schemaConfiguration;
}
/**
* @param configuration
* @return
*/
private String getPropertyValue(Properties configuration, String propertyName) {
Optional<String> optionalPropertyValue = getOptionalPropertyValue(configuration, propertyName);
if(!optionalPropertyValue.isPresent()) {
reportError(propertyName + " undefined in configuration");
}
return optionalPropertyValue.get();
}
/**
* @param configuration
* @return
*/
private Optional<String> getOptionalPropertyValue(Properties configuration, String propertyName) {
String propertyValue = configuration.getProperty(propertyName);
return Optional.fromNullable(propertyValue);
}
/**
* @return
*/
private Integer reportError(String message) {
System.out.println(message);
displayHelp();
throw new IllegalArgumentException(message);
}
private void displayHelp() {
System.out.println("Usage:\n"
+ "<call> -c <configurationFilePath> [-s <seed>] [-salt <salt>]\n"
+ " -c : Required, the configuration that describes what to obfuscate.\n"
+ " --config : Same as -c.\n"
+ " -s : Optional, the seed used for the obfuscation.\n"
+ " --seed : Same as -s.\n"
+ " --salt : Optional, the salt used for the obfuscation.");
}
}