/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.analytics;
import org.eclipse.che.api.analytics.logger.EventLogger;
import org.eclipse.che.api.analytics.shared.dto.EventParameters;
import org.eclipse.che.api.analytics.shared.dto.MetricInfoDTO;
import org.eclipse.che.api.analytics.shared.dto.MetricInfoListDTO;
import org.eclipse.che.api.analytics.shared.dto.MetricValueDTO;
import org.eclipse.che.api.analytics.shared.dto.MetricValueListDTO;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.core.rest.annotations.GenerateLink;
import org.eclipse.che.dto.server.JsonArrayImpl;
import org.eclipse.che.dto.server.JsonStringMapImpl;
import com.google.inject.Inject;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Service is responsible for processing REST requests for analytics data.
*
* @author Anatoliy Bazko
*/
@Api(value = "/analytics",
description = "Analytics manager")
@Path("/analytics")
public class AnalyticsService extends Service {
private static final Logger LOG = LoggerFactory.getLogger(AnalyticsService.class);
private final MetricHandler metricHandler;
private final EventLogger eventLogger;
@Inject
public AnalyticsService(MetricHandler metricHandler, EventLogger eventLogger) {
this.metricHandler = metricHandler;
this.eventLogger = eventLogger;
}
@ApiOperation(value = "Get metric by name",
notes = "Get metric by name. Additional display filters can be used as query parameters.",
response = MetricValueDTO.class,
position = 1)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Unexpected error occurred. Can't get value for metric")})
@GenerateLink(rel = "metric value")
@GET
@Path("/metric/{name}")
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed({"user", "system/admin", "system/manager"})
public Response getValue(@ApiParam(value = "Metric name", required = true)
@PathParam("name") String metricName,
@ApiParam(value = "Page number. Relevant only for LONG data type")
@QueryParam("page") String page,
@ApiParam(value = "Number of results per page.")
@QueryParam("per_page") String perPage,
@Context UriInfo uriInfo) throws ServerException {
try {
Map<String, String> metricContext = extractContext(uriInfo,
page,
perPage);
MetricValueDTO value = metricHandler.getValue(metricName, metricContext, uriInfo);
return Response.status(Response.Status.OK).entity(value).build();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new ServerException("Unexpected error occurred. Can't get value for metric " + metricName);
}
}
@ApiOperation(value = "Get list of metric values",
notes = "Get list of metric values",
response = MetricInfoListDTO.class,
position = 2)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Unexpected error occurred. Can't get value for metric")})
@GenerateLink(rel = "list of metric values")
@POST
@Path("/metric/{name}/list")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed({"user", "system/admin", "system/manager"})
public Response getListValues(@ApiParam(value = "Metric name", required = true)
@PathParam("name") String metricName,
@Context UriInfo uriInfo,
@ApiParam(value = "Search filter", required = true)
List<Map<String, String>> parameters) throws ServerException {
try {
Map<String, String> metricContext = extractContext(uriInfo);
MetricValueListDTO list = metricHandler.getListValues(metricName, parameters, metricContext, uriInfo);
return Response.status(Response.Status.OK).entity(list).build();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new ServerException("Unexpected error occurred. Can't get list of metrics");
}
}
@GenerateLink(rel = "metric value")
@POST
@Path("/metric/{name}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed({"user", "system/admin", "system/manager"})
public Response getValueByJson(Map<String, String> parameters,
@PathParam("name") String metricName,
@QueryParam("page") String page,
@QueryParam("per_page") String perPage,
@Context UriInfo uriInfo) throws ServerException {
try {
Map<String, String> metricContext = extractContext(uriInfo,
page,
perPage);
MetricValueDTO value = metricHandler.getValueByJson(metricName,
new JsonStringMapImpl<>(parameters),
metricContext,
uriInfo);
return Response.status(Response.Status.OK).entity(value).build();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new ServerException("Unexpected error occurred. Can't get value for metric " + metricName);
}
}
@ApiOperation(value = "Get public metric",
notes = "Get public metric (Factory)",
response = MetricValueDTO.class,
position = 4)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message ="Not Found"),
@ApiResponse(code = 500, message = "Unexpected error occurred. Can't get value for metric")})
@GenerateLink(rel = "metric value")
@GET
@Path("/public-metric/{name}")
@Produces(MediaType.APPLICATION_JSON)
public Response getPublicValue(@ApiParam(value = "Metric name", required = true, allowableValues = "factory_used")
@PathParam("name") String metricName,
@ApiParam(value = "Page number")
@QueryParam("page") String page,
@ApiParam(value = "Resylts per page")
@QueryParam("per_page") String perPage,
@Context UriInfo uriInfo) throws ServerException {
try {
Map<String, String> metricContext = extractContext(uriInfo,
page,
perPage);
MetricValueDTO value = metricHandler.getPublicValue(metricName, metricContext, uriInfo);
return Response.status(Response.Status.OK).entity(value).build();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new ServerException("Unexpected error occurred. Can't get value for metric " + metricName);
}
}
@ApiOperation(value = "Get metric value for current user",
notes = "Get metric value for current user",
response = MetricValueListDTO.class,
position = 5)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message ="Not Found"),
@ApiResponse(code = 500, message = "Unexpected error occurred. Can't get value for metric")})
@GenerateLink(rel = "list of metric values")
@POST
@Path("/metric/user")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed({"user", "system/admin", "system/manager"})
public Response getUserValues(@ApiParam(value = "Metric names", required = true)
List<String> metricNames, @Context UriInfo uriInfo) throws ServerException {
try {
Map<String, String> metricContext = extractContext(uriInfo);
MetricValueListDTO list = metricHandler.getUserValues(new JsonArrayImpl<>(metricNames),
metricContext,
uriInfo);
return Response.status(Response.Status.OK).entity(list).build();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new ServerException("Unexpected error occurred. Can't get values of metrics");
}
}
@ApiOperation(value = "Get metric info",
notes = "Get information about specified metric",
response = MetricInfoDTO.class,
position = 6)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message ="Not Found"),
@ApiResponse(code = 500, message = "Unexpected error occurred. Can't get info for metric")})
@GenerateLink(rel = "metric info")
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/metricinfo/{name}")
@RolesAllowed({"user", "system/admin", "system/manager"})
public Response getInfo(@ApiParam(value = "Metric name", required = true)
@PathParam("name") String metricName, @Context UriInfo uriInfo) throws ServerException {
try {
MetricInfoDTO metricInfoDTO = metricHandler.getInfo(metricName, uriInfo);
return Response.status(Response.Status.OK).entity(metricInfoDTO).build();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new ServerException("Unexpected error occurred. Can't get info for metric " + metricName);
}
}
@ApiOperation(value = "Get info on all available metric",
notes = "Get info on all available metric",
response = MetricInfoListDTO.class,
position = 7)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message ="Not Found"),
@ApiResponse(code = 500, message = "Unexpected error occurred. Can't get info for metric")})
@GenerateLink(rel = "all metric info")
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/metricinfo")
@RolesAllowed({"user", "system/admin", "system/manager"})
public Response getAllInfo(@Context UriInfo uriInfo) throws ServerException {
try {
MetricInfoListDTO metricInfoListDTO = metricHandler.getAllInfo(uriInfo);
return Response.status(Response.Status.OK).entity(metricInfoListDTO).build();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new ServerException("Unexpected error occurred. Can't get metric info");
}
}
@GenerateLink(rel = "log analytics event")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Path("log/{event}")
@RolesAllowed({"user", "temp_user", "system/admin", "system/manager"})
public Response logEvent(@PathParam("event") String event,
@Context SecurityContext securityContext,
EventParameters parameters) throws ServerException {
try {
Map<String, String> params;
if (parameters == null) {
params = new HashMap<>();
} else {
params = parameters.getParams();
}
if (!params.containsKey(EventLogger.USER_PARAM) && securityContext != null && securityContext.getUserPrincipal() != null) {
params.put(EventLogger.USER_PARAM, securityContext.getUserPrincipal().getName());
}
eventLogger.log(event, params);
return Response.status(Response.Status.ACCEPTED).build();
} catch (Exception e) {
throw new ServerException("Unexpected error occurred. Can't log event " + event);
}
}
private Map<String, String> extractContext(UriInfo info,
String page,
String perPage) {
MultivaluedMap<String, String> parameters = info.getQueryParameters();
Map<String, String> context = new HashMap<>(parameters.size());
for (String key : parameters.keySet()) {
context.put(key.toUpperCase(), parameters.getFirst(key));
}
if (page != null && perPage != null) {
context.put("PAGE", page);
context.put("PER_PAGE", perPage);
}
return context;
}
private Map<String, String> extractContext(UriInfo info) {
return extractContext(info, null, null);
}
}