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

com.ibm.cp4waiops.connectors.sdk.TicketAction Maven / Gradle / Ivy

There is a newer version: 2.2.8
Show newest version
package com.ibm.cp4waiops.connectors.sdk;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.OffsetDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Map.Entry;

import org.json.JSONObject;

import com.ibm.cp4waiops.connectors.sdk.models.Ticket;

import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;

public class TicketAction {
    protected ConnectorBase connector = null;
    protected String sourceName = null;
    protected Map mapping;
    protected String partition = null;
    protected String instance = null;
    protected String connMode = null;

    public static final String TOPIC_OUTPUT_ACTION_SNOW = "cp4waiops-cartridge.connector-snow-actions";
    public static final String TOPIC_OUTPUT_INCIDENT = "cp4waiops-cartridge.incident";
    public static final String TOPIC_OUTPUT_CHANGE_REQUEST = "cp4waiops-cartridge.changerequest";
    public static final String TOPIC_INPUT_REQUESTS = "cp4waiops-cartridge.lifecycle.output.connector-requests";
    public static final String TOPIC_OUTPUT_RESPONSES = "cp4waiops-cartridge.lifecycle.input.connector-responses";
    public static final String TOPIC_LIFECYCLE_INPUT_EVENTS = "cp4waiops-cartridge.lifecycle.input.events";

    static final String CE_CONNECTION_MODE = "connectionmode";
    static final String CONNECTION_ID = "connection_id";
    static final String INSTANCE = "instance";
    final static String CHANGE_REQUEST_DISC = "com.ibm.sdlc.snow.changerequest.discovered";
    final static String INCIDENT_DISC = "com.ibm.sdlc.snow.incident.discovered";
    final static String SOURCE_NAME = "source_name";

    static final String RESPONSE_TIME_CE_EXT = "responsetime";
    static final URI SELF_SOURCE = URI.create("template.connectors.aiops.watson.ibm.com/connectorsnow");
    static final String COMPONENT_NAME_CE_EXTENSION_NAME = "componentname";
    static final String CONNECTION_ID_CE_EXTENSION_NAME = "connectionid";
    static final String SYSTEM_NAME_CE_EXTENSION_NAME = "systemname";
    static final String TOOL_TYPE = "tooltype";
    public final static String TOOL_TYPE_SNOW = "com.ibm.sdlc.type.snow";
    static final String CE_EXT_STRUCTURED_CONTENT_MODE = "structuredcontentmode";
    static final String CE_EXT_STRUCTURED_CONTENT_MODE_VALUE = "true";

    static final String CONNECTION_MODE_HISTORICAL = "historical";
    static final String CONNECTION_MODE_LIVE = "live";

    ElasticHelper elasticHelper = null;

    static final Logger logger = Logger.getLogger(TicketAction.class.getName());

    /**
     * Perform actions with a ticket type
     * 
     * @param connector
     *            the connector used for querying ticket information. The connector contains key information required
     *            for AI training and inference
     * @param mapping
     *            if mapping is provided, call the applyMapping function in this class to allow custom fields to be used
     *            in place of expected ones
     * @param sourceName
     *            the name of the source where the data comes from
     * @param instance
     *            the instance name of the connector
     * @param connMode
     *            the connection mode, can be live or historic
     */
    public TicketAction(ConnectorBase connector, Map mapping, String sourceName, String instance,
            String connMode) {
        this.connector = connector;
        this.mapping = mapping;
        this.sourceName = sourceName;
        this.partition = getPartition();
        this.instance = instance;
        this.connMode = connMode;

        try {
            elasticHelper = new ElasticHelper();
        } catch (PropertyReadException e) {
            logger.log(Level.WARNING,
                    "Failed to setup elastic helper due to missing elastic variables: " + e.getMessage());
        }
    }

    /**
     * Create Kafka message containing incident data, to be used by AI training or inference.
     * 
     * @param ticket
     *            data to be put onto Kafka
     * @param source
     *            the source of this data, typically an identifiable URI
     */
    public void emitIncident(Ticket ticket, String source) {
        try {
            connector.emitCloudEvent(TOPIC_OUTPUT_INCIDENT, partition, getIncidentCE(ticket, source));
        } catch (Exception e) {
            logger.log(Level.WARNING, "Failed to emit incident to Kafka due to error: " + e.getMessage(), e);
        }
    }

    /**
     * Create Kafka message containing change request data, to be used by AI training or inference.
     * 
     * @param ticket
     *            data to be put onto Kafka
     * @param source
     *            the source of this data, typically an identifiable URI
     */
    public void emitChangeRequest(Ticket ticket, String source) {
        try {
            connector.emitCloudEvent(TOPIC_OUTPUT_CHANGE_REQUEST, partition, getChangeRequestCE(ticket, source));
        } catch (Exception e) {
            logger.log(Level.WARNING, "Failed to emit change request to Kafka due to error: " + e.getMessage(), e);
        }
    }

    public CloudEvent getIncidentCE(Ticket ticket, String source) throws JsonProcessingException {
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        String json = ow.writeValueAsString(ticket);

        return getIncidentCE(new JSONObject(json), source);
    }

    public CloudEvent getChangeRequestCE(Ticket ticket, String source) throws JsonProcessingException {
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        String json = ow.writeValueAsString(ticket);

        return getChangeRequestCE(new JSONObject(json), source);
    }

    /**
     * Takes an incident JSON and adds the expected Cloud Event properties
     * 
     * @param incident
     *            incident data in JSON format
     * @param source
     *            the source of the data for identifying where the event came from
     * 
     * @return
     */
    protected CloudEvent getIncidentCE(JSONObject json, String source) {
        return getCE(INCIDENT_DISC, json, source);
    }

    /**
     * Takes an change request JSON and adds the expected Cloud Event properties
     * 
     * @param incident
     *            incident data in JSON format
     * @param source
     *            the source of the data for identifying where the event came from
     * 
     * @return
     */
    protected CloudEvent getChangeRequestCE(JSONObject json, String source) {
        return getCE(CHANGE_REQUEST_DISC, json, source);
    }

    /**
     * Get the Cloud Event
     * 
     * @param cloudEventType
     *            the type for differentiating between change request and incidents
     * @param json
     * @param source
     * 
     * @return
     */
    protected CloudEvent getCE(String cloudEventType, JSONObject json, String source) {
        json.put(SOURCE_NAME, sourceName);
        json.put(CE_CONNECTION_MODE, connMode);
        json.put(CONNECTION_ID, connector.getConnectorID());
        json.put(INSTANCE, instance);

        return createEvent(0, cloudEventType, json.toString(), getSourceURI(source));
    }

    protected static String getValue(JSONObject snowResource, String key) {
        Object value = snowResource.get(key);
        if (value == null)
            value = "";
        return value.toString();
    }

    /**
     * Apply mapping is called on the JSON resource before being mapped to a Ticket
     * 
     * @param snowResource
     *            the original json
     * @param json
     *            the json to be returned
     * @param mappings
     *            the mapping
     */
    public void applyMappings(JSONObject snowResource, JSONObject json, Map mappings) {
        if (snowResource == null || json == null || mappings == null) {
            return;
        }
        for (Entry mapping : mappings.entrySet()) {

            String key = mapping.getKey();
            if (!json.has(key))
                continue;

            String value = getValue(snowResource, mapping.getValue());
            if (!value.isBlank())
                json.put(key, value);
        }
    }

    // Gets the URI for the source or returns null if it is an invalid URI
    protected static URI getSourceURI(String sourceURI) {
        try {
            if (sourceURI != null) {
                URI uri = new URI(sourceURI);
                return uri;
            }
        } catch (URISyntaxException e) {
            // Do nothing
        }
        return null;
    }

    protected CloudEvent createEvent(long responseTime, String ce_type, String jsonMessage, URI source) {
        // Default source in case none is set
        if (source == null) {
            source = SELF_SOURCE;
        }

        // The cloud event being returned needs to be in a structured format
        return CloudEventBuilder.v1().withId(UUID.randomUUID().toString()).withSource(source)
                .withTime(OffsetDateTime.now()).withType(ce_type).withExtension(RESPONSE_TIME_CE_EXT, responseTime)
                .withExtension(CONNECTION_ID_CE_EXTENSION_NAME, connector.getConnectorID())
                .withExtension(COMPONENT_NAME_CE_EXTENSION_NAME, connector.getComponentName())
                .withExtension(TOOL_TYPE, TOOL_TYPE_SNOW)
                .withExtension(CE_EXT_STRUCTURED_CONTENT_MODE, CE_EXT_STRUCTURED_CONTENT_MODE_VALUE)
                .withData("application/json", jsonMessage.getBytes()).build();
    }

    protected String getPartition() {
        // Generate the partition
        // ConnectorConfiguration currentConfig = getConnectorConfiguration();
        if (connector != null) {
            String connectionID = connector.getConnectorID();
            if (connectionID != null && !connectionID.isEmpty()) {
                return "{\"ce-partitionkey\":\"" + connectionID + "\"}";
            }
        }

        // If a partition cannot be created, return null
        // Null is a valid partition and will not throw errors, but
        // can run into unintended consequences from consumerss
        return null;
    }

    /**
     * Insert incident data directly into Elastic for AI training
     * 
     * @param ticket
     *            data to be inserted into Elastic
     * 
     * @throws IOException
     *             Error inserting into Elastic
     */
    public void insertIncidentIntoElastic(Ticket ticket) throws IOException {
        if (ticket != null) {
            elasticHelper.insertIntoElastic(ticket.getHashMap(), Constant.ELASTIC_INCIDENT);
        } else {
            logger.log(Level.WARNING, "Ticket is null, data will not be inserted into elastic");
        }
    }

    /**
     * Insert change request data directly into Elastic for AI training
     * 
     * @param ticket
     *            data to be inserted into Elastic
     * 
     * @throws IOException
     *             Error inserting into Elastic
     */
    public void insertChangeRequestIntoElastic(Ticket ticket) throws IOException {
        if (ticket != null) {
            elasticHelper.insertIntoElastic(ticket.getHashMap(), Constant.ELASTIC_CHANGE_REQUEST);
        } else {
            logger.log(Level.WARNING, "Ticket is null, data will not be inserted into elastic");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy