org.kie.workbench.common.stunner.backend.service.DiagramServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.kie.workbench.common.stunner.backend.service.DiagramServiceImpl.java

Source

/*
 * Copyright 2017 Red Hat, Inc. and/or its affiliates.
 *
 * 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.kie.workbench.common.stunner.backend.service;

import java.io.File;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
import javax.annotation.PostConstruct;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.ServletContext;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jboss.errai.bus.server.annotations.Service;
import org.jboss.errai.bus.server.api.RpcContext;
import org.kie.workbench.common.stunner.core.api.DefinitionManager;
import org.kie.workbench.common.stunner.core.api.FactoryManager;
import org.kie.workbench.common.stunner.core.backend.service.AbstractVFSDiagramService;
import org.kie.workbench.common.stunner.core.definition.service.DefinitionSetService;
import org.kie.workbench.common.stunner.core.diagram.Diagram;
import org.kie.workbench.common.stunner.core.diagram.Metadata;
import org.kie.workbench.common.stunner.core.diagram.MetadataImpl;
import org.kie.workbench.common.stunner.core.graph.Graph;
import org.kie.workbench.common.stunner.core.registry.BackendRegistryFactory;
import org.kie.workbench.common.stunner.core.service.DiagramService;
import org.kie.workbench.common.stunner.core.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.uberfire.backend.server.util.Paths;
import org.uberfire.backend.vfs.Path;
import org.uberfire.io.IOService;
import org.uberfire.java.nio.file.FileSystem;
import org.uberfire.java.nio.file.FileSystemAlreadyExistsException;
import org.uberfire.java.nio.file.StandardDeleteOption;

@Service
public class DiagramServiceImpl extends AbstractVFSDiagramService<Metadata, Diagram<Graph, Metadata>>
        implements DiagramService {

    private static final Logger LOG = LoggerFactory.getLogger(DiagramServiceImpl.class.getName());

    private static final String METADATA_EXTENSION = "meta";
    private static final String VFS_ROOT_PATH = "default://stunner";
    private static final String VFS_DIAGRAMS_PATH = "diagrams";
    private static final String APP_DIAGRAMS_PATH = "WEB-INF/diagrams";

    private FileSystem fileSystem;
    private org.uberfire.java.nio.file.Path root;

    protected DiagramServiceImpl() {
        this(null, null, null, null, null);
    }

    @Inject
    public DiagramServiceImpl(final DefinitionManager definitionManager, final FactoryManager factoryManager,
            final Instance<DefinitionSetService> definitionSetServiceInstances,
            final @Named("ioStrategy") IOService ioService, final BackendRegistryFactory registryFactory) {
        super(definitionManager, factoryManager, definitionSetServiceInstances, ioService, registryFactory);
    }

    @PostConstruct
    public void init() {
        // Initialize caches.
        super.initialize();
        // Initialize the application's VFS.
        initFileSystem();
        // Register packaged diagrams into VFS.
        registerAppDefinitions();
        // Load vfs diagrams and put into the parent registry.
        final Collection<Diagram<Graph, Metadata>> diagrams = getAllDiagrams();
        if (null != diagrams) {
            diagrams.forEach(diagram -> getRegistry().register(diagram));
        }
    }

    @Override
    public Path create(final Path path, final String name, final String defSetId) {
        return super.create(path, name, defSetId, buildMetadataInstance(path, defSetId, name));
    }

    @Override
    protected Metadata buildMetadataInstance(final org.uberfire.backend.vfs.Path path, String defSetId,
            String title) {
        return new MetadataImpl.MetadataImplBuilder(defSetId, getDefinitionManager()).setPath(path).setTitle(title)
                .build();
    }

    @Override
    protected InputStream loadMetadataForPath(final Path path) {
        return doLoadMetadataStreamByDiagramPath(path);
    }

    @Override
    protected Class<? extends Metadata> getMetadataType() {
        return Metadata.class;
    }

    @Override
    protected Metadata doSave(final Diagram diagram, final String raw, final String metadata) {
        try {
            getIoService().startBatch(fileSystem);
            final Path _path = diagram.getMetadata().getPath();
            final String name = null != _path ? _path.getFileName() : getNewFileName(diagram);
            final org.uberfire.java.nio.file.Path path = null != _path ? Paths.convert(_path)
                    : getDiagramsPath().resolve(name);
            // Serialize the diagram's raw data.
            LOG.debug("Serializing raw data: " + raw);
            getIoService().write(path, raw);
            final String metadataFileName = getMetadataFileName(name);
            final org.uberfire.java.nio.file.Path metadataPath = getDiagramsPath().resolve(metadataFileName);
            LOG.debug("Serializing raw metadadata: " + metadata);
            getIoService().write(metadataPath, metadata);
            diagram.getMetadata().setPath(Paths.convert(path));
        } catch (Exception e) {
            LOG.error("Error serializing diagram with UUID [" + diagram.getName() + "].", e);
        } finally {
            getIoService().endBatch();
        }
        return diagram.getMetadata();
    }

    private String getNewFileName(final Diagram diagram) {
        final String defSetId = diagram.getMetadata().getDefinitionSetId();
        final DefinitionSetService defSetService = getServiceById(defSetId);
        return UUID.uuid(8) + "." + defSetService.getResourceType().getSuffix();
    }

    @Override
    protected boolean doDelete(final Path _path) {
        final org.uberfire.java.nio.file.Path path = Paths.convert(_path);
        if (getIoService().exists(path)) {
            getIoService().startBatch(fileSystem);
            try {
                getIoService().deleteIfExists(path, StandardDeleteOption.NON_EMPTY_DIRECTORIES);
            } catch (Exception e) {
                LOG.error("Error deleting diagram for path [" + path + "].", e);
                return false;
            } finally {
                getIoService().endBatch();
            }
        }
        return true;
    }

    private InputStream doLoadMetadataStreamByDiagramPath(final Path dPath) {
        org.uberfire.java.nio.file.Path path = getDiagramsPath().resolve(getMetadataFileName(dPath.getFileName()));
        if (null != path) {
            try {
                return loadPath(path);
            } catch (Exception e) {
                LOG.warn("Cannot load metadata for [" + dPath.toString() + "].", e);
            }
        }
        return null;
    }

    private String getMetadataFileName(final String uri) {
        return uri + "." + METADATA_EXTENSION;
    }

    private Collection<Diagram<Graph, Metadata>> getAllDiagrams() {
        return getDiagramsByPath(root);
    }

    private void registerAppDefinitions() {
        deployAppDiagrams(APP_DIAGRAMS_PATH);
    }

    private void initFileSystem() {
        try {
            fileSystem = getIoService().newFileSystem(URI.create(VFS_ROOT_PATH), new HashMap<String, Object>() {
                {
                    put("init", Boolean.TRUE);
                    put("internal", Boolean.TRUE);
                }
            });
        } catch (FileSystemAlreadyExistsException e) {
            fileSystem = getIoService().getFileSystem(URI.create(VFS_ROOT_PATH));
        }
        this.root = fileSystem.getRootDirectories().iterator().next();
    }

    private void deployAppDiagrams(final String path) {
        ServletContext servletContext = RpcContext.getServletRequest().getServletContext();
        if (null != servletContext) {
            String dir = servletContext.getRealPath(path);
            if (dir != null && new File(dir).exists()) {
                dir = dir.replaceAll("\\\\", "/");
                findAndDeployDiagrams(dir);
            }
        } else {
            LOG.warn("No servlet context available. Cannot deploy the application diagrams.");
        }
    }

    private void findAndDeployDiagrams(final String directory) {
        if (!StringUtils.isBlank(directory)) {
            // Look for data sets deploy
            File[] files = new File(directory).listFiles(_deployFilter);
            if (files != null) {
                for (File f : files) {
                    try {
                        String name = f.getName();
                        if (isFileNameAccepted(name)) {
                            // Register it into VFS storage.
                            registerIntoVFS(f);
                        }
                    } catch (Exception e) {
                        LOG.error("Error loading the application default diagrams.", e);
                    }
                }
            }
        }
    }

    private void registerIntoVFS(final File file) {
        String name = file.getName();
        org.uberfire.java.nio.file.Path actualPath = getDiagramsPath().resolve(name);
        boolean exists = getIoService().exists(actualPath);
        if (!exists) {
            getIoService().startBatch(fileSystem);
            try {
                String content = FileUtils.readFileToString(file);
                org.uberfire.java.nio.file.Path diagramPath = getDiagramsPath().resolve(file.getName());
                getIoService().write(diagramPath, content);
            } catch (Exception e) {
                LOG.error("Error registering diagram into app's VFS", e);
            } finally {
                getIoService().endBatch();
            }
        } else {
            LOG.warn("Diagram [" + name
                    + "] already exists on VFS storage. This file should not be longer present here.");
        }
    }

    public org.uberfire.java.nio.file.Path getDiagramsPath() {
        return root.resolve(VFS_DIAGRAMS_PATH);
    }

    private boolean isFileNameAccepted(final String name) {
        if (name != null && name.trim().length() > 0) {
            return getExtensionsAccepted().stream().anyMatch(s -> name.endsWith("." + s)) || isMetadataFile(name);
        }
        return false;
    }

    private boolean isMetadataFile(final String name) {
        return null != name && name.endsWith("." + METADATA_EXTENSION);
    }

    private FilenameFilter _deployFilter = (dir, name) -> true;
}