/*
*
* 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 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.apache.geode.tools.pulse.internal.controllers;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.sun.net.httpserver.Headers;
import org.apache.geode.tools.pulse.internal.data.Cluster;
import org.apache.geode.tools.pulse.internal.data.PulseConstants;
import org.apache.geode.tools.pulse.internal.data.PulseVersion;
import org.apache.geode.tools.pulse.internal.data.Repository;
import org.apache.geode.tools.pulse.internal.log.PulseLogWriter;
import org.apache.geode.tools.pulse.internal.service.PulseService;
import org.apache.geode.tools.pulse.internal.service.PulseServiceFactory;
import org.apache.geode.tools.pulse.internal.service.SystemAlertsService;
import org.apache.geode.tools.pulse.internal.util.StringUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Class PulseController
*
* This class contains the implementations for all http Ajax requests needs to be served in Pulse.
*
* @since GemFire version 7.5
*/
@Controller
public class PulseController {
private static final PulseLogWriter LOGGER = PulseLogWriter.getLogger();
// CONSTANTS
private final String DEFAULT_EXPORT_FILENAME = "DataBrowserQueryResult.json";
private final String QUERYSTRING_PARAM_ACTION = "action";
private final String QUERYSTRING_PARAM_QUERYID = "queryId";
private final String ACTION_VIEW = "view";
private final String ACTION_DELETE = "delete";
private String STATUS_REPSONSE_SUCCESS = "success";
private String STATUS_REPSONSE_FAIL = "fail";
private String ERROR_REPSONSE_QUERYNOTFOUND = "No queries found";
private String ERROR_REPSONSE_QUERYIDMISSING = "Query id is missing";
private static final String EMPTY_JSON = "{}";
// Shared object to hold pulse version details
public static PulseVersion pulseVersion = new PulseVersion();
// default is gemfire
private static String pulseProductSupport = PulseConstants.PRODUCT_NAME_GEMFIRE;
private final ObjectMapper mapper = new ObjectMapper();
@Autowired
PulseServiceFactory pulseServiceFactory;
@RequestMapping(value = "/pulseUpdate", method = RequestMethod.POST)
public void getPulseUpdate(HttpServletRequest request, HttpServletResponse response)
throws IOException {
String pulseData = request.getParameter("pulseData");
ObjectNode responseMap = mapper.createObjectNode();
JsonNode requestMap = null;
try {
requestMap = mapper.readTree(pulseData);
Iterator<?> keys = requestMap.fieldNames();
// Execute Services
while (keys.hasNext()) {
String serviceName = keys.next().toString();
try {
PulseService pulseService = pulseServiceFactory.getPulseServiceInstance(serviceName);
responseMap.put(serviceName, pulseService.execute(request));
} catch (Exception serviceException) {
LOGGER.warning("serviceException [for service " + serviceName + "] = "
+ serviceException.getMessage());
responseMap.put(serviceName, EMPTY_JSON);
}
}
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occurred : " + e.getMessage());
}
}
// Create Response
response.getOutputStream().write(responseMap.toString().getBytes());
}
@RequestMapping(value = "/authenticateUser", method = RequestMethod.GET)
public void authenticateUser(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// json object to be sent as response
ObjectNode responseJSON = mapper.createObjectNode();
try {
responseJSON.put("isUserLoggedIn", this.isUserLoggedIn(request));
// Send json response
response.getOutputStream().write(responseJSON.toString().getBytes());
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occurred : " + e.getMessage());
}
}
}
/**
* Method isUserLoggedIn Check whether user is logged in or not.
*
* @param request
* @return boolean
*/
protected boolean isUserLoggedIn(HttpServletRequest request) {
return null != request.getUserPrincipal();
}
@RequestMapping(value = "/pulseVersion", method = RequestMethod.GET)
public void pulseVersion(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// json object to be sent as response
ObjectNode responseJSON = mapper.createObjectNode();
try {
// Reference to repository
Repository repository = Repository.get();
// set pulse web app url
String pulseWebAppUrl = request.getScheme() + "://" + request.getServerName() + ":"
+ request.getServerPort() + request.getContextPath();
repository.setPulseWebAppUrl(pulseWebAppUrl);
// Response
responseJSON.put("pulseVersion", PulseController.pulseVersion.getPulseVersion());
responseJSON.put("buildId", PulseController.pulseVersion.getPulseBuildId());
responseJSON.put("buildDate", PulseController.pulseVersion.getPulseBuildDate());
responseJSON.put("sourceDate", PulseController.pulseVersion.getPulseSourceDate());
responseJSON.put("sourceRevision", PulseController.pulseVersion.getPulseSourceRevision());
responseJSON.put("sourceRepository", PulseController.pulseVersion.getPulseSourceRepository());
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occured : " + e.getMessage());
}
}
// Send json response
response.getOutputStream().write(responseJSON.toString().getBytes());
}
@RequestMapping(value = "/clearAlerts", method = RequestMethod.GET)
public void clearAlerts(HttpServletRequest request, HttpServletResponse response)
throws IOException {
int alertType;
ObjectNode responseJSON = mapper.createObjectNode();
try {
alertType = Integer.valueOf(request.getParameter("alertType"));
} catch (NumberFormatException e) {
// Empty json response
response.getOutputStream().write(responseJSON.toString().getBytes());
if (LOGGER.finerEnabled()) {
LOGGER.finer(e.getMessage());
}
return;
}
try {
boolean isClearAll = Boolean.valueOf(request.getParameter("clearAll"));
// get cluster object
Cluster cluster = Repository.get().getCluster();
cluster.clearAlerts(alertType, isClearAll);
responseJSON.put("status", "deleted");
responseJSON.put("systemAlerts",
SystemAlertsService.getAlertsJson(cluster, cluster.getNotificationPageNumber()));
responseJSON.put("pageNumber", cluster.getNotificationPageNumber());
boolean isGFConnected = cluster.isConnectedFlag();
if (isGFConnected) {
responseJSON.put("connectedFlag", isGFConnected);
} else {
responseJSON.put("connectedFlag", isGFConnected);
responseJSON.put("connectedErrorMsg", cluster.getConnectionErrorMsg());
}
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occurred : " + e.getMessage());
}
}
// Send json response
response.getOutputStream().write(responseJSON.toString().getBytes());
}
@RequestMapping(value = "/acknowledgeAlert", method = RequestMethod.GET)
public void acknowledgeAlert(HttpServletRequest request, HttpServletResponse response)
throws IOException {
int alertId;
ObjectNode responseJSON = mapper.createObjectNode();
try {
alertId = Integer.valueOf(request.getParameter("alertId"));
} catch (NumberFormatException e) {
// Empty json response
response.getOutputStream().write(responseJSON.toString().getBytes());
if (LOGGER.finerEnabled()) {
LOGGER.finer(e.getMessage());
}
return;
}
try {
// get cluster object
Cluster cluster = Repository.get().getCluster();
// set alert is acknowledged
cluster.acknowledgeAlert(alertId);
responseJSON.put("status", "deleted");
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occured : " + e.getMessage());
}
}
// Send json response
response.getOutputStream().write(responseJSON.toString().getBytes());
}
@RequestMapping(value = "/dataBrowserRegions", method = RequestMethod.GET)
public void dataBrowserRegions(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// get cluster object
Cluster cluster = Repository.get().getCluster();
// json object to be sent as response
ObjectNode responseJSON = mapper.createObjectNode();
ArrayNode regionsData = mapper.createArrayNode();
try {
// getting cluster's Regions
responseJSON.put("clusterName", cluster.getServerName());
regionsData = getRegionsJson(cluster);
responseJSON.put("clusterRegions", regionsData);
responseJSON.put("connectedFlag", cluster.isConnectedFlag());
responseJSON.put("connectedErrorMsg", cluster.getConnectionErrorMsg());
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occured : " + e.getMessage());
}
}
// Send json response
response.getOutputStream().write(responseJSON.toString().getBytes());
}
/**
* This method creates json for list of cluster regions
*
* @param cluster
* @return ArrayNode JSON array
*/
private ArrayNode getRegionsJson(Cluster cluster) {
Collection<Cluster.Region> clusterRegions = cluster.getClusterRegions().values();
ArrayNode regionsListJson = mapper.createArrayNode();
if (!clusterRegions.isEmpty()) {
for (Cluster.Region region : clusterRegions) {
ObjectNode regionJSON = mapper.createObjectNode();
regionJSON.put("name", region.getName());
regionJSON.put("fullPath", region.getFullPath());
regionJSON.put("regionType", region.getRegionType());
if (region.getRegionType().contains("PARTITION")) {
regionJSON.put("isPartition", true);
} else {
regionJSON.put("isPartition", false);
}
regionJSON.put("memberCount", region.getMemberCount());
List<String> regionsMembers = region.getMemberName();
ArrayNode jsonRegionMembers = mapper.createArrayNode();
for (int i = 0; i < regionsMembers.size(); i++) {
Cluster.Member member = cluster.getMembersHMap().get(regionsMembers.get(i));
ObjectNode jsonMember = mapper.createObjectNode();
jsonMember.put("key", regionsMembers.get(i));
jsonMember.put("id", member.getId());
jsonMember.put("name", member.getName());
jsonRegionMembers.add(jsonMember);
}
regionJSON.put("members", jsonRegionMembers);
regionsListJson.add(regionJSON);
}
}
return regionsListJson;
}
@RequestMapping(value = "/dataBrowserQuery", method = RequestMethod.GET)
public void dataBrowserQuery(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// get query string
String query = request.getParameter("query");
String members = request.getParameter("members");
int limit = 0;
try {
limit = Integer.valueOf(request.getParameter("limit"));
} catch (NumberFormatException e) {
limit = 0;
if (LOGGER.finerEnabled()) {
LOGGER.finer(e.getMessage());
}
}
ObjectNode queryResult = mapper.createObjectNode();
try {
if (StringUtils.isNotNullNotEmptyNotWhiteSpace(query)) {
// get cluster object
Cluster cluster = Repository.get().getCluster();
String userName = request.getUserPrincipal().getName();
// Call execute query method
queryResult = cluster.executeQuery(query, members, limit);
// Add query in history if query is executed successfully
if (!queryResult.has("error")) {
// Add html escaped query to history
String escapedQuery = StringEscapeUtils.escapeHtml(query);
cluster.addQueryInHistory(escapedQuery, userName);
}
}
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occured : " + e.getMessage());
}
}
response.getOutputStream().write(queryResult.toString().getBytes());
}
@RequestMapping(value = "/dataBrowserQueryHistory", method = RequestMethod.GET)
public void dataBrowserQueryHistory(HttpServletRequest request, HttpServletResponse response)
throws IOException {
ObjectNode responseJSON = mapper.createObjectNode();
ArrayNode queryResult = null;
String action = "";
try {
// get cluster object
Cluster cluster = Repository.get().getCluster();
String userName = request.getUserPrincipal().getName();
// get query string
action = request.getParameter(QUERYSTRING_PARAM_ACTION);
if (!StringUtils.isNotNullNotEmptyNotWhiteSpace(action)) {
action = ACTION_VIEW;
}
if (action.toLowerCase().equalsIgnoreCase(ACTION_DELETE)) {
String queryId = request.getParameter(QUERYSTRING_PARAM_QUERYID);
if (StringUtils.isNotNullNotEmptyNotWhiteSpace(queryId)) {
boolean deleteStatus = cluster.deleteQueryById(userName, queryId);
if (deleteStatus) {
responseJSON.put("status", STATUS_REPSONSE_SUCCESS);
} else {
responseJSON.put("status", STATUS_REPSONSE_FAIL);
responseJSON.put("error", ERROR_REPSONSE_QUERYNOTFOUND);
}
} else {
responseJSON.put("status", STATUS_REPSONSE_FAIL);
responseJSON.put("error", ERROR_REPSONSE_QUERYIDMISSING);
}
}
// Get list of past executed queries
queryResult = cluster.getQueryHistoryByUserId(userName);
responseJSON.put("queryHistory", queryResult);
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occured : " + e.getMessage());
}
}
response.getOutputStream().write(responseJSON.toString().getBytes());
}
@RequestMapping(value = "/dataBrowserExport", method = RequestMethod.GET)
public void dataBrowserExport(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// get query string
String query = request.getParameter("query");
String members = request.getParameter("members");
int limit = 0;
try {
limit = Integer.valueOf(request.getParameter("limit"));
} catch (NumberFormatException e) {
limit = 0;
if (LOGGER.finerEnabled()) {
LOGGER.finer(e.getMessage());
}
}
ObjectNode queryResult = mapper.createObjectNode();
try {
if (StringUtils.isNotNullNotEmptyNotWhiteSpace(query)) {
// get cluster object
Cluster cluster = Repository.get().getCluster();
String userName = request.getUserPrincipal().getName();
// Call execute query method
queryResult = cluster.executeQuery(query, members, limit);
// Add query in history if query is executed successfully
if (!queryResult.has("error")) {
// Add html escaped query to history
String escapedQuery = StringEscapeUtils.escapeHtml(query);
cluster.addQueryInHistory(escapedQuery, userName);
}
}
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occured : " + e.getMessage());
}
}
response.setContentType("application/json");
response.setHeader("Content-Disposition", "attachment; filename=results.json");
response.getOutputStream().write(queryResult.toString().getBytes());
}
@RequestMapping(value = "/getQueryStatisticsGridModel", method = RequestMethod.GET)
public void getQueryStatisticsGridModel(HttpServletRequest request, HttpServletResponse response)
throws IOException {
ObjectNode responseJSON = mapper.createObjectNode();
// get cluster object
Cluster cluster = Repository.get().getCluster();
String userName = request.getUserPrincipal().getName();
try {
String[] arrColNames = Cluster.Statement.getGridColumnNames();
String[] arrColAttribs = Cluster.Statement.getGridColumnAttributes();
int[] arrColWidths = Cluster.Statement.getGridColumnWidths();
ArrayNode colNamesList = mapper.createArrayNode();
for (int i = 0; i < arrColNames.length; ++i) {
colNamesList.add(arrColNames[i]);
}
ArrayNode colModelList = mapper.createArrayNode();
for (int i = 0; i < arrColAttribs.length; ++i) {
ObjectNode columnJSON = mapper.createObjectNode();
columnJSON.put("name", arrColAttribs[i]);
columnJSON.put("index", arrColAttribs[i]);
columnJSON.put("width", arrColWidths[i]);
columnJSON.put("sortable", "true");
columnJSON.put("sorttype", ((i == 0) ? "String" : "integer"));
colModelList.add(columnJSON);
}
responseJSON.put("columnNames", colNamesList);
responseJSON.put("columnModels", colModelList);
responseJSON.put("clusterName", cluster.getServerName());
responseJSON.put("userName", userName);
// Send json response
response.getOutputStream().write(responseJSON.toString().getBytes());
} catch (Exception e) {
if (LOGGER.fineEnabled()) {
LOGGER.fine("Exception Occured : " + e.getMessage());
}
}
}
}