org.opennms.features.topology.plugins.topo.graphml.GraphMLEdgeStatusProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.opennms.features.topology.plugins.topo.graphml.GraphMLEdgeStatusProvider.java

Source

/*******************************************************************************
 * This file is part of OpenNMS(R).
 *
 * Copyright (C) 2016 The OpenNMS Group, Inc.
 * OpenNMS(R) is Copyright (C) 1999-2016 The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * OpenNMS(R) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with OpenNMS(R).  If not, see:
 *      http://www.gnu.org/licenses/
 *
 * For more information contact:
 *     OpenNMS(R) Licensing <license@opennms.org>
 *     http://www.opennms.org/
 *     http://www.opennms.com/
 *******************************************************************************/

package org.opennms.features.topology.plugins.topo.graphml;

import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import javax.script.SimpleScriptContext;

import org.apache.commons.io.FilenameUtils;
import org.opennms.features.topology.api.info.MeasurementsWrapper;
import org.opennms.features.topology.api.topo.AbstractVertex;
import org.opennms.features.topology.api.topo.Criteria;
import org.opennms.features.topology.api.topo.EdgeProvider;
import org.opennms.features.topology.api.topo.EdgeRef;
import org.opennms.features.topology.api.topo.EdgeStatusProvider;
import org.opennms.features.topology.api.topo.SimpleConnector;
import org.opennms.features.topology.api.topo.Status;
import org.opennms.features.topology.plugins.topo.graphml.internal.GraphMLServiceAccessor;
import org.opennms.netmgt.model.OnmsNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;

public class GraphMLEdgeStatusProvider implements EdgeStatusProvider {

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

    /**
     * Representation for the script to execute.
     */
    private class StatusScript {

        private final ScriptEngine engine;
        private final String source;

        /**
         * Indicator if script has been compiled.
         * If null, not determined yet if compilable at all.
         */
        private Optional<CompiledScript> compiledScript = null;

        private StatusScript(final ScriptEngine engine, final String source) {
            this.engine = Objects.requireNonNull(engine);
            this.source = Objects.requireNonNull(source);
        }

        public GraphMLEdgeStatus eval(final ScriptContext context) throws ScriptException {
            if (this.compiledScript == null) {
                if (this.engine instanceof Compilable) {
                    this.compiledScript = Optional.of(((Compilable) engine).compile(source));
                } else {
                    this.compiledScript = Optional.empty();
                }
            }
            if (this.compiledScript.isPresent()) {
                return (GraphMLEdgeStatus) this.compiledScript.get().eval(context);

            } else {
                return (GraphMLEdgeStatus) this.engine.eval(this.source, context);
            }
        }
    }

    private final Path scriptPath;
    private final GraphMLTopologyProvider provider;
    private final ScriptEngineManager scriptEngineManager;
    private final GraphMLServiceAccessor serviceAccessor;

    public GraphMLEdgeStatusProvider(final GraphMLTopologyProvider provider,
            final ScriptEngineManager scriptEngineManager, final GraphMLServiceAccessor serviceAccessor,
            final Path scriptPath) {
        this.provider = Objects.requireNonNull(provider);
        this.scriptEngineManager = Objects.requireNonNull(scriptEngineManager);
        this.serviceAccessor = Objects.requireNonNull(serviceAccessor);
        this.scriptPath = Objects.requireNonNull(scriptPath);
    }

    public GraphMLEdgeStatusProvider(final GraphMLTopologyProvider provider,
            final ScriptEngineManager scriptEngineManager, final GraphMLServiceAccessor serviceAccessor) {
        this(provider, scriptEngineManager, serviceAccessor,
                Paths.get(System.getProperty("opennms.home"), "etc", "graphml-edge-status"));
    }

    @Override
    public Map<EdgeRef, Status> getStatusForEdges(EdgeProvider edgeProvider, Collection<EdgeRef> edges,
            Criteria[] criteria) {
        final List<StatusScript> scripts = Lists.newArrayList();
        try (final DirectoryStream<Path> stream = Files.newDirectoryStream(getScriptPath())) {
            for (final Path path : stream) {
                final String extension = FilenameUtils.getExtension(path.toString());
                final ScriptEngine scriptEngine = this.scriptEngineManager.getEngineByExtension(extension);
                if (scriptEngine == null) {
                    LOG.warn("No script engine found for extension '{}'", extension);
                    continue;
                }
                LOG.debug("Found script: path={}, extension={}, engine={}", path, extension, scriptEngine);
                try (final Stream<String> lines = Files.lines(path, Charset.defaultCharset())) {
                    final String source = lines.collect(Collectors.joining("\n"));
                    scripts.add(new StatusScript(scriptEngine, source));
                }
            }
        } catch (final IOException e) {
            LOG.error("Failed to walk template directory: {}", getScriptPath());
            return Collections.emptyMap();
        }

        return serviceAccessor.getTransactionOperations()
                .execute(transactionStatus -> edges.stream().filter(eachEdge -> eachEdge instanceof GraphMLEdge)
                        .map(edge -> (GraphMLEdge) edge)
                        .map(edge -> new HashMap.SimpleEntry<>(edge, computeEdgeStatus(scripts, edge)))
                        .filter(e -> e.getValue() != null)
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
    }

    @Override
    public String getNamespace() {
        return provider.getVertexNamespace();
    }

    @Override
    public boolean contributesTo(String namespace) {
        return getNamespace().equals(namespace);
    }

    public Path getScriptPath() {
        return scriptPath;
    }

    private GraphMLEdgeStatus computeEdgeStatus(final List<StatusScript> scripts, final GraphMLEdge edge) {
        return scripts.stream().flatMap(script -> {
            final SimpleBindings bindings = createBindings(edge);
            final StringWriter writer = new StringWriter();
            final ScriptContext context = new SimpleScriptContext();
            context.setWriter(writer);
            context.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
            try {
                LOG.debug("Executing script: {}", script);
                final GraphMLEdgeStatus status = script.eval(context);
                if (status != null) {
                    return Stream.of(status);
                } else {
                    return Stream.empty();
                }
            } catch (final ScriptException e) {
                LOG.error("Failed to execute script: {}", e);
                return Stream.empty();
            } finally {
                LOG.info(writer.toString());
            }
        }).reduce(GraphMLEdgeStatus::merge).orElse(null);
    }

    private SimpleBindings createBindings(GraphMLEdge edge) {
        SimpleBindings bindings = new SimpleBindings();
        bindings.put("edge", edge);
        bindings.put("sourceNode", getNodeForEdgeVertexConnector(edge.getSource()));
        bindings.put("targetNode", getNodeForEdgeVertexConnector(edge.getTarget()));
        bindings.put("measurements", new MeasurementsWrapper(serviceAccessor.getMeasurementsService()));
        bindings.put("nodeDao", serviceAccessor.getNodeDao());
        bindings.put("snmpInterfaceDao", serviceAccessor.getSnmpInterfaceDao());
        return bindings;
    }

    private OnmsNode getNodeForEdgeVertexConnector(SimpleConnector simpleConnector) {
        if (simpleConnector != null && simpleConnector.getVertex() instanceof AbstractVertex) {
            AbstractVertex abstractVertex = (AbstractVertex) simpleConnector.getVertex();
            if (abstractVertex.getNodeID() != null) {
                return serviceAccessor.getNodeDao().get(abstractVertex.getNodeID());
            }
        }
        return null;
    }
}