com.streamreduce.rest.resource.agent.AgentResource.java Source code

Java tutorial

Introduction

Here is the source code for com.streamreduce.rest.resource.agent.AgentResource.java

Source

/*
 * Copyright 2012 Nodeable Inc
 *
 *    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 com.streamreduce.rest.resource.agent;

import com.streamreduce.core.event.EventId;
import com.streamreduce.core.model.Event;
import com.streamreduce.core.model.InventoryItem;
import com.streamreduce.core.model.messages.MessageType;
import com.streamreduce.rest.resource.AbstractResource;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Component;

@Component
@Path("agent/metrics")
public class AgentResource extends AbstractResource {

    /**
     * Takes a JSON payload representing an agent metrics payload, validates it and
     * persists validated payloads.  This will also result in a stream message
     * with the agent metric information in the message stream.  (Note: The JSON
     * payload can be either a singular agent metrics payload or an array of agent
     * metrics payload objects.)
     * <br /><br />
     * The request object should be structured as described below:
     *
     * <ul class="indented">
     *     <li><b>node_id*:</b> The instance id as known by the cloud provider (Must correspond to a cloud inventory item's node id)</li>
     *     <li><b>data*:</b> The JSON object describing the agent metric payload
     *         <ul>
     *             <li><b>generated*:</b> The timestamp of when the metric was gathered/created (Format: yyyy-MM-dd'T'HH:mm:ss.SSSSSS)</li>
     *             <li>... (This data can be whatever you want really and since we do not validate this, no need in documenting it at this time.)</li>
     *         </ul>
     *     </li>
     * </ul>
     *
     * <b>* denotes a required field.</b>
     *
     * @param jsonString the raw JSON payload representing either a singular agent
     * metrics payload or an array of singular agent metrics payloads
     *
     * @return the result of the request
     *
     * @response.representation.405.doc Returned if the request was invalid in any way:
     * Invalid agent metrics payload structure, invalid cloud inventory item id in the
     * payload or whenever any deeper level exception occurs
     *
     * @response.representation.201.doc Returned if the request was successful
     */
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createAgentMetricsEntry(String jsonString) {

        if (isEmpty(jsonString)) {
            return error("Missing payload", Response.status(Response.Status.BAD_REQUEST));
        }

        try {
            JSONObject json = JSONObject.fromObject(jsonString);

            if (!json.has("node_id")) {
                return error("Request is missing the node id to associate the metrics with.",
                        Response.status(Response.Status.BAD_REQUEST));
            }

            if (!json.has("data")) {
                return error("Request is missing the 'data'.", Response.status(Response.Status.BAD_REQUEST));
            }

            try {
                json.getJSONArray("data");
            } catch (JSONException je) {
                return error("'data' should be an array.", Response.status(Response.Status.BAD_REQUEST));
            }

            String nodeId = json.getString("node_id");
            List<InventoryItem> inventoryItems = applicationManager.getInventoryService()
                    .getInventoryItemsForExternalId(nodeId);

            if (inventoryItems == null || inventoryItems.isEmpty()) {
                return error("'node_id' does not correspond with an inventory item, no metrics stored.",
                        Response.status(Response.Status.BAD_REQUEST));
            }

            // we might have multiple inventoryItems with this nodeId
            // if keys are shared across the account boundary (you never know!)
            for (InventoryItem inventoryItem : inventoryItems) {
                JSONArray metrics = json.getJSONArray("data");

                for (Object rawMetric : metrics) {
                    JSONObject metric = (JSONObject) rawMetric;
                    String generated = metric.getString("generated");
                    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
                    Date dateGenerated;

                    try {
                        dateGenerated = df.parse(generated);
                    } catch (ParseException pe) {
                        logger.error("Unable to parse the generated date of the metric.", pe);
                        dateGenerated = new Date();
                    }

                    Map<String, Object> eventContext = new HashMap<>();

                    eventContext.put("activityGenerated", dateGenerated);
                    eventContext.put("activityPayload", metric);

                    inventoryItem.addHashtag("agent");

                    // Create the event stream entry
                    Event event = applicationManager.getEventService().createEvent(EventId.ACTIVITY, inventoryItem,
                            eventContext);

                    // create the message
                    // note: all messages will have the #agent tag now.
                    applicationManager.getMessageService().sendAccountMessage(event, inventoryItem,
                            inventoryItem.getConnection(), dateGenerated.getTime(), MessageType.AGENT,
                            inventoryItem.getHashtags(), null);

                }

            }

            return Response.status(Response.Status.CREATED).build();

        } catch (Exception e) {
            logger.error("Agent Exception", e);
            return error(e.getMessage(), Response.status(Response.Status.BAD_REQUEST));
        }
    }

}