All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robovm.compiler.config.Config Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 Trillian AB
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.robovm.compiler.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.JarFile;

import org.apache.commons.io.IOUtils;
import org.robovm.compiler.Version;
import org.robovm.compiler.clazz.Clazz;
import org.robovm.compiler.clazz.Clazzes;
import org.robovm.compiler.clazz.Path;
import org.robovm.compiler.log.Logger;
import org.robovm.compiler.target.ConsoleTarget;
import org.robovm.compiler.target.Target;
import org.robovm.compiler.target.ios.IOSTarget;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.convert.Converter;
import org.simpleframework.xml.convert.Registry;
import org.simpleframework.xml.convert.RegistryStrategy;
import org.simpleframework.xml.core.Persister;
import org.simpleframework.xml.filter.PlatformFilter;
import org.simpleframework.xml.stream.Format;
import org.simpleframework.xml.stream.InputNode;
import org.simpleframework.xml.stream.OutputNode;

/**
 * @author niklas
 *
 */
@Root
public class Config {
    
    public enum Cacerts { full };
    public enum TargetType { console, ios };
    
    @Element(required = false)
    private File installDir = null;
    @Element(required = false)
    private String executableName = null;
    @Element(required = false)
    private Boolean useDynamicJni = null;
    @Element(required = false)
    private Boolean skipRuntimeLib = null;
    @Element(required = false)
    private File mainJar;
    @Element(required = false)
    private String mainClass;
    @Element(required = false)
    private Cacerts cacerts = null;
    @Element(required = false)
    private OS os = null;
    @Element(required = false)
    private Arch arch = null;
    @ElementList(required = false, entry = "root")
    private ArrayList roots;
    @ElementList(required = false, entry = "pattern")
    private ArrayList forceLinkClasses;
    @ElementList(required = false, entry = "lib")
    private ArrayList libs;
    @ElementList(required = false, entry = "framework")
    private ArrayList frameworks;
    @ElementList(required = false, entry = "resource")
    private ArrayList resources;
    @ElementList(required = false, entry = "classpathentry")
    private ArrayList bootclasspath;
    @ElementList(required = false, entry = "classpathentry")
    private ArrayList classpath;
    @Element(required = false, name = "target")
    private TargetType targetType;
    
    @Element(required = false)
    private String iosSdkVersion;
    @Element(required = false)
    private File iosInfoPList = null;
    @Element(required = false)
    private File iosResourceRulesPList;
    @Element(required = false)
    private File iosEntitlementsPList;
    @Element(required = false)
    private String iosSignIdentity;
    
    private Target target = null;
    private Properties properties = new Properties();
    
    private Home home = null;
    private File cacheDir = new File(System.getProperty("user.home"), ".robovm/cache");
    private File ccBinPath = null;
    
    private boolean clean = false;
    private boolean debug = true;
    private boolean useDebugLibs = false;
    private boolean skipLinking = false;
    private boolean skipInstall = false;
    
    private File osArchDepLibDir;
    private File tmpDir;
    private Clazzes clazzes;
    private Logger logger = Logger.NULL_LOGGER;
    private List resourcesPaths = new ArrayList();

    Config() {
    }
    
    public Home getHome() {
        return home;
    }
    
    public File getInstallDir() {
        return installDir;
    }

    public String getExecutableName() {
        return executableName;
    }

    public File getCacheDir() {
        return cacheDir;
    }

    public File getCcBinPath() {
        return ccBinPath;
    }

    public OS getOs() {
        return os;
    }

    public Arch getArch() {
        return arch;
    }

    public String getTriple() {
        return arch.getLlvmName() + "-unknown-" + os;
    }
    
    public boolean isClean() {
        return clean;
    }

    public boolean isDebug() {
        return debug;
    }

    public boolean isUseDebugLibs() {
        return useDebugLibs;
    }
    
    public boolean isSkipRuntimeLib() {
        return skipRuntimeLib != null && skipRuntimeLib.booleanValue();
    }

    public boolean isSkipLinking() {
        return skipLinking;
    }

    public boolean isSkipInstall() {
        return skipInstall;
    }
    
    public boolean isUseDynamicJni() {
        return useDynamicJni != null && useDynamicJni.booleanValue();
    }
    
    public File getMainJar() {
        return mainJar;
    }

    public String getMainClass() {
        return mainClass;
    }

    public Cacerts getCacerts() {
        return cacerts == null ? Cacerts.full : cacerts;
    }
    
    public List getResourcesPaths() {
        return resourcesPaths;
    }
    
    public void addResourcesPath(Path path) {
        resourcesPaths.add(path);
    }
    
    public File getTmpDir() {
        if (tmpDir == null) {
            try {
                tmpDir = File.createTempFile("robovm", ".tmp");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            tmpDir.delete();
            tmpDir.mkdirs();
        }
        return tmpDir;
    }

    public List getForceLinkClasses() {
        return forceLinkClasses == null ? Collections.emptyList() 
                : Collections.unmodifiableList(forceLinkClasses);
    }
    
    public List getLibs() {
        List result = new ArrayList();
        if (libs != null) {
            for (Lib lib : libs) {
                result.add(lib.getValue());
            }
        }
        return Collections.unmodifiableList(result);
    }
    
    public List getFrameworks() {
        return frameworks == null ? Collections.emptyList() 
                : Collections.unmodifiableList(frameworks);
    }
    
    public List getResources() {
        return resources == null ? Collections.emptyList() 
                : Collections.unmodifiableList(resources);
    }
    
    public File getOsArchDepLibDir() {
        return osArchDepLibDir;
    }
    
    public Clazzes getClazzes() {
        return clazzes;
    }

    public List getBootclasspath() {
        return bootclasspath;
    }
    
    public List getClasspath() {
        return classpath;
    }
    
    public Properties getProperties() {
        return properties;
    }
    
    public Logger getLogger() {
        return logger;
    }
    
    public Target getTarget() {
        return target;
    }
    
    public String getIosSdkVersion() {
        return iosSdkVersion;
    }

    public File getIosInfoPList() {
        return iosInfoPList;
    }

    public File getIosResourceRulesPList() {
        return iosResourceRulesPList;
    }

    public File getIosEntitlementsPList() {
        return iosEntitlementsPList;
    }

    public String getIosSignIdentity() {
        return iosSignIdentity;
    }

    private static File makeFileRelativeTo(File dir, File f) {
        if (f.getParentFile() == null) {
            return dir;
        }
        return new File(makeFileRelativeTo(dir, f.getParentFile()), f.getName());
    }
    
    public String getArchiveName(Path path) {
        if (path.getFile().isFile()) {
            return path.getFile().getName();
        } else {
            return "classes" + path.getIndex() + ".jar";
        }
    }
    
    public File getLlFile(Clazz clazz) {
        String baseName = clazz.getInternalName().replace('/', File.separatorChar);
        return new File(getCacheDir(clazz.getPath()), baseName + ".class.ll");
    }
    
    public File getBcFile(Clazz clazz) {
        String baseName = clazz.getInternalName().replace('/', File.separatorChar);
        return new File(getCacheDir(clazz.getPath()), baseName + ".class.bc");
    }
    
    public File getSFile(Clazz clazz) {
        String baseName = clazz.getInternalName().replace('/', File.separatorChar);
        return new File(getCacheDir(clazz.getPath()), baseName + ".class.s");
    }
    
    public File getOFile(Clazz clazz) {
        String baseName = clazz.getInternalName().replace('/', File.separatorChar);
        return new File(getCacheDir(clazz.getPath()), baseName + ".class.o");
    }
    
    public File getDepsFile(Clazz clazz) {
        String baseName = clazz.getInternalName().replace('/', File.separatorChar);
        return new File(getCacheDir(clazz.getPath()), baseName + ".class.deps");
    }
    
    public File getCacheDir(Path path) {
        File srcRoot = path.getFile().getParentFile();
        String name = path.getFile().getName();
        try {
            return new File(makeFileRelativeTo(cacheDir, srcRoot.getCanonicalFile()), name);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    private static Map getManifestAttributes(File jarFile) throws IOException {
        JarFile jf = null;
        try {
            jf = new JarFile(jarFile);
            return new HashMap(jf.getManifest().getMainAttributes());
        } finally {
            jf.close();
        }
    }
    
    private static String getImplementationVersion(File jarFile) throws IOException {
        return (String) getManifestAttributes(jarFile).get(Attributes.Name.IMPLEMENTATION_VERSION);
    }

    private static String getMainClass(File jarFile) throws IOException {
        return (String) getManifestAttributes(jarFile).get(Attributes.Name.MAIN_CLASS);
    }
    
    private Config build() throws IOException {
        if (home == null) {
            home = Home.find();
        }
        
        if (bootclasspath == null) {
            bootclasspath = new ArrayList();
        }
        if (classpath == null) {
            classpath = new ArrayList();
        }
        
        if (mainJar != null) {
            mainClass = getMainClass(mainJar);
            classpath.add(mainJar);
        }
        
        if (!skipLinking && executableName == null && mainClass == null) {
            throw new IllegalArgumentException("No target and no main class specified");
        }

        if (!skipLinking && classpath.isEmpty()) {
            throw new IllegalArgumentException("No classpath specified");
        }
        
        if (skipLinking) {
            skipInstall = true;
        }
        
        if (executableName == null) {
            executableName = mainClass;
        }

        List realBootclasspath = bootclasspath == null ? new ArrayList() : bootclasspath;
        if (!isSkipRuntimeLib()) {
            realBootclasspath = new ArrayList(bootclasspath);
            realBootclasspath.add(0, home.rtPath);
        }

        this.clazzes = new Clazzes(this, realBootclasspath, classpath);
        
        if (!skipInstall) {
            if (installDir == null) {
                installDir = new File(".", executableName);
            }
            installDir.mkdirs();
        }

        if (targetType == TargetType.console) {
            target = new ConsoleTarget();
        } else if (targetType == TargetType.ios) {
            target = new IOSTarget();
        } else {
            // Auto
            if (os == OS.ios) {
                target = new IOSTarget();
            } else {
                target = new ConsoleTarget();
            }
        }
        target.init(this);
        
        os = target.getOs();
        arch = target.getArch();
        
        osArchDepLibDir = new File(new File(home.libVmDir, os.toString()), 
                arch.toString());
        
        File osDir = new File(cacheDir, os.toString());
        File archDir = new File(osDir, arch.toString());
        cacheDir = new File(archDir, "default");
        cacheDir.mkdirs();
        
        return this;
    }

    public static class Home {
        private File binDir = null;
        private File libVmDir = null;
        private File rtPath = null;
        private Map cacertsPath = null;
        private boolean dev = false;

        public Home(File homeDir) {
            validate(homeDir);
            binDir = new File(homeDir, "bin");
            libVmDir = new File(homeDir, "lib/vm");
            rtPath = new File(homeDir, "lib/robovm-rt.jar");
            cacertsPath = new HashMap();
            cacertsPath.put(Cacerts.full, new File(homeDir, "lib/robovm-cacerts-full.jar"));
        }
        
        private Home(File devDir, File binDir, File libVmDir, File rtPath) {
            this.binDir = binDir;
            this.libVmDir = libVmDir;
            this.rtPath = rtPath;
            cacertsPath = new HashMap();
            cacertsPath.put(Cacerts.full, new File(devDir, 
                    "cacerts/full/target/robovm-cacerts-full-" + Version.getVersion() + ".jar"));
            this.dev = true;
        }

        public boolean isDev() {
            return dev;
        }

        public File getBinDir() {
            return binDir;
        }
        
        public File getLibVmDir() {
            return libVmDir;
        }
        
        public File getRtPath() {
            return rtPath;
        }
        
        public File getCacertsPath(Cacerts cacerts) {
            return cacertsPath.get(cacerts);
        }
        
        public static Home find() {
            // Check if ROBOVM_DEV_ROOT has been set. If set it should be pointing
            // at the root of a complete RoboVM source tree.
            if (System.getenv("ROBOVM_DEV_ROOT") != null) {
                File dir = new File(System.getenv("ROBOVM_DEV_ROOT"));
                return validateDevRootDir(dir);
            }
            
            if (System.getenv("ROBOVM_HOME") != null) {
                File dir = new File(System.getenv("ROBOVM_HOME"));
                return new Home(dir);
            }
            
            List candidates = new ArrayList();
            File userHome = new File(System.getProperty("user.home"));
            candidates.add(new File(userHome, "Applications/robovm"));
            candidates.add(new File(userHome, ".robovm/home"));
            candidates.add(new File("/usr/local/lib/robovm"));
            candidates.add(new File("/opt/robovm"));
            candidates.add(new File("/usr/lib/robovm"));
            
            for (File dir : candidates) {
                if (dir.exists()) {
                    return new Home(dir);
                }
            }
            
            throw new IllegalArgumentException("ROBOVM_HOME not set and no RoboVM " 
                    + "installation found in " + candidates);
        }
        
        public static void validate(File dir) {
            String error = "Path " + dir + " is not a valid RoboVM install directory: ";
            // Check for required dirs and match the compiler version
            // with our version.
            if (!dir.exists()) {
                throw new IllegalArgumentException(error + "no such path");
            }
            
            if (!dir.isDirectory()) {
                throw new IllegalArgumentException(error + "not a directory");
            }
            
            File libDir = new File(dir, "lib");
            if (!libDir.exists() || !libDir.isDirectory()) {
                throw new IllegalArgumentException(error + "lib/ missing or invalid");
            }
            File binDir = new File(dir, "bin");
            if (!binDir.exists() || !binDir.isDirectory()) {
                throw new IllegalArgumentException(error + "bin/ missing or invalid");
            }
            File libVmDir = new File(libDir, "vm");
            if (!libVmDir.exists() || !libVmDir.isDirectory()) {
                throw new IllegalArgumentException(error + "lib/vm/ missing or invalid");
            }
            File rtJarFile = new File(libDir, "robovm-rt.jar");
            if (!rtJarFile.exists() || !rtJarFile.isFile()) {
                throw new IllegalArgumentException(error 
                        + "lib/robovm-rt.jar missing or invalid");
            }
            
            // Compare the version of this compiler with the version of the
            // robovm-rt.jar in the home dir. They have to match.
            try {
                String thisVersion = Version.getVersion();
                String thatVersion = getImplementationVersion(rtJarFile);
                if (thisVersion == null || thatVersion == null || !thisVersion.equals(thatVersion)) {
                    throw new IllegalArgumentException(error + "version mismatch (expected: " 
                            + thisVersion + ", was: " + thatVersion + ")");
                }
            } catch (IOException e) {
                throw new IllegalArgumentException(error 
                        + "failed to get version of rt jar", e);
            }
        }

        private static Home validateDevRootDir(File dir) {
            String error = "Path " + dir + " is not a valid RoboVM source tree: ";
            // Check for required dirs.
            if (!dir.exists()) {
                throw new IllegalArgumentException(error + "no such path");
            }
            
            if (!dir.isDirectory()) {
                throw new IllegalArgumentException(error + "not a directory");
            }
            
            File vmBinariesDir = new File(dir, "vm/target/binaries");
            if (!vmBinariesDir.exists() || !vmBinariesDir.isDirectory()) {
                throw new IllegalArgumentException(error + "vm/target/binaries/ missing or invalid");
            }
            File binDir = new File(dir, "bin");
            if (!binDir.exists() || !binDir.isDirectory()) {
                throw new IllegalArgumentException(error + "bin/ missing or invalid");
            }

            String rtJarName = "robovm-rt-" + Version.getVersion() + ".jar";
            File rtJar = new File(dir, "rt/target/" + rtJarName);
            if (!rtJar.exists() || rtJar.isDirectory()) {
                throw new IllegalArgumentException(error 
                        + "rt/target/" + rtJarName + " missing or invalid");
            }

            return new Home(dir, binDir, vmBinariesDir, rtJar);
        }
    }
    
    public static class Builder {
        final Config config;
        
        public Builder() {
            this.config = new Config();
        }
        
        public Builder os(OS os) {
            config.os = os;
            return this;
        }
        
        public Builder arch(Arch arch) {
            config.arch = arch;
            return this;
        }
        
        public Builder clearClasspathEntries() {
            if (config.classpath != null) {
                config.classpath.clear();
            }
            return this;
        }

        public Builder addClasspathEntry(File f) {
            if (config.classpath == null) {
                config.classpath = new ArrayList();
            }
            config.classpath.add(f);
            return this;
        }
        
        public Builder clearBootClasspathEntries() {
            if (config.bootclasspath != null) {
                config.bootclasspath.clear();
            }
            return this;
        }

        public Builder addBootClasspathEntry(File f) {
            if (config.bootclasspath == null) {
                config.bootclasspath = new ArrayList();
            }
            config.bootclasspath.add(f);
            return this;
        }
        
        public Builder mainJar(File f) {
            config.mainJar = f;
            return this;
        }

        public Builder installDir(File installDir) {
            config.installDir = installDir;
            return this;
        }

        public Builder executableName(String executableName) {
            config.executableName = executableName;
            return this;
        }

        public Builder home(Home home) {
            config.home = home;
            return this;
        }

        public Builder cacheDir(File cacheDir) {
            config.cacheDir = cacheDir;
            return this;
        }

        public Builder clean(boolean b) {
            config.clean = b;
            return this;
        }

        public Builder ccBinPath(File ccBinPath) {
            config.ccBinPath = ccBinPath;
            return this;
        }

        public Builder debug(boolean b) {
            config.debug = b;
            return this;
        }

        public Builder useDebugLibs(boolean b) {
            config.useDebugLibs = b;
            return this;
        }
        
        public Builder skipRuntimeLib(boolean b) {
            config.skipRuntimeLib = b;
            return this;
        }

        public Builder skipLinking(boolean b) {
            config.skipLinking = b;
            return this;
        }

        public Builder skipInstall(boolean b) {
            config.skipInstall = b;
            return this;
        }
        
        public Builder useDynamicJni(boolean b) {
            config.useDynamicJni = b;
            return this;
        }
        
        public Builder mainClass(String mainClass) {
            config.mainClass = mainClass;
            return this;
        }

        public Builder tmpDir(File tmpDir) {
            config.tmpDir = tmpDir;
            return this;
        }
        
        public Builder logger(Logger logger) {
            config.logger = logger;
            return this;
        }

        public Builder clearForceLinkClasses() {
            if (config.forceLinkClasses != null) {
                config.forceLinkClasses.clear();
            }
            return this;
        }

        public Builder addForceLinkClass(String pattern) {
            if (config.forceLinkClasses == null) {
                config.forceLinkClasses = new ArrayList();
            }
            config.forceLinkClasses.add(pattern);
            return this;
        }

        public Builder clearLibs() {
            if (config.libs != null) {
                config.libs.clear();
            }
            return this;
        }

        public Builder addLib(String lib) {
            if (config.libs == null) {
                config.libs = new ArrayList();
            }
            config.libs.add(new Lib(lib));
            return this;
        }
        
        public Builder clearFrameworks() {
            if (config.frameworks != null) {
                config.frameworks.clear();
            }
            return this;
        }
        
        public Builder addFramework(String framework) {
            if (config.frameworks == null) {
                config.frameworks = new ArrayList();
            }
            config.frameworks.add(framework);
            return this;
        }
        
        public Builder clearResources() {
            if (config.resources != null) {
                config.resources.clear();
            }
            return this;
        }
        
        public Builder addResource(File path) {
            if (config.resources == null) {
                config.resources = new ArrayList();
            }
            config.resources.add(path);
            return this;
        }

        public Builder targetType(TargetType targetType) {
            config.targetType = targetType;
            return this;
        }
        
        public Builder clearProperties() {
            config.properties.clear();
            return this;
        }
        
        public Builder addProperties(Properties properties) {
            config.properties.putAll(properties);
            return this;
        }
        
        public Builder addProperties(File file) throws IOException {
            Properties props = new Properties();
            Reader reader = null;
            try {
                reader = new InputStreamReader(new FileInputStream(file), "utf-8");
                props.load(reader);
                addProperties(props);
            } finally {
                IOUtils.closeQuietly(reader);
            }
            return this;
        }
        
        public Builder addProperty(String name, String value) {
            config.properties.put(name, value);
            return this;
        }
        
        public Builder cacerts(Cacerts cacerts) {
            config.cacerts = cacerts;
            return this;
        }
        
        public Builder iosSdkVersion(String sdkVersion) {
            config.iosSdkVersion = sdkVersion;
            return this;
        }
        
        public Builder iosInfoPList(File infoPList) {
            config.iosInfoPList = infoPList;
            return this;
        }
        
        public Builder iosEntitlementsPList(File entitlementsPList) {
            config.iosEntitlementsPList = entitlementsPList;
            return this;
        }

        public Builder iosResourceRulesPList(File resourceRulesPList) {
            config.iosResourceRulesPList = resourceRulesPList;
            return this;
        }
        
        public Builder iosSignIdentity(String signIdentity) {
            config.iosSignIdentity = signIdentity;
            return this;
        }
        
        public Config build() throws IOException {
            return config.build();
        }
        
        public void read(File file) throws Exception {
            Reader reader = null;
            try {
                reader = new InputStreamReader(new FileInputStream(file), "utf-8");
                read(reader, file.getAbsoluteFile().getParentFile());
            } finally {
                IOUtils.closeQuietly(reader);
            }
        }
        
        public void read(Reader reader, File wd) throws Exception {
            Serializer serializer = createSerializer(wd);
            serializer.read(config, reader);
            //  was renamed to  but we still support . We need to
            // copy  to  and set  to null.
            if (config.roots != null && !config.roots.isEmpty()) {
                if (config.forceLinkClasses == null) {
                    config.forceLinkClasses = new ArrayList();
                }
                config.forceLinkClasses.addAll(config.roots);
                config.roots = null;
            }
        }
        
        public void write(File file) throws Exception {
            Writer writer = null;
            try {
                writer = new OutputStreamWriter(new FileOutputStream(file), "utf-8");
                write(writer, file.getAbsoluteFile().getParentFile());
            } finally {
                IOUtils.closeQuietly(writer);
            }
        }
        
        public void write(Writer writer, File wd) throws Exception {
            Serializer serializer = createSerializer(wd);
            serializer.write(config, writer);
        }

        private Serializer createSerializer(File wd) throws Exception {
            Registry registry = new Registry();
            RelativeFileConverter fileConverter = new RelativeFileConverter(wd);
            registry.bind(File.class, fileConverter);
            registry.bind(Lib.class, new RelativeLibConverter(fileConverter));
            Serializer serializer = new Persister(new RegistryStrategy(registry), 
                    new PlatformFilter(config.properties), new Format(2));
            return serializer;
        }
    }

    private static final class Lib {
        private final String value;

        public Lib(String value) {
            this.value = value;
        }
        
        public String getValue() {
            return value;
        }
    }
    
    private static final class RelativeLibConverter implements Converter {
        private final RelativeFileConverter fileConverter;

        public RelativeLibConverter(RelativeFileConverter fileConverter) {
            this.fileConverter = fileConverter;
        }

        @Override
        public Lib read(InputNode node) throws Exception {
            String value = node.getValue();
            if (value == null) {
                return null;
            }
            if (value.endsWith(".a") || value.endsWith(".o")) {
                return new Lib(fileConverter.read(value).getAbsolutePath());
            } else {
                return new Lib(value);
            }
        }

        @Override
        public void write(OutputNode node, Lib lib) throws Exception {
            String value = lib.getValue();
            if (value.endsWith(".a") || value.endsWith(".o")) {
                fileConverter.write(node, new File(value));
            } else {
                node.setValue(value);
            }
        }
    }
    
    private static final class RelativeFileConverter implements Converter {
        private final String wdPrefix;
        
        public RelativeFileConverter(File wd) {
            if (wd.isFile()) {
                wd = wd.getParentFile();
            }
            String prefix = wd.getAbsolutePath();
            if (!prefix.endsWith(File.separator)) {
                prefix = prefix + File.separator;
            }
            wdPrefix = prefix;
        }
        
        File read(String value) {
            if (value == null) {
                return null;
            }
            File file = new File(value);
            if (!file.isAbsolute()) {
                file = new File(wdPrefix, value);
            }
            return file;
        }
        
        @Override
        public File read(InputNode node) throws Exception {
            return read(node.getValue());
        }

        @Override
        public void write(OutputNode node, File value) throws Exception {
            String path = value.getAbsolutePath();
            if (path.startsWith(wdPrefix)) {
                node.setValue(path.substring(wdPrefix.length()));
            } else {
                node.setValue(path);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy