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

org.finos.legend.sdlc.entities.EntityReserializer Maven / Gradle / Ivy

The newest version!
// Copyright 2021 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.entities;

import org.eclipse.collections.api.RichIterable;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.MutableList;
import org.eclipse.collections.impl.utility.Iterate;
import org.finos.legend.sdlc.domain.model.entity.Entity;
import org.finos.legend.sdlc.serialization.EntitySerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.function.Predicate;

public class EntityReserializer
{
    private static final Logger LOGGER = LoggerFactory.getLogger(EntityReserializer.class);

    private final EntitySerializer sourceSerializer;
    private final EntitySerializer targetSerializer;
    private final String targetFileExtension;

    private EntityReserializer(EntitySerializer sourceSerializer, EntitySerializer targetSerializer, String targetFileExtension)
    {
        this.sourceSerializer = sourceSerializer;
        this.targetSerializer = targetSerializer;
        this.targetFileExtension = (targetFileExtension == null) ? this.targetSerializer.getDefaultFileExtension() : targetFileExtension;
    }

    public List reserializeDirectoryTree(Path sourceDirectory, Path targetDirectory) throws IOException
    {
        return reserializeDirectoryTree(sourceDirectory, null, targetDirectory);
    }

    public List reserializeDirectoryTree(Path sourceDirectory, Predicate filter, Path targetDirectory) throws IOException
    {
        return reserializeDirectoryTree(sourceDirectory, filter, targetDirectory, true);
    }

    public List reserializeDirectoryTree(Path sourceDirectory, Predicate filter, Path targetDirectory, boolean enforceOneEntityPerFile) throws IOException
    {
        if (Files.notExists(sourceDirectory))
        {
            LOGGER.debug("Source directory {} does not exist: no entities reserialized to {}", sourceDirectory, targetDirectory);
            return Collections.emptyList();
        }

        Path targetEntitiesDirectory = targetDirectory.resolve("entities");

        List entityPaths = Lists.mutable.empty();
        Deque directories = new ArrayDeque<>();
        directories.add(sourceDirectory);
        while (!directories.isEmpty())
        {
            Path directory = directories.removeFirst();
            try (DirectoryStream dirStream = Files.newDirectoryStream(directory))
            {
                for (Path entry : dirStream)
                {
                    if (Files.isDirectory(entry))
                    {
                        directories.addLast(entry);
                    }
                    else if ((filter == null) || filter.test(entry))
                    {
                        entityPaths.addAll(reserializeFile(sourceDirectory, entry, targetEntitiesDirectory, enforceOneEntityPerFile));
                    }
                }
            }
        }

        return entityPaths;
    }

    public Predicate getDefaultExtensionFilter()
    {
        return getExtensionFilter(this.sourceSerializer.getDefaultFileExtension());
    }

    private List reserializeFile(Path sourceDirectory, Path sourceFile, Path targetDirectory, boolean enforceOneEntityPerFile) throws IOException
    {
        LOGGER.debug("Reading {}", sourceFile);
        List entities;
        try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(sourceFile)))
        {
            if (enforceOneEntityPerFile)
            {
                Entity singleEntity = this.sourceSerializer.deserialize(inputStream);
                Path expectedPath = sourceSerializer.filePathForEntity(singleEntity, sourceDirectory);
                if (!sourceFile.equals(expectedPath))
                {
                    throw new RuntimeException("Expected entity with path " + singleEntity.getPath() + " to be located on " + expectedPath);
                }
                entities = Collections.singletonList(singleEntity);
            }
            else
            {
                entities = this.sourceSerializer.deserializeMany(inputStream);
            }
        }
        catch (Exception e)
        {
            StringBuilder builder = new StringBuilder("Error deserializing entity from ").append(sourceFile);
            String eMessage = e.getMessage();
            if (eMessage != null)
            {
                builder.append(": ").append(eMessage);
            }
            String message = builder.toString();
            LOGGER.debug(message, e);
            if (e instanceof IOException)
            {
                throw new IOException(message, e);
            }
            throw new RuntimeException(message, e);
        }

        LOGGER.debug("Finished reading {}", sourceFile);
        List entityPaths = Lists.mutable.empty();
        for (Entity entity : entities)
        {
            String entityPath = entity.getPath();
            Path targetFile = this.targetSerializer.filePathForEntity(entity, targetDirectory, this.targetFileExtension);
            LOGGER.debug("Writing {} to {}", entityPath, targetFile);
            Files.createDirectories(targetFile.getParent());
            try (OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(targetFile, StandardOpenOption.CREATE_NEW)))
            {
                this.targetSerializer.serialize(entity, outputStream);
            }
            catch (Exception e)
            {
                StringBuilder builder = new StringBuilder("Error serializing entity '").append(entityPath).append("' to ").append(targetFile);
                if (e instanceof FileAlreadyExistsException)
                {
                    builder.append(": target file already exists");
                }
                else
                {
                    String eMessage = e.getMessage();
                    if (eMessage != null)
                    {
                        builder.append(": ").append(eMessage);
                    }
                }
                String message = builder.toString();
                LOGGER.debug(message, e);
                if (e instanceof IOException)
                {
                    throw new IOException(message, e);
                }
                throw new RuntimeException(message, e);
            }
            LOGGER.debug("Finished writing {} to {}", entityPath, targetFile);
            entityPaths.add(entityPath);
        }

        return entityPaths;
    }

    public static EntityReserializer newReserializer(EntitySerializer sourceSerializer, EntitySerializer targetSerializer, String targetFileExtension)
    {
        return new EntityReserializer(sourceSerializer, targetSerializer, targetFileExtension);
    }

    public static EntityReserializer newReserializer(EntitySerializer sourceSerializer, EntitySerializer targetSerializer)
    {
        return newReserializer(sourceSerializer, targetSerializer, null);
    }

    public static Predicate getExtensionFilter(String extension)
    {
        String canonicalExtension = canonicalizeFileExtension(extension);
        return (canonicalExtension == null) ? EntityReserializer::hasNoExtension : p -> hasExtension(p, canonicalExtension);
    }

    public static Predicate getExtensionsFilter(String... extensions)
    {
        return getExtensionsFilter(Arrays.asList(extensions));
    }

    public static Predicate getExtensionsFilter(Collection extensions)
    {
        switch (extensions.size())
        {
            case 0:
            {
                return p -> false;
            }
            case 1:
            {
                return getExtensionFilter(Iterate.getFirst(extensions));
            }
            default:
            {
                MutableList canonicalExtensions = Iterate.collect(extensions, EntityReserializer::canonicalizeFileExtension, Lists.mutable.ofInitialCapacity(extensions.size()));
                return p -> hasAnyExtension(p, canonicalExtensions);
            }
        }
    }

    private static boolean hasNoExtension(Path path)
    {
        return hasNoExtension(path.getFileName().toString());
    }

    private static boolean hasNoExtension(String fileName)
    {
        return fileName.lastIndexOf('.') == -1;
    }

    private static boolean hasExtension(Path path, String canonicalExtension)
    {
        return hasExtension(path.getFileName().toString(), canonicalExtension);
    }

    private static boolean hasExtension(String fileName, String canonicalExtension)
    {
        return fileName.endsWith(canonicalExtension);
    }

    private static boolean hasAnyExtension(Path path, RichIterable canonicalExtensions)
    {
        String fileName = path.getFileName().toString();
        return canonicalExtensions.anySatisfy(ex -> (ex == null) ? hasNoExtension(fileName) : hasExtension(fileName, ex));
    }

    private static String canonicalizeFileExtension(String extension)
    {
        if ((extension == null) || extension.isEmpty())
        {
            return null;
        }
        if (extension.charAt(0) != '.')
        {
            return "." + extension;
        }
        return extension;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy