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

org.finos.legend.sdlc.server.project.CachingFileAccessContext Maven / Gradle / Ivy

There is a newer version: 0.177.4
Show newest version
// Copyright 2020 Goldman Sachs
//
// 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.finos.legend.sdlc.server.project;

import org.eclipse.collections.api.factory.Maps;
import org.eclipse.collections.api.list.MutableList;
import org.eclipse.collections.api.map.MutableMap;
import org.finos.legend.sdlc.server.project.ProjectFileAccessProvider.FileAccessContext;
import org.finos.legend.sdlc.server.project.ProjectFileAccessProvider.ProjectFile;

import java.util.Map;
import java.util.stream.Stream;

public class CachingFileAccessContext extends AbstractFileAccessContext
{
    private final FileAccessContext delegate;
    private final MutableMap cache = Maps.mutable.empty();
    private boolean isCacheFull = false;

    private CachingFileAccessContext(FileAccessContext delegate)
    {
        this.delegate = delegate;
    }

    @Override
    protected Stream getFilesInCanonicalDirectories(MutableList directories)
    {
        fillCache();
        Stream> stream = this.cache.entrySet().stream();
        if (directories.size() == 1)
        {
            String directory = directories.get(0);
            if (!ProjectPaths.ROOT_DIRECTORY.equals(directory))
            {
                stream = stream.filter(f -> f.getKey().startsWith(directory));
            }
        }
        else
        {
            stream = stream.filter(f ->
            {
                String path = f.getKey();
                return directories.anySatisfy(path::startsWith);
            });
        }
        return stream.map(e -> ProjectFiles.newByteArrayProjectFile(e.getKey(), e.getValue()));
    }

    @Override
    public ProjectFile getFile(String path)
    {
        String canonicalPath = canonicalizePath(path);
        byte[] bytes = getFileBytes(canonicalPath);
        return (bytes == null) ? null : ProjectFiles.newByteArrayProjectFile(canonicalPath, bytes);
    }

    private byte[] getFileBytes(String canonicalPath)
    {
        synchronized (this.cache)
        {
            return this.isCacheFull ?
                    this.cache.get(canonicalPath) :
                    this.cache.getIfAbsentPutWithKey(canonicalPath, this::getFileBytesFromDelegate);
        }
    }

    private byte[] getFileBytesFromDelegate(String canonicalPath)
    {
        ProjectFile file = this.delegate.getFile(canonicalPath);
        return (file == null) ? null : file.getContentAsBytes();
    }

    public void fillCache()
    {
        synchronized (this.cache)
        {
            if (!this.isCacheFull)
            {
                this.delegate.getFiles().forEach(pf -> this.cache.getIfAbsentPut(pf.getPath(), pf::getContentAsBytes));
                this.isCacheFull = true;
            }
        }
    }

    public static CachingFileAccessContext wrap(FileAccessContext fileAccessContext)
    {
        if (fileAccessContext == null)
        {
            return null;
        }
        if (fileAccessContext instanceof CachingFileAccessContext)
        {
            return (CachingFileAccessContext) fileAccessContext;
        }
        return new CachingFileAccessContext(fileAccessContext);
    }

    private static String canonicalizePath(String path)
    {
        int pathLength = path.length();
        switch (pathLength)
        {
            case 0:
            {
                return "/";
            }
            case 1:
            {
                return (path.charAt(0) == '/') ? path : ("/" + path);
            }
            default:
            {
                int lastIndex = pathLength - 1;
                return (path.charAt(0) == '/') ?
                        ((path.charAt(lastIndex) == '/') ? path.substring(0, lastIndex) : path) :
                        ((path.charAt(lastIndex) == '/') ? ("/" + path.substring(0, lastIndex)) : ("/" + path));
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy