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

org.teavm.parsing.ClasspathResourceMapper Maven / Gradle / Ivy

There is a newer version: 0.10.2
Show newest version
/*
 *  Copyright 2013 Alexey Andreev.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.teavm.parsing;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import org.teavm.common.CachedMapper;
import org.teavm.common.Mapper;
import org.teavm.model.ClassHolder;

/**
 *
 * @author Alexey Andreev
 */
public class ClasspathResourceMapper implements Mapper, ClassDateProvider {
    private static final String PACKAGE_PREFIX = "packagePrefix.";
    private static final String CLASS_PREFIX = "classPrefix.";
    private Mapper innerMapper;
    private List transformations = new ArrayList<>();
    private ClassRefsRenamer renamer;
    private ClassLoader classLoader;
    private Map modificationDates = new HashMap<>();

    private static class Transformation {
        String packageName;
        String packagePrefix = "";
        String fullPrefix = "";
        String classPrefix = "";
    }

    public ClasspathResourceMapper(ClassLoader classLoader, Mapper innerMapper) {
        this.innerMapper = innerMapper;
        try {
            Enumeration resources = classLoader.getResources("META-INF/teavm.properties");
            Map transformationMap = new HashMap<>();
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                Properties properties = new Properties();
                try (InputStream input = resource.openStream()) {
                    properties.load(input);
                }
                loadProperties(properties, transformationMap);
            }
            transformations.addAll(transformationMap.values());
        } catch (IOException e) {
            throw new RuntimeException("Error reading resources", e);
        }
        renamer = new ClassRefsRenamer(new CachedMapper<>(classNameMapper));
        this.classLoader = classLoader;
    }

    private void loadProperties(Properties properties, Map cache) {
        for (String propertyName : properties.stringPropertyNames()) {
            if (propertyName.startsWith(PACKAGE_PREFIX)) {
                String packageName = propertyName.substring(PACKAGE_PREFIX.length());
                Transformation transformation = getTransformation(cache, packageName);
                transformation.packagePrefix = properties.getProperty(propertyName) + ".";
                transformation.fullPrefix = transformation.packagePrefix + transformation.packageName;
            } else if (propertyName.startsWith(CLASS_PREFIX)) {
                String packageName = propertyName.substring(CLASS_PREFIX.length());
                Transformation transformation = getTransformation(cache, packageName);
                transformation.classPrefix = properties.getProperty(propertyName);
            }
        }
    }

    private Transformation getTransformation(Map cache, String packageName) {
        Transformation transformation = cache.get(packageName);
        if (transformation == null) {
            transformation = new Transformation();
            transformation.packageName = packageName + ".";
            transformation.fullPrefix = packageName + ".";
            cache.put(packageName, transformation);
        }
        return transformation;
    }

    @Override
    public ClassHolder map(String name) {
        for (Transformation transformation : transformations) {
            if (name.startsWith(transformation.packageName)) {
                int index = name.lastIndexOf('.');
                String className = name.substring(index + 1);
                String packageName = index > 0 ? name.substring(0, index) : "";
                ClassHolder classHolder = innerMapper.map(transformation.packagePrefix + packageName
                        + "." + transformation.classPrefix + className);
                if (classHolder != null) {
                    classHolder = renamer.rename(classHolder);
                }
                return classHolder;
            }
        }
        return innerMapper.map(name);
    }

    private String renameClass(String name) {
        for (Transformation transformation : transformations) {
            if (name.startsWith(transformation.fullPrefix)) {
                int index = name.lastIndexOf('.');
                String className = name.substring(index + 1);
                String packageName = name.substring(0, index);
                if (className.startsWith(transformation.classPrefix)) {
                    return packageName.substring(transformation.packagePrefix.length()) + "."
                            + className.substring(transformation.classPrefix.length());
                }
            }
        }
        return name;
    }

    private Mapper classNameMapper = preimage -> renameClass(preimage);

    @Override
    public Date getModificationDate(String className) {
        ModificationDate mdate = modificationDates.get(className);
        if (mdate == null) {
            mdate = new ModificationDate();
            modificationDates.put(className, mdate);
            mdate.date = calculateModificationDate(className);
        }
        return mdate.date;
    }

    private Date calculateModificationDate(String className) {
        int dotIndex = className.lastIndexOf('.');
        String packageName;
        String simpleName;
        if (dotIndex > 0) {
            packageName = className.substring(0, dotIndex + 1);
            simpleName = className.substring(dotIndex + 1);
        } else {
            packageName = "";
            simpleName = className;
        }
        for (Transformation transformation : transformations) {
            if (packageName.startsWith(transformation.packageName)) {
                String fullName = transformation.packagePrefix + packageName + transformation.classPrefix + simpleName;
                Date date = getOriginalModificationDate(fullName);
                if (date != null) {
                    return date;
                }
            }
        }
        return getOriginalModificationDate(className);
    }

    private Date getOriginalModificationDate(String className) {
        URL url = classLoader.getResource(className.replace('.', '/') + ".class");
        if (url == null) {
            return null;
        }
        if (url.getProtocol().equals("file")) {
            try {
                File file = new File(url.toURI());
                return file.exists() ? new Date(file.lastModified()) : null;
            } catch (URISyntaxException e) {
                // If URI is invalid, we just report that class should be reparsed
                return null;
            }
        } else if (url.getProtocol().equals("jar") && url.getPath().startsWith("file:")) {
            int exclIndex = url.getPath().indexOf('!');
            String jarFileName = exclIndex >= 0 ? url.getPath().substring(0, exclIndex) : url.getPath();
            File file = new File(jarFileName.substring("file:".length()));
            return file.exists() ? new Date(file.lastModified()) : null;
        } else {
            return null;
        }
    }

    static class ModificationDate {
        Date date;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy