org.eclipse.viatra.modelobfuscator.application.common.ModelObfuscatorHeadless.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.viatra.modelobfuscator.application.common.ModelObfuscatorHeadless.java

Source

/*******************************************************************************
 * 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.List;
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 java.util.concurrent.TimeUnit;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.BasicExtendedMetaData;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.viatra.modelobfuscator.emf.simple.EMFModelObfuscatorBuilder;
import org.eclipse.viatra.modelobfuscator.emf.simple.SimpleEMFModelObfuscator;
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.Stopwatch;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
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)) {

            performEMFObfuscation(seed, salt, configuration);

        } else if (mode.equals(XML_OBFUSCATION_MODE)) {

            performXMLObfuscation(seed, salt, configuration);

        } else {
            reportError("Unknown mode " + mode + " selected in configuration");
        }

        return IApplication.EXIT_OK;
    }

    /**
     * @param seed
     * @param salt
     * @param configuration
     */
    private void performEMFObfuscation(String seed, String salt, Properties configuration) {
        // ensure output directory existence
        File outputDirectory = checkOutputDirectory(configuration);

        // check input file existence
        Map<String, URI> inputs = processInput(configuration);

        Map<String, Object> extensionToFactoryMap = Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap();
        ResourceSetImpl ecoreRS = performEMFSetup(extensionToFactoryMap);

        // load ecore models into registry
        loadEcorePackagesIntoRegistry(configuration, EPackage.Registry.INSTANCE, ecoreRS);

        // load inputs into resource set
        ResourceSetImpl resourceSet = loadInputModels(inputs, extensionToFactoryMap);

        // initialize obfuscator
        EMFModelObfuscatorBuilder obfuscatorBuilder = EMFModelObfuscatorBuilder.create();
        obfuscatorBuilder.setInput(resourceSet);

        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());
        }

        // perform obfuscation
        performObfuscation(obfuscatorBuilder);

        // save models to output directory
        saveObfuscatedModels(outputDirectory, inputs, resourceSet);
    }

    /**
     * @param extensionToFactoryMap
     * @return
     */
    private ResourceSetImpl performEMFSetup(Map<String, Object> extensionToFactoryMap) {
        if (!extensionToFactoryMap.containsKey("ecore")) {
            extensionToFactoryMap.put("ecore", new EcoreResourceFactoryImpl());
        }
        ResourceSetImpl ecoreRS = new ResourceSetImpl();
        final ExtendedMetaData extendedMetaData = new BasicExtendedMetaData(EPackage.Registry.INSTANCE);
        ecoreRS.getLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData);
        return ecoreRS;
    }

    /**
     * @param configuration
     * @return
     */
    private Map<String, URI> processInput(Properties configuration) {
        Map<String, URI> inputs = Maps.newHashMap();
        List<String> resultList = processFileListProperty(configuration, OBFUSCATION_INPUT_PROPERTY);
        for (String filePath : resultList) {
            URI fileURI = URI.createFileURI(filePath);
            inputs.put(filePath, fileURI);
        }
        return inputs;
    }

    /**
     * @param inputs
     * @param extensionToFactoryMap
     * @return
     */
    private ResourceSetImpl loadInputModels(Map<String, URI> inputs, Map<String, Object> extensionToFactoryMap) {
        ResourceSetImpl resourceSet = new ResourceSetImpl();
        for (Entry<String, URI> inputEntry : inputs.entrySet()) {
            URI uri = inputEntry.getValue();
            // XXX we only support XMI resources in this way
            if (!extensionToFactoryMap.containsKey(uri.fileExtension())) {
                extensionToFactoryMap.put(uri.fileExtension(), new EcoreResourceFactoryImpl());
            }
            System.out.println("Loading resource: " + inputEntry.getKey());
            Stopwatch stopwatch = Stopwatch.createStarted();
            resourceSet.getResource(uri, true);
            stopwatch.stop();
            String elapsedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms ("
                    + stopwatch.elapsed(TimeUnit.NANOSECONDS) + " ns)";
            System.out.println("Loaded resource: " + inputEntry.getKey() + " in " + elapsedTime);
        }
        return resourceSet;
    }

    /**
     * @param configuration
     * @param ePackageRegistryInstance
     * @param ecoreRS
     */
    private void loadEcorePackagesIntoRegistry(Properties configuration,
            org.eclipse.emf.ecore.EPackage.Registry ePackageRegistryInstance, ResourceSetImpl ecoreRS) {
        String ecore = getPropertyValue(configuration, OBFUSCATION_ECORE_PROPERTY);
        StringTokenizer ecoreTokenizer = new StringTokenizer(ecore, ";");
        while (ecoreTokenizer.hasMoreTokens()) {
            String ecorePath = (String) ecoreTokenizer.nextToken();
            // create input stream for input files
            Resource ecoreResource = ecoreRS.getResource(URI.createFileURI(ecorePath), true);
            EObject root = ecoreResource.getContents().get(0);
            if (root instanceof EPackage) {
                EPackage ePackage = (EPackage) root;
                ePackageRegistryInstance.put(ePackage.getNsURI(), ePackage);
                System.out.println(
                        "Registered metamodel: " + ePackage.getName() + "(nsURI: " + ePackage.getNsURI() + ")");
            }
        }
    }

    /**
     * @param obfuscatorBuilder
     */
    private void performObfuscation(EMFModelObfuscatorBuilder obfuscatorBuilder) {
        SimpleEMFModelObfuscator obfuscator = obfuscatorBuilder.build();
        System.out.println("Obfuscating EMF resource set");
        Stopwatch stopwatch = Stopwatch.createStarted();
        obfuscator.obfuscate();
        stopwatch.stop();
        String elapsedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms ("
                + stopwatch.elapsed(TimeUnit.NANOSECONDS) + " ns)";
        System.out.println("Obfuscation finished in: " + elapsedTime);
    }

    /**
     * @param outputDirectory
     * @param inputs
     * @param resourceSet
     */
    private void saveObfuscatedModels(File outputDirectory, Map<String, URI> inputs, ResourceSetImpl resourceSet) {
        URI outputDirUri = URI.createFileURI(outputDirectory.getPath());
        for (Entry<String, URI> entry : inputs.entrySet()) {
            URI uri = entry.getValue();
            String fileSegment = uri.lastSegment();
            URI outputUri = outputDirUri.appendSegment(fileSegment);
            Resource resource = resourceSet.getResource(uri, false);
            resource.setURI(outputUri);
            try {
                System.out.println("Saving resource: " + fileSegment);
                Stopwatch stopwatch2 = Stopwatch.createStarted();
                resource.save(null);
                stopwatch2.stop();
                String elapsedTime2 = stopwatch2.elapsed(TimeUnit.MILLISECONDS) + " ms ("
                        + stopwatch2.elapsed(TimeUnit.NANOSECONDS) + " ns)";
                System.out.println("Saved resource: " + fileSegment + " in " + elapsedTime2);
            } catch (IOException e) {
                reportError("Could not save output " + fileSegment);
            }
        }
    }

    private List<String> processFileListProperty(Properties configuration, String obfuscationInputProperty) {
        List<String> resultList = Lists.newArrayList();
        String input = getPropertyValue(configuration, obfuscationInputProperty);
        StringTokenizer inputTokenizer = new StringTokenizer(input, ";");
        while (inputTokenizer.hasMoreTokens()) {
            String inputPath = (String) inputTokenizer.nextToken();
            // create input stream for input files
            File file = new File(inputPath);
            if (!file.exists()) {
                reportError("Input " + file.getPath() + " specified in configuration could not be found");
            }
            if (file.isFile()) {
                String fileName = file.getName();
                if (resultList.contains(fileName)) {
                    reportError("Multiple files with the same name " + fileName + " in configuration");
                }
                resultList.add(inputPath);
            } 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");
            }
        }
        return resultList;
    }

    /**
     * @param seed
     * @param salt
     * @param configuration
     */
    private void performXMLObfuscation(String seed, String salt, Properties configuration) {
        // 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);
    }

    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) {
        List<String> resultList = processFileListProperty(configuration, OBFUSCATION_INPUT_PROPERTY);
        // create input stream for input files
        for (String fileName : resultList) {
            File file = new File(fileName);
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                inputs.put(file.getName(), fileInputStream);
            } catch (FileNotFoundException e) {
                reportError("Input " + file.getPath()
                        + " specified in configuration could not be found, although it exists");
            }
        }
    }

    /**
     * @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 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);
                Stopwatch stopwatch = Stopwatch.createStarted();
                obfuscator.obfuscate();
                stopwatch.stop();
                System.out.println("Obfuscation finished in: " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms ("
                        + stopwatch.elapsed(TimeUnit.NANOSECONDS) + " ns)");
                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());
            }
        }
    }

    /**
     * @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.");
    }

}