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

io.virtdata.docsys.metafs.fs.renderfs.api.FileRenderer Maven / Gradle / Ivy

package io.virtdata.docsys.metafs.fs.renderfs.api;

import io.virtdata.docsys.metafs.fs.renderfs.api.rendered.RenderedContent;
import io.virtdata.docsys.metafs.fs.renderfs.api.rendering.RenderingScope;
import io.virtdata.docsys.metafs.fs.renderfs.api.rendering.TemplateCompiler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.spi.FileSystemProvider;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@SuppressWarnings("Duplicates")
public class FileRenderer extends FileContentRenderer {
    private final static Logger logger = LoggerFactory.getLogger(FileRenderer.class);

    private final String sourceExtension;
    private final String targetExtension;
    private final Pattern sourceNamePattern;
    private final Pattern targetNamePattern;
    private final boolean isCaseSensitive;

    private TemplateCompiler compiler;

    /**
     * Create a file renderer from a source extension to a target extension, which will yield the
     * virtual contents of the target file by applying a set of renderers to the source file data.
     *
     * @param fromext  The extension of the source (actual) file, including the dot and extension name.
     * @param toext    The extension of the target (virtual) file, including the dot and extension name.
     * @param cased    Whether or not to do case-sensitive matching against the source and target extensions.
     * @param compiler A lookup function which can create a renderer for a specific path as needed.
     */
    public FileRenderer(String fromext, String toext, boolean cased, TemplateCompiler compiler) {
        this.compiler = compiler;

        if (!fromext.startsWith(".")) {
            throw new InvalidParameterException("You must provide a source extension in '.xyz' form.");
        }
        if (!toext.startsWith(".")) {
            throw new InvalidParameterException("You must provide a target extension in '.xyz' form.");
        }
        this.isCaseSensitive = cased;
        this.sourceExtension = fromext;
        this.sourceNamePattern = toNamePattern(fromext);
        this.targetExtension = toext;
        this.targetNamePattern = toNamePattern(toext);

    }

    private Pattern toNamePattern(String fileExtension) {
        Pattern.compile(fileExtension);
        StringBuilder sb = new StringBuilder("(?.+)(?");
        if (this.isCaseSensitive) {
            sb.append(Pattern.quote(fileExtension));
        } else {
            for (int i = 0; i < fileExtension.length(); i++) {
                String c = fileExtension.substring(i, i + 1);
                if (c.toUpperCase().equals(c.toLowerCase())) {
                    sb.append(Pattern.quote(c));
                } else {
                    sb.append("[").append(c.toLowerCase()).append(c.toUpperCase()).append("]");
                }
            }
            sb.append(")");
        }
        String pattern = sb.toString().replaceAll("\\\\E\\\\Q", "");
        return Pattern.compile(pattern);

    }

    @Override
    public List getVirtualPathsFor(Path path) {
        ArrayList vpaths = new ArrayList<>();
        if (this.matchesSource(path) && !isWrapperPath(path)) {
            Path targetPaths = this.getRenderedTargetName(path);
            vpaths.add(targetPaths);
        }
        return vpaths;
    }


    @Override
    public Pattern getSourcePattern() {
        return sourceNamePattern;
    }

    @Override
    public Pattern getTargetPattern() {
        return targetNamePattern;
    }

    @Override
    public boolean isWrapperPath(Path p) {
        String filename = p.getName(p.getNameCount() - 1).toString();
        return filename.startsWith("__.") || filename.startsWith("_.");
    }

    public String getSourceExtension() {
        return sourceExtension;
    }

    public String getTargetExtension() {
        return targetExtension;
    }

    @Override
    public Path getSourcePath(Path targetName) {
        Matcher matcher = targetNamePattern.matcher(targetName.toString());
        if (matcher.matches()) {
            String basepath = matcher.group("basepath");
            String extension = matcher.group("extension");
            if (basepath == null || extension == null) {
                throw new RuntimeException(
                        "Unable to extract named fields 'basepath' or 'extension' from target " +
                                "name '" + targetName + "' with pattern '" + targetNamePattern + "'");
            }
            return targetName.getFileSystem().getPath(basepath + sourceExtension);

        }
        return null;

    }

    @Override
    public Path getRenderedTargetName(Path sourceName) {
        Matcher matcher = sourceNamePattern.matcher(sourceName.toString());
        if (matcher.matches()) {
            String basepath = matcher.group("basepath");
            String extension = matcher.group("extension");
            if (basepath == null || extension == null) {
                throw new RuntimeException(
                        "Unable to extract named fields 'basepath' or 'extension' from source " +
                                "name '" + sourceName + "' with pattern '" + sourceNamePattern + "'");
            }

            return sourceName.getFileSystem().getPath(basepath + targetExtension);
        }
        throw new RuntimeException("Unable to match source name '" + sourceName + "' with pattern '" + sourceNamePattern + "'");

    }

    @Override
    public synchronized RenderedContent render(Path sourcePath, Path targetPath, Supplier byteBuffer) {
        RenderingScope scope = new RenderingScope(sourcePath, targetPath, compiler);
        if (!targetPath.toString().endsWith(".mdf")) {
            for (Path template : getTemplates(sourcePath)) {
                RenderingScope outer = new RenderingScope(template, template, compiler);
                scope = outer.wrap(scope);
            }
        }
        logger.info("SCOPE chain: " + scope.getDiagnosticSummary());
        RenderedContent rendered = scope.getRendered();
        return rendered;
    }

    private LinkedList getTemplates(Path sourcePath) {
        LinkedList chain = new LinkedList<>();
        sourcePath.normalize();
        Path directoryPath = sourcePath.getParent();
        String[] parts = sourcePath.toString().split("\\.");
        String extension = parts[parts.length - 1];

        try {
            Path localTmpl = directoryPath.resolve("_." + extension);
            FileSystemProvider provider = localTmpl.getFileSystem().provider();
            if (Files.exists(localTmpl)) {
                chain.addLast(localTmpl);
            }
//            provider.checkAccess(localTmpl, AccessMode.READ);
//            chain.addLast(localTmpl);
        } catch (Exception ignored) {
        }

        while (directoryPath != null) {
            try {
                Path localTmpl = directoryPath.resolve("__." + extension);
                directoryPath = directoryPath.getParent();
                if (Files.exists(localTmpl)) {
                    chain.addLast(localTmpl);
                }
//                localTmpl.getFileSystem().provider().checkAccess(localTmpl, AccessMode.READ);
//                chain.addLast(localTmpl);
            } catch (Exception ignored) {
            }
        }
        return chain;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb
                .append(compiler.toString())
                .append(this.sourceExtension)
                .append("→")
                .append(this.targetExtension)
                .append(")");
        return sb.toString();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy