org.smartdeveloperhub.vocabulary.util.SerializationManager.java Source code

Java tutorial

Introduction

Here is the source code for org.smartdeveloperhub.vocabulary.util.SerializationManager.java

Source

/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the Smart Developer Hub Project:
 *     http://www.smartdeveloperhub.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2015-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.smartdeveloperhub.vocabulary:sdh-vocabulary:0.3.0
 *   Bundle      : sdh-vocabulary-0.3.0.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.smartdeveloperhub.vocabulary.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smartdeveloperhub.vocabulary.util.Module.Format;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

public final class SerializationManager {

    private static final class SerializationHelper {

        private final ModuleHelper helper;
        private final Path where;
        private final String fileName;
        private final Module module;

        SerializationHelper(final Module module, final Path where) throws IOException {
            this.module = module;
            this.where = where;
            this.helper = getHelper(module);
            this.fileName = MorePaths.getFileName(module.location());
        }

        Path serialize(final Format format) throws IOException {
            if (format.equals(this.module.format())) {
                return copyCanonicalSerialization();
            } else {
                return transformCanonicalSerialization(format);
            }
        }

        private Path transformCanonicalSerialization(final Format format) throws IOException {
            final Path target = this.where.resolve(this.fileName + "." + format.fileExtension());
            try {
                final String transformed = this.helper.export(format);
                Files.copy(new ByteArrayInputStream(transformed.getBytes(StandardCharsets.UTF_8)), target,
                        StandardCopyOption.REPLACE_EXISTING);
                return target;
            } catch (final IOException e) {
                throw new IOException("Could not copy " + format.getName() + " serialization of module "
                        + this.module.location() + " [" + this.module.format().getName() + "] to " + target, e);
            }
        }

        private Path copyCanonicalSerialization() throws IOException {
            final Path target = this.where
                    .resolve(this.fileName + "." + MorePaths.getFileExtension(this.module.location()));
            try {
                Files.copy(this.module.location(), target, StandardCopyOption.REPLACE_EXISTING);
                return target;
            } catch (final IOException e) {
                throw new IOException("Could not copy canonical serialization of module " + this.module.location()
                        + " [" + this.module.format().getName() + "] to " + target);
            }
        }

        private static ModuleHelper getHelper(final Module module) throws IOException {
            ModuleHelper helper;
            try {
                helper = new ModuleHelper(module.location()).load(module.locationNamespace(), module.format());
            } catch (final IOException e) {
                throw new IOException(
                        "Could not load module " + module.location() + " [" + module.format().getName() + "]", e);
            }
            return helper;
        }

    }

    private static final class SerializationKey {

        private final String module;
        private final String format;
        private final String charset;

        private SerializationKey(final String module, final String format, final String charset) {
            this.module = module;
            this.format = format;
            this.charset = charset;
        }

        @Override
        public int hashCode() {
            return Objects.hash(this.module, this.format, this.charset);
        }

        @Override
        public boolean equals(final Object obj) {
            boolean result = false;
            if (obj instanceof SerializationKey) {
                final SerializationKey that = (SerializationKey) obj;
                result = Objects.equals(this.module, that.module) && Objects.equals(this.format, that.format)
                        && Objects.equals(this.charset, that.charset);
            }
            return result;
        }

        @Override
        public String toString() {
            return this.format + " [" + this.charset + "] serialization for module " + this.module;
        }

        static SerializationKey create(final Module module, final Format format, final Charset charset) {
            return new SerializationKey(module.implementationIRI(), format.getName(), charset.toString());
        }

    }

    private static final Logger LOGGER = LoggerFactory.getLogger(SerializationManager.class);

    private final Path location;
    private final Map<Path, Map<Format, Path>> serializations;

    private final Map<SerializationKey, Lock> serialLocks;
    private final Map<SerializationKey, Path> serialFiles;

    private SerializationManager(final Path where, final Map<Path, Map<Format, Path>> serializations) {
        this.location = where;
        this.serializations = serializations;
        this.serialFiles = Maps.newLinkedHashMap();
        this.serialLocks = Maps.newLinkedHashMap();
    }

    public Path location() {
        return this.location;
    }

    public Path getSerialization(final Module module, final Format format) {
        Map<Format, Path> moduleSerializations = this.serializations.get(module.location());
        if (moduleSerializations == null) {
            moduleSerializations = Collections.emptyMap();
        }
        return moduleSerializations.get(format);
    }

    public Path getSerialization(final Module module, final Format format, final Charset targetCharset)
            throws IOException {
        final SerializationKey key = SerializationKey.create(module, format, targetCharset);
        Lock lock = null;
        synchronized (this) {
            final Path path = this.serialFiles.get(key);
            if (path != null) {
                LOGGER.debug("Found {}: {}", key, path);
                return path;
            }
            lock = this.serialLocks.get(key);
            if (lock == null) {
                lock = new ReentrantLock();
                this.serialLocks.put(key, lock);
                LOGGER.debug("Scheduled creation of {}", key);
            }
        }
        lock.lock();
        try {
            final Path target = generateSerialization(module, format, targetCharset);
            if (target != null) {
                synchronized (this) {
                    LOGGER.debug("Created {}: {}", key, target);
                    this.serialFiles.put(key, target);
                }
            }
            return target;
        } finally {
            lock.unlock();
        }
    }

    private Path generateSerialization(final Module module, final Format format, final Charset targetCharset)
            throws IOException {
        final Path source = getSerialization(module, format);
        Path target = null;
        if (source != null) {
            if (StandardCharsets.UTF_8.equals(targetCharset)) {
                target = source;
            } else {
                target = source.getParent().resolve(MorePaths.getFileName(source) + "." + targetCharset.name() + "."
                        + MorePaths.getFileExtension(source));
                IOUtil.transcode(source, StandardCharsets.UTF_8, target, targetCharset);
                target.toFile().deleteOnExit();
            }
        }
        return target;
    }

    private static Map<Format, Path> generate(final Module module, final Path where) throws IOException {
        createDirectory(where);
        final SerializationHelper helper = new SerializationHelper(module, where);
        final ImmutableMap.Builder<Format, Path> builder = ImmutableMap.builder();
        for (final Format format : Format.values()) {
            builder.put(format, helper.serialize(format));
        }
        return builder.build();
    }

    private static Map<Path, Map<Format, Path>> generate(final Catalog catalog, final Path where)
            throws IOException {
        createDirectory(where);
        final ImmutableMap.Builder<Path, Map<Format, Path>> builder = ImmutableMap.builder();
        for (final String moduleId : catalog.modules()) {
            final Module module = catalog.get(moduleId);
            final Path moduleParent = module.location().getParent();
            final Path relativeModuleParent = catalog.getRoot().relativize(moduleParent);
            final Path target = where.resolve(relativeModuleParent);
            try {
                builder.put(module.location(), generate(module, target));
            } catch (final IOException e) {
                throw new IOException("Could not generate serializations for module " + module.location() + " ["
                        + module.format().getName() + "]", e);
            }
        }
        return builder.build();
    }

    private static void createDirectory(final Path where) throws IOException {
        final File file = where.toFile();
        if (!file.exists()) {
            if (!file.mkdirs()) {
                throw new IOException("Could not create target directory '" + where + "'");
            }
        } else if (!file.isDirectory()) {
            throw new IOException("Target path '" + where + "' points to an existing file, not a directory");
        }
    }

    public static SerializationManager create(final Module module, final Path location) throws IOException {
        final Map<Path, Map<Format, Path>> serials = ImmutableMap.<Path, Map<Format, Path>>builder()
                .put(module.location(), generate(module, location)).build();
        return new SerializationManager(location, serials);
    }

    public static SerializationManager create(final Catalog catalog, final Path location) throws IOException {
        return new SerializationManager(location, generate(catalog, location));
    }

}