org.apache.streams.graph.GraphPersistWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.streams.graph.GraphPersistWriter.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 *
 *   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.apache.streams.graph;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Preconditions;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.util.EntityUtils;
import org.apache.streams.components.http.HttpPersistWriterConfiguration;
import org.apache.streams.components.http.persist.SimpleHTTPPostPersistWriter;
import org.apache.streams.config.ComponentConfigurator;
import org.apache.streams.config.StreamsConfigurator;
import org.apache.streams.core.StreamsDatum;
import org.apache.streams.graph.neo4j.CypherGraphHelper;
import org.apache.streams.jackson.StreamsJacksonMapper;
import org.apache.streams.pojo.json.Activity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Adds activityobjects as vertices and activities as edges to a graph database with
 * an http rest endpoint (such as neo4j)
 */
public class GraphPersistWriter extends SimpleHTTPPostPersistWriter {

    public static final String STREAMS_ID = GraphPersistWriter.class.getCanonicalName();

    private final static Logger LOGGER = LoggerFactory.getLogger(GraphPersistWriter.class);
    private final static long MAX_WRITE_LATENCY = 1000;

    protected GraphWriterConfiguration configuration;

    protected GraphHelper graphHelper;

    private static ObjectMapper mapper;

    protected final ReadWriteLock lock = new ReentrantReadWriteLock();

    public GraphPersistWriter() {
        this(new ComponentConfigurator<GraphWriterConfiguration>(GraphWriterConfiguration.class)
                .detectConfiguration(StreamsConfigurator.config.getConfig("graph")));
    }

    public GraphPersistWriter(GraphWriterConfiguration configuration) {
        super(StreamsJacksonMapper.getInstance().convertValue(configuration, HttpPersistWriterConfiguration.class));
        if (configuration.getType().equals(GraphConfiguration.Type.NEO_4_J)) {
            super.configuration.setResourcePath("/db/" + configuration.getGraph() + "/transaction/commit");
        } else if (configuration.getType().equals(GraphConfiguration.Type.REXSTER)) {
            super.configuration.setResourcePath("/graphs/" + configuration.getGraph());
        }
        this.configuration = configuration;
    }

    @Override
    protected ObjectNode preparePayload(StreamsDatum entry) {

        Activity activity = null;

        if (entry.getDocument() instanceof Activity) {
            activity = (Activity) entry.getDocument();
        } else if (entry.getDocument() instanceof ObjectNode) {
            activity = mapper.convertValue(entry.getDocument(), Activity.class);
        } else if (entry.getDocument() instanceof String) {
            try {
                activity = mapper.readValue((String) entry.getDocument(), Activity.class);
            } catch (Throwable e) {
                LOGGER.warn(e.getMessage());
            }
        }

        Preconditions.checkNotNull(activity);

        ObjectNode request = mapper.createObjectNode();
        ArrayNode statements = mapper.createArrayNode();

        activity.getActor().setObjectType("page");

        // always add vertices first
        // what types of verbs are relevant for adding vertices?
        if (configuration.getVertices().getVerbs().contains(activity.getVerb())) {

            // what objects and objectTypes are relevant for adding vertices?
            if (configuration.getVertices().getObjects().contains("actor")
                    && configuration.getVertices().getObjectTypes().contains(activity.getActor().getObjectType())) {
                statements.add(graphHelper.mergeVertexRequest(activity.getActor()));
            }
            if (configuration.getVertices().getObjects().contains("object") && configuration.getVertices()
                    .getObjectTypes().contains(activity.getObject().getObjectType())) {
                statements.add(graphHelper.mergeVertexRequest(activity.getObject()));
            }
            if (configuration.getVertices().getObjects().contains("provider") && configuration.getVertices()
                    .getObjectTypes().contains(activity.getProvider().getObjectType())) {
                statements.add(graphHelper.mergeVertexRequest(activity.getProvider()));
            }
            if (configuration.getVertices().getObjects().contains("target") && configuration.getVertices()
                    .getObjectTypes().contains(activity.getTarget().getObjectType())) {
                statements.add(graphHelper.mergeVertexRequest(activity.getProvider()));
            }

        }

        // what types of verbs are relevant for adding edges?
        if (configuration.getEdges().getVerbs().contains(activity.getVerb())) {

            // what objects and objectTypes are relevant for adding edges?
            if (configuration.getEdges().getObjects().contains("actor")
                    && configuration.getEdges().getObjects().contains("object")
                    && configuration.getEdges().getObjectTypes().contains(activity.getActor().getObjectType())
                    && configuration.getEdges().getObjectTypes().contains(activity.getObject().getObjectType())) {
                statements.add(graphHelper.createEdgeRequest(activity, activity.getActor(), activity.getObject()));
            }
            if (configuration.getEdges().getObjects().contains("actor")
                    && configuration.getEdges().getObjects().contains("target")
                    && configuration.getEdges().getObjectTypes().contains(activity.getActor().getObjectType())
                    && configuration.getEdges().getObjectTypes().contains(activity.getTarget().getObjectType())) {
                statements.add(graphHelper.createEdgeRequest(activity, activity.getActor(), activity.getTarget()));
            }
            if (configuration.getEdges().getObjects().contains("provider")
                    && configuration.getEdges().getObjects().contains("actor")
                    && configuration.getEdges().getObjectTypes().contains(activity.getProvider().getObjectType())
                    && configuration.getEdges().getObjectTypes().contains(activity.getActor().getObjectType())) {
                statements
                        .add(graphHelper.createEdgeRequest(activity, activity.getProvider(), activity.getActor()));
            }
        }

        request.put("statements", statements);
        return request;

    }

    @Override
    protected ObjectNode executePost(HttpPost httpPost) {

        Preconditions.checkNotNull(httpPost);

        ObjectNode result = null;

        CloseableHttpResponse response = null;

        String entityString = null;
        try {
            response = httpclient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if (response.getStatusLine().getStatusCode() == 200
                    || response.getStatusLine().getStatusCode() == 201 && entity != null) {
                entityString = EntityUtils.toString(entity);
                result = mapper.readValue(entityString, ObjectNode.class);
            }
            LOGGER.debug("Writer response:\n{}\n{}\n{}", httpPost.toString(),
                    response.getStatusLine().getStatusCode(), entityString);
            if (result == null || (result.get("errors") != null && result.get("errors").isArray()
                    && result.get("errors").iterator().hasNext())) {
                LOGGER.error("Write Error: " + result.get("errors"));
            } else {
                LOGGER.info("Write Success");
            }
        } catch (IOException e) {
            LOGGER.error("IO error:\n{}\n{}\n{}", httpPost.toString(), response, e.getMessage());
        } catch (Exception e) {
            LOGGER.error("Write Exception:\n{}\n{}\n{}", httpPost.toString(), response, e.getMessage());
        } finally {
            try {
                if (response != null)
                    response.close();
            } catch (IOException e) {
            }
        }
        return result;
    }

    @Override
    public void prepare(Object configurationObject) {

        super.prepare(configurationObject);
        mapper = StreamsJacksonMapper.getInstance();

        if (configuration.getType().equals(GraphConfiguration.Type.NEO_4_J)) {
            graphHelper = new CypherGraphHelper();
        }

        Preconditions.checkNotNull(graphHelper);
    }

    @Override
    public void cleanUp() {

        LOGGER.info("exiting");

    }

}