mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge branch 'api/pr/grafana/device-mgt' into 'master'
Added grafana integration See merge request entgra/carbon-device-mgt!829
This commit is contained in:
commit
21e014d6a6
@ -0,0 +1,7 @@
|
||||
package org.wso2.carbon.device.mgt.jaxrs.exception;
|
||||
|
||||
public class RefererNotValid extends Exception {
|
||||
public RefererNotValid(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.wso2.carbon.device.mgt.jaxrs.service.api;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
@ -37,12 +38,16 @@ import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
|
||||
|
||||
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.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.util.List;
|
||||
|
||||
@SwaggerDefinition(
|
||||
@ -78,6 +83,89 @@ import java.util.List;
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public interface ReportManagementService {
|
||||
|
||||
@POST
|
||||
@Path("/grafana/api/ds/query")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "POST",
|
||||
value = "Grafana query API proxy",
|
||||
tags = "Analytics",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
Response queryDatasource(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo);
|
||||
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/frontend-metrics")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "POST",
|
||||
value = "Grafana frontend-metric API proxy",
|
||||
tags = "Analytics",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
Response frontendMetrics(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/dashboards/uid/{uid}")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "POST",
|
||||
value = "Grafana dashboard details API proxy",
|
||||
tags = "Analytics",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
Response getDashboard(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException;
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/annotations")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Grafana annotations API proxy",
|
||||
tags = "Analytics",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
Response getAnnotations(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException;
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/alerts/states-for-dashboard")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "POST",
|
||||
value = "Get Grafana alert states for dashboard details API proxy",
|
||||
tags = "Analytics",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
Response getAlertStateForDashboards(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException;
|
||||
|
||||
@GET
|
||||
@Path("/devices")
|
||||
@ApiOperation(
|
||||
|
||||
@ -26,25 +26,38 @@ import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.BadRequestException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.bean.GrafanaPanelIdentifier;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.MaliciousQueryAttempt;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaUtil;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.Constants;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList;
|
||||
import org.wso2.carbon.device.mgt.common.ReportFiltersList;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.exception.RefererNotValid;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.service.api.ReportManagementService;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.GrafanaRequestHandlerUtil;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
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.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -57,6 +70,85 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ReportManagementServiceImpl.class);
|
||||
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/ds/query")
|
||||
@Override
|
||||
public Response queryDatasource(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
|
||||
try {
|
||||
GrafanaPanelIdentifier panelIdentifier = GrafanaRequestHandlerUtil.getPanelIdentifier(headers);
|
||||
GrafanaUtil.getGrafanaQueryService().buildSafeQuery(body, panelIdentifier.getDashboardId(), panelIdentifier.getPanelId(), requestUriInfo.getRequestUri());
|
||||
return GrafanaRequestHandlerUtil.proxyPassPostRequest(body, requestUriInfo, panelIdentifier.getOrgId());
|
||||
} catch (MaliciousQueryAttempt e) {
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(e.getMessage()).build()).build();
|
||||
} catch (GrafanaManagementException e) {
|
||||
return GrafanaRequestHandlerUtil.constructInternalServerError(e, e.getMessage());
|
||||
} catch (RefererNotValid e) {
|
||||
return GrafanaRequestHandlerUtil.constructInvalidReferer();
|
||||
} catch (SQLException | IOException | DBConnectionException e) {
|
||||
log.error(e);
|
||||
return GrafanaRequestHandlerUtil.constructInternalServerError(e, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/frontend-metrics")
|
||||
@Override
|
||||
public Response frontendMetrics(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
|
||||
return proxyPassPostRequest(body, headers, requestUriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/dashboards/uid/{uid}")
|
||||
@Override
|
||||
public Response getDashboard(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
|
||||
return proxyPassGetRequest(headers, requestUriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/annotations")
|
||||
@Override
|
||||
public Response getAnnotations(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
|
||||
return proxyPassGetRequest(headers, requestUriInfo);
|
||||
}
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/grafana/api/alerts/states-for-dashboard")
|
||||
@Override
|
||||
public Response getAlertStateForDashboards(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
|
||||
return proxyPassGetRequest(headers, requestUriInfo);
|
||||
}
|
||||
|
||||
public Response proxyPassGetRequest(HttpHeaders headers, UriInfo requestUriInfo) {
|
||||
try {
|
||||
GrafanaPanelIdentifier panelIdentifier = GrafanaRequestHandlerUtil.getPanelIdentifier(headers);
|
||||
return GrafanaRequestHandlerUtil.proxyPassGetRequest(requestUriInfo, panelIdentifier.getOrgId());
|
||||
} catch (RefererNotValid e) {
|
||||
return GrafanaRequestHandlerUtil.constructInvalidReferer();
|
||||
} catch (GrafanaManagementException e) {
|
||||
return GrafanaRequestHandlerUtil.constructInternalServerError(e, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public Response proxyPassPostRequest(JsonObject body, HttpHeaders headers, UriInfo requestUriInfo) {
|
||||
try {
|
||||
GrafanaPanelIdentifier panelIdentifier = GrafanaRequestHandlerUtil.getPanelIdentifier(headers);
|
||||
return GrafanaRequestHandlerUtil.proxyPassPostRequest(body, requestUriInfo, panelIdentifier.getOrgId());
|
||||
} catch (RefererNotValid e) {
|
||||
return GrafanaRequestHandlerUtil.constructInvalidReferer();
|
||||
} catch (GrafanaManagementException e) {
|
||||
return GrafanaRequestHandlerUtil.constructInternalServerError(e, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Path("/devices")
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.jaxrs.service.impl.util;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.common.util.HttpUtil;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.bean.GrafanaPanelIdentifier;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.GrafanaEnvVariablesNotDefined;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaConstants;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaUtil;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.Constants;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.exception.RefererNotValid;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class GrafanaRequestHandlerUtil {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GrafanaRequestHandlerUtil.class);
|
||||
|
||||
public static Response proxyPassGetRequest(UriInfo requestUriInfo, String orgId) throws GrafanaEnvVariablesNotDefined {
|
||||
HttpGet grafanaGetReq = new HttpGet();
|
||||
return forwardRequestToGrafanaEndpoint(grafanaGetReq, requestUriInfo, orgId);
|
||||
}
|
||||
|
||||
public static Response proxyPassPostRequest(JsonObject body, UriInfo requestUriInfo, String orgId)
|
||||
throws GrafanaEnvVariablesNotDefined {
|
||||
HttpPost grafanaPostReq = new HttpPost();
|
||||
try {
|
||||
setRequestEntity(grafanaPostReq, body);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
String errorMsg = "Error occurred while parsing body";
|
||||
log.error(errorMsg, e);
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMsg).build()).build();
|
||||
}
|
||||
return forwardRequestToGrafanaEndpoint(grafanaPostReq, requestUriInfo, orgId);
|
||||
}
|
||||
|
||||
private static Response forwardRequestToGrafanaEndpoint(HttpRequestBase requestBase, UriInfo requestUriInfo, String orgId)
|
||||
throws GrafanaEnvVariablesNotDefined {
|
||||
URI grafanaUri = generateGrafanaUri(requestUriInfo);
|
||||
requestBase.setURI(grafanaUri);
|
||||
requestBase.setHeader(GrafanaConstants.X_GRAFANA_ORG_ID_HEADER, orgId);
|
||||
try(CloseableHttpClient client = HttpClients.createDefault()) {
|
||||
HttpResponse grafanaResponse = invokeGrafanaAPI(client, requestBase);
|
||||
String grafanaResponseBody = HttpUtil.getResponseString(grafanaResponse);
|
||||
return Response.status(Response.Status.OK).entity(grafanaResponseBody).
|
||||
header(HttpHeaders.CONTENT_TYPE, HttpUtil.getContentType(grafanaResponse)).build();
|
||||
} catch (IOException e) {
|
||||
String msg = "Error occurred while calling Grafana API";
|
||||
log.error(msg, e);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
} catch (GrafanaManagementException e) {
|
||||
String err = "Error occurred while retrieving Grafana configuration";
|
||||
log.error(err, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(err).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpResponse invokeGrafanaAPI(HttpClient client, HttpRequestBase request) throws IOException, GrafanaManagementException {
|
||||
setBasicAuthHeader(request);
|
||||
return client.execute(request);
|
||||
}
|
||||
|
||||
public static void setBasicAuthHeader(HttpRequestBase request) throws GrafanaManagementException {
|
||||
String basicAuth = GrafanaUtil.getBasicAuthBase64Header();
|
||||
request.setHeader(HttpHeaders.AUTHORIZATION, basicAuth);
|
||||
}
|
||||
|
||||
public static URI generateGrafanaUri(UriInfo requestUriInfo) throws GrafanaEnvVariablesNotDefined {
|
||||
String base = GrafanaUtil.getGrafanaHTTPBase(requestUriInfo.getRequestUri().getScheme());
|
||||
String grafanaRequestPath = getGrafanaRequestPathWQuery(requestUriInfo);
|
||||
return HttpUtil.createURI(GrafanaUtil.generateGrafanaUrl(grafanaRequestPath, base));
|
||||
}
|
||||
|
||||
public static String getGrafanaRequestPathWQuery(UriInfo requestUriInfo) {
|
||||
String contextPath = "/reports/grafana";
|
||||
String path = requestUriInfo.getPath().substring(contextPath.length());
|
||||
String queryParam = requestUriInfo.getRequestUri().getRawQuery();
|
||||
if (queryParam != null) {
|
||||
path += Constants.URI_QUERY_SEPARATOR + queryParam;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static GrafanaPanelIdentifier getPanelIdentifier(HttpHeaders headers) throws RefererNotValid {
|
||||
String referer = headers.getHeaderString(GrafanaConstants.REFERER_HEADER);
|
||||
if(referer == null) {
|
||||
String errMsg = "Request does not contain Referer header";
|
||||
log.error(errMsg);
|
||||
throw new RefererNotValid(errMsg);
|
||||
}
|
||||
GrafanaPanelIdentifier panelIdentifier = GrafanaUtil.getPanelIdentifierFromReferer(referer);
|
||||
if(panelIdentifier.getDashboardId() == null ||
|
||||
panelIdentifier.getPanelId() == null || panelIdentifier.getOrgId() == null) {
|
||||
String errMsg = "Referer must contain dashboardId, panelId and orgId";
|
||||
log.error(errMsg);
|
||||
throw new RefererNotValid(errMsg);
|
||||
}
|
||||
return panelIdentifier;
|
||||
}
|
||||
|
||||
public static void setRequestEntity(HttpPost postRequest, JsonObject body) throws UnsupportedEncodingException {
|
||||
StringEntity bodyEntity = new StringEntity(body.toString());
|
||||
bodyEntity.setContentType(MediaType.APPLICATION_JSON);
|
||||
postRequest.setEntity(bodyEntity);
|
||||
}
|
||||
|
||||
public static Response constructInvalidReferer() {
|
||||
String errorMsg = "Request does not contain a valid Referer header";
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMsg).build()).build();
|
||||
}
|
||||
public static Response constructInternalServerError(Exception e, String errMsg) {
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errMsg).build()).build();
|
||||
}
|
||||
|
||||
public static void copyHeadersToGrafanaRequest(HttpRequestBase grafanaRequest, HttpHeaders headers) {
|
||||
Map<String, List<String>> headerValues = headers.getRequestHeaders();
|
||||
for (String key : headerValues.keySet()) {
|
||||
if (!key.equals(HttpHeaders.AUTHORIZATION) && !key.equals(HttpHeaders.CONTENT_LENGTH)) {
|
||||
for (String value : headerValues.get(key)) {
|
||||
grafanaRequest.setHeader(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.common.exceptions;
|
||||
|
||||
public class GrafanaManagementException extends Exception{
|
||||
|
||||
private static final long serialVersionUID = -3951279311829079297L;
|
||||
|
||||
public GrafanaManagementException(String msg, Exception nestedEx) {
|
||||
super(msg, nestedEx);
|
||||
}
|
||||
public GrafanaManagementException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@ -338,6 +338,10 @@
|
||||
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||
<artifactId>io.entgra.server.bootup.heartbeat.beacon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (pvt) Ltd. 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.wso2.carbon.device.mgt.core.common.util;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.Constants;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpUtil {
|
||||
|
||||
public static URI createURI(String uriString) {
|
||||
uriString = uriString.replace(" ", "%20");
|
||||
return URI.create(uriString);
|
||||
}
|
||||
|
||||
public static String getRequestSubPathFromEnd(URI requestUri, int position) {
|
||||
if (requestUri.getPath() != null) {
|
||||
String[] pathList = requestUri.getPath().split("/");
|
||||
if (pathList.length - 1 >= position) {
|
||||
return pathList[pathList.length - 1 - position];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getRequestSubPath(String fullPath, int position) {
|
||||
String[] pathList = fullPath.split("/");
|
||||
if (pathList.length - 1 > position) {
|
||||
String path = pathList[position + 1];
|
||||
if(path.contains(Constants.URI_QUERY_SEPARATOR)) {
|
||||
path = path.substring(0, path.indexOf(Constants.URI_QUERY_SEPARATOR));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getResponseString(HttpResponse response) throws IOException {
|
||||
return EntityUtils.toString(response.getEntity());
|
||||
}
|
||||
|
||||
public static boolean isQueryParamExist(String param, URI request) {
|
||||
Map<String, List<String>> queryMap = getQueryMap(request);
|
||||
return queryMap.containsKey(param);
|
||||
}
|
||||
public static String getFirstQueryValue(String param, Map<String, List<String>> queryMap) {
|
||||
List<String> valueList = queryMap.get(param);
|
||||
String firstValue = null;
|
||||
if(valueList != null) {
|
||||
firstValue = valueList.get(0);
|
||||
}
|
||||
return firstValue;
|
||||
}
|
||||
public static Map<String, List<String>> getQueryMap(String uri) {
|
||||
String query = getQueryFromURIPath(uri);
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
if (query != null) {
|
||||
String[] params = query.split("&");
|
||||
for (String param : params) {
|
||||
String[] paramArr = param.split("=");
|
||||
if (paramArr.length == 2) {
|
||||
String name = paramArr[0];
|
||||
String value = paramArr[1];
|
||||
if (!map.containsKey(name)) {
|
||||
List<String> valueList = new ArrayList<>();
|
||||
map.put(name, valueList);
|
||||
}
|
||||
map.get(name).add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
public static Map<String, List<String>> getQueryMap(URI request) {
|
||||
String query = request.getQuery();
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
if (query != null) {
|
||||
String[] params = query.split("&");
|
||||
for (String param : params) {
|
||||
String[] paramArr = param.split("=");
|
||||
if (paramArr.length == 2) {
|
||||
String name = paramArr[0];
|
||||
String value = paramArr[1];
|
||||
if (!map.containsKey(name)) {
|
||||
List<String> valueList = new ArrayList<>();
|
||||
map.put(name, valueList);
|
||||
}
|
||||
map.get(name).add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
public static String getQueryFromURIPath(String uri) {
|
||||
String query = null;
|
||||
if (uri.length() > "?".length() && uri.contains("?")) {
|
||||
query = uri.substring(uri.lastIndexOf("?") + "?".length());
|
||||
}
|
||||
if (StringUtils.isEmpty(query)) {
|
||||
query = null;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
public static String getContentType(HttpResponse response) {
|
||||
ContentType contentType = ContentType.getOrDefault(response.getEntity());
|
||||
return contentType.getMimeType();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.bean;
|
||||
|
||||
public class GrafanaPanelIdentifier {
|
||||
|
||||
private String orgId;
|
||||
private String dashboardUID;
|
||||
private String panelId;
|
||||
|
||||
public GrafanaPanelIdentifier(String orgId, String dashboardUID, String panelId) {
|
||||
this.orgId = orgId;
|
||||
this.dashboardUID = dashboardUID;
|
||||
this.panelId = panelId;
|
||||
}
|
||||
|
||||
public String getOrgId() {
|
||||
return orgId;
|
||||
}
|
||||
|
||||
public void setOrgId(String orgId) {
|
||||
this.orgId = orgId;
|
||||
}
|
||||
|
||||
public String getDashboardId() {
|
||||
return dashboardUID;
|
||||
}
|
||||
|
||||
public void setDashboardId(String dashboardId) {
|
||||
this.dashboardUID = dashboardId;
|
||||
}
|
||||
|
||||
public String getPanelId() {
|
||||
return panelId;
|
||||
}
|
||||
|
||||
public void setPanelId(String panelId) {
|
||||
this.panelId = panelId;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (Pvt) Ltd. 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.wso2.carbon.device.mgt.core.grafana.mgt.config;
|
||||
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.xml.bean.CacheConfiguration;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.xml.bean.User;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.List;
|
||||
|
||||
@XmlRootElement(name = "GrafanaConfiguration")
|
||||
public class GrafanaConfiguration {
|
||||
|
||||
private User adminUser;
|
||||
private List<CacheConfiguration> caches;
|
||||
|
||||
@XmlElement(name = "AdminUser")
|
||||
public User getAdminUser() {
|
||||
return adminUser;
|
||||
}
|
||||
|
||||
public void setAdminUser(User user) {
|
||||
this.adminUser = user;
|
||||
}
|
||||
|
||||
|
||||
@XmlElementWrapper(name = "Cache")
|
||||
@XmlElement(name = "CacheConfiguration")
|
||||
public List<CacheConfiguration> getCaches() {
|
||||
return caches;
|
||||
}
|
||||
|
||||
public CacheConfiguration getCacheByName(String cacheName) {
|
||||
for (CacheConfiguration cache : caches) {
|
||||
if (cache.getName().equals(cacheName)) {
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setCaches(List<CacheConfiguration> caches) {
|
||||
this.caches = caches;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaConstants;
|
||||
import org.wso2.carbon.utils.CarbonUtils;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.File;
|
||||
|
||||
public class GrafanaConfigurationManager {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GrafanaConfigurationManager.class);
|
||||
private static GrafanaConfigurationManager grafanaConfigurationManager;
|
||||
private GrafanaConfiguration grafanaConfiguration;
|
||||
private static final String GRAFANA_CONFIG_PATH = CarbonUtils.getCarbonConfigDirPath() + File.separator
|
||||
+ GrafanaConstants.CONFIG_XML_NAME;
|
||||
|
||||
public static GrafanaConfigurationManager getInstance() {
|
||||
if (grafanaConfigurationManager == null) {
|
||||
synchronized (GrafanaConfigurationManager.class) {
|
||||
if (grafanaConfigurationManager == null) {
|
||||
grafanaConfigurationManager = new GrafanaConfigurationManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return grafanaConfigurationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Grafana Configuration through the provided configuration location
|
||||
* @param configLocation has the path of the configuration file
|
||||
* @throws GrafanaManagementException throws when there are any errors during the initialization of
|
||||
* Grafana configuration
|
||||
*/
|
||||
public synchronized void initConfig(String configLocation) throws GrafanaManagementException {
|
||||
try {
|
||||
File smsConfig = new File(configLocation);
|
||||
Document doc = convertXMLToDocument(smsConfig);
|
||||
|
||||
/* Un-marshaling Grafana configuration */
|
||||
JAXBContext smsContext = JAXBContext.newInstance(GrafanaConfiguration.class);
|
||||
Unmarshaller unmarshaller = smsContext.createUnmarshaller();
|
||||
this.grafanaConfiguration = (GrafanaConfiguration) unmarshaller.unmarshal(doc);
|
||||
} catch (JAXBException e) {
|
||||
String msg = "Error occurred while initializing Grafana config '" + configLocation + "'";
|
||||
log.error(msg, e);
|
||||
throw new GrafanaManagementException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Grafana Configuration through the grafana-config.xml file in the GRAFANA_CONFIG_PATH
|
||||
* @throws GrafanaManagementException throws when there are any errors during the initialization of config
|
||||
*/
|
||||
public void initConfig() throws GrafanaManagementException {
|
||||
this.initConfig(GRAFANA_CONFIG_PATH);
|
||||
}
|
||||
|
||||
public GrafanaConfiguration getGrafanaConfiguration() throws GrafanaManagementException {
|
||||
if (grafanaConfiguration != null) {
|
||||
return grafanaConfiguration;
|
||||
}
|
||||
initConfig();
|
||||
return grafanaConfiguration;
|
||||
}
|
||||
|
||||
private static Document convertXMLToDocument(File file) throws GrafanaManagementException {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
factory.setFeature(GrafanaConstants.XML.FEATURES_DISALLOW_DOCTYPE_DECL, true);
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
DocumentBuilder docBuilder = factory.newDocumentBuilder();
|
||||
return docBuilder.parse(file);
|
||||
} catch (Exception e) {
|
||||
String errMsg = "Error occurred while parsing file, while converting to a org.w3c.dom.Document";
|
||||
log.error(errMsg, e);
|
||||
throw new GrafanaManagementException(errMsg, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (Pvt) Ltd. 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.wso2.carbon.device.mgt.core.grafana.mgt.config.xml.bean;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
public class CacheConfiguration {
|
||||
|
||||
private String name;
|
||||
private int capacity;
|
||||
|
||||
@XmlAttribute(name = "name")
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@XmlElement(name = "Capacity")
|
||||
public int getCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setCapacity(int capacity) {
|
||||
this.capacity = capacity;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.config.xml.bean;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement(name="AdminUser")
|
||||
public class User {
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
@XmlElement(name="Username")
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@XmlElement(name="Password")
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
public class DashboardNotFound extends GrafanaAPIException {
|
||||
|
||||
private static final long serialVersionUID = -2111271331930070297L;
|
||||
|
||||
public DashboardNotFound(String errMsg) {
|
||||
super(errMsg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
public class DatasourceNotFound extends GrafanaAPIException {
|
||||
|
||||
private static final long serialVersionUID = -3171279332930270227L;
|
||||
|
||||
public DatasourceNotFound(String errMsg) {
|
||||
super(errMsg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
|
||||
public class GrafanaAPIException extends GrafanaManagementException {
|
||||
|
||||
private static final long serialVersionUID = -3921249462930270227L;
|
||||
|
||||
public GrafanaAPIException(String errMsg) {
|
||||
super(errMsg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
|
||||
public class GrafanaEnvVariablesNotDefined extends GrafanaManagementException {
|
||||
|
||||
private static final long serialVersionUID = -3444449462330270237L;
|
||||
|
||||
public GrafanaEnvVariablesNotDefined(String errMsg) {
|
||||
super(errMsg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
|
||||
public class MaliciousQueryAttempt extends GrafanaManagementException {
|
||||
|
||||
private static final long serialVersionUID = -3171279331930070297L;
|
||||
|
||||
public MaliciousQueryAttempt(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public MaliciousQueryAttempt(String msg, Exception nestedException) {
|
||||
super(msg, nestedException);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
public class PanelNotFound extends GrafanaAPIException {
|
||||
|
||||
private static final long serialVersionUID = -3471479441930070297L;
|
||||
public PanelNotFound(String errMsg) {
|
||||
super(errMsg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
public class QueryMisMatch extends MaliciousQueryAttempt {
|
||||
|
||||
private static final long serialVersionUID = -3171279334939076294L;
|
||||
|
||||
public QueryMisMatch(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
public class QueryNotFound extends GrafanaAPIException {
|
||||
|
||||
private static final long serialVersionUID = -3151259335930070297L;
|
||||
public QueryNotFound(String errMsg) {
|
||||
super(errMsg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.exception;
|
||||
|
||||
public class TemplateNotFound extends GrafanaAPIException {
|
||||
|
||||
private static final long serialVersionUID = -3481878481830070297L;
|
||||
public TemplateNotFound(String errMsg) {
|
||||
super(errMsg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.service;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.bean.Datasource;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface GrafanaAPIService {
|
||||
|
||||
String getQueryTemplate(String dashboardUID, String panelId, String refId,
|
||||
String requestScheme) throws IOException, GrafanaManagementException;
|
||||
|
||||
JsonObject getPanelDetails(String dashboardUID, String panelId, String requestScheme) throws
|
||||
IOException, GrafanaManagementException;
|
||||
|
||||
JsonObject getDashboardDetails(String dashboardUID, String requestScheme) throws IOException,
|
||||
GrafanaManagementException;
|
||||
|
||||
Datasource getDatasource(int datasourceId, String requestScheme) throws IOException,
|
||||
GrafanaManagementException;
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.service;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public interface GrafanaQueryService {
|
||||
|
||||
void buildSafeQuery(JsonObject queryRequestBody, String dashboardUID, String panelId,
|
||||
URI requestUri) throws IOException, SQLException, GrafanaManagementException, DBConnectionException;
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.service.bean;
|
||||
|
||||
public class Datasource {
|
||||
private int id;
|
||||
private String url;
|
||||
private String name;
|
||||
private String type;
|
||||
private String database;
|
||||
|
||||
public Datasource(int id, String url, String name, String type, String database) {
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
public void setDatabase(String database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (Pvt) Ltd. 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.wso2.carbon.device.mgt.core.grafana.mgt.service.cache;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.GrafanaConfiguration;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.GrafanaConfigurationManager;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.xml.bean.CacheConfiguration;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.bean.Datasource;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaConstants;
|
||||
|
||||
public class CacheManager {
|
||||
private static final Log log = LogFactory.getLog(CacheManager.class);
|
||||
|
||||
private Cache<Integer, Datasource> datasourceAPICache;
|
||||
private Cache<QueryTemplateCacheKey, String> queryTemplateAPICache;
|
||||
private Cache<String, String> encodedQueryCache;
|
||||
|
||||
private CacheManager() {
|
||||
initCache();
|
||||
}
|
||||
|
||||
private static final class CacheManagerHolder {
|
||||
static final CacheManager cacheManager = new CacheManager();
|
||||
}
|
||||
|
||||
public static CacheManager getInstance() {
|
||||
return CacheManagerHolder.cacheManager;
|
||||
}
|
||||
|
||||
public Cache<String, String> getEncodedQueryCache() {
|
||||
return encodedQueryCache;
|
||||
}
|
||||
|
||||
public Cache<QueryTemplateCacheKey, String> getQueryTemplateAPICache() {
|
||||
return queryTemplateAPICache;
|
||||
}
|
||||
|
||||
|
||||
public Cache<Integer, Datasource> getDatasourceAPICache() {
|
||||
return datasourceAPICache;
|
||||
}
|
||||
|
||||
|
||||
private void initCache() {
|
||||
this.datasourceAPICache = buildDatasourceCache();
|
||||
this.queryTemplateAPICache = buildQueryCacheByName(GrafanaConstants.QUERY_API_CACHE_NAME);
|
||||
this.encodedQueryCache = buildQueryCacheByName(GrafanaConstants.ENCODED_QUERY_CACHE_NAME);
|
||||
}
|
||||
|
||||
private <K, V> Cache<K, V> buildDatasourceCache() {
|
||||
return CacheBuilder.newBuilder().build();
|
||||
}
|
||||
|
||||
private <K , V> Cache<K, V> buildQueryCacheByName(String cacheName) {
|
||||
int capacity = getCacheCapacity(cacheName);
|
||||
return CacheBuilder.newBuilder().maximumSize(capacity).build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static int getCacheCapacity(String cacheName) {
|
||||
try {
|
||||
GrafanaConfiguration configuration = GrafanaConfigurationManager.getInstance().getGrafanaConfiguration();
|
||||
CacheConfiguration cacheConfig = configuration.getCacheByName(cacheName);
|
||||
if (cacheConfig == null) {
|
||||
log.error("CacheConfiguration config not defined for " + cacheName);
|
||||
throw new GrafanaManagementException("Query API CacheConfiguration configuration not properly defined");
|
||||
}
|
||||
return cacheConfig.getCapacity();
|
||||
} catch (GrafanaManagementException e) {
|
||||
String errMsg = "Error occurred while initializing cache capacity for " + cacheName;
|
||||
log.error(errMsg);
|
||||
throw new RuntimeException(errMsg, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (Pvt) Ltd. 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.wso2.carbon.device.mgt.core.grafana.mgt.service.cache;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class QueryTemplateCacheKey {
|
||||
|
||||
private final String dashboardUID;
|
||||
private final String panelId;
|
||||
private final String refId;
|
||||
private volatile int hashCode;
|
||||
|
||||
public QueryTemplateCacheKey(String dashboardUID, String panelId, String refId) {
|
||||
this.dashboardUID = dashboardUID;
|
||||
this.panelId = panelId;
|
||||
this.refId = refId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof QueryTemplateCacheKey) {
|
||||
final QueryTemplateCacheKey other = (QueryTemplateCacheKey) obj;
|
||||
String thisId = this.dashboardUID + this.panelId + this.refId;
|
||||
String otherId = other.dashboardUID + other.panelId + other.refId;
|
||||
return thisId.equals(otherId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hashCode == 0) {
|
||||
hashCode = Objects.hash(dashboardUID, panelId, refId);
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.service.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.common.util.HttpUtil;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.DashboardNotFound;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.DatasourceNotFound;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.GrafanaEnvVariablesNotDefined;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.PanelNotFound;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.QueryNotFound;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.TemplateNotFound;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.GrafanaAPIService;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.bean.Datasource;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.cache.CacheManager;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.cache.QueryTemplateCacheKey;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaConstants;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaUtil;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.Constants;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import java.io.IOException;
|
||||
|
||||
public class GrafanaAPIServiceImpl implements GrafanaAPIService {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GrafanaAPIServiceImpl.class);
|
||||
|
||||
public String getQueryTemplate(String dashboardUID, String panelId, String refId,
|
||||
String requestScheme) throws IOException, GrafanaManagementException {
|
||||
try {
|
||||
return getPanelQuery(dashboardUID, panelId, refId, requestScheme);
|
||||
} catch (QueryNotFound e) {
|
||||
return getTemplateQuery(dashboardUID, refId, requestScheme);
|
||||
}
|
||||
}
|
||||
|
||||
public String getPanelQuery(String dashboardUID, String panelId, String refId,
|
||||
String requestScheme) throws IOException, GrafanaManagementException {
|
||||
JsonObject panel = getPanelDetails(dashboardUID, panelId, requestScheme);
|
||||
JsonArray queries = panel.getAsJsonArray(GrafanaConstants.DASHBOARD_PANEL_DETAIL_QUERIES_KEY);
|
||||
JsonObject query = getQueryByRefId(queries, refId);
|
||||
if (query == null) {
|
||||
throw new QueryNotFound("No query exists for {dashboard: " + dashboardUID +
|
||||
", panelId: " + panelId + ", refId: " + refId + "}");
|
||||
}
|
||||
String queryTemplate = query.get(GrafanaConstants.RAW_SQL_KEY).getAsString();
|
||||
CacheManager.getInstance().getQueryTemplateAPICache().
|
||||
put(new QueryTemplateCacheKey(dashboardUID, panelId, refId), queryTemplate);
|
||||
return queryTemplate;
|
||||
}
|
||||
|
||||
// Here template query means the grafana template variable queries
|
||||
public String getTemplateQuery(String dashboardUID, String refId,
|
||||
String requestScheme) throws IOException, GrafanaManagementException {
|
||||
JsonObject template = getTemplatingDetails(dashboardUID, refId, requestScheme);
|
||||
JsonElement queryElement = template.get(GrafanaConstants.TEMPLATE_QUERY_KEY);
|
||||
if (queryElement == null) {
|
||||
throw new QueryNotFound("No template query exists for {dashboard: " + dashboardUID +
|
||||
", refId: " + refId + "}");
|
||||
}
|
||||
String query = queryElement.getAsString();
|
||||
CacheManager.getInstance().getQueryTemplateAPICache().
|
||||
put(new QueryTemplateCacheKey(dashboardUID, null, refId), query);
|
||||
return query;
|
||||
}
|
||||
|
||||
public JsonObject getTemplatingDetails(String dashboardUID, String refId, String requestScheme) throws
|
||||
IOException, GrafanaManagementException {
|
||||
JsonObject dashboard = getDashboardDetails(dashboardUID, requestScheme);
|
||||
JsonObject template = getTemplateByRefId(dashboard, refId);
|
||||
if (template == null) {
|
||||
String errorMsg = "Template for {refId: " + refId + ", dashboard: " + dashboardUID + "} is not found";
|
||||
log.error(errorMsg);
|
||||
throw new TemplateNotFound(errorMsg);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
public JsonObject getPanelDetails(String dashboardUID, String panelId, String requestScheme) throws
|
||||
IOException, GrafanaManagementException {
|
||||
JsonObject dashboard = getDashboardDetails(dashboardUID, requestScheme);
|
||||
JsonObject panel = getPanelById(dashboard, panelId);
|
||||
if (panel == null) {
|
||||
String errorMsg = "Panel " + panelId + " for dashboard " + dashboardUID + " is not found";
|
||||
log.error(errorMsg);
|
||||
throw new PanelNotFound(errorMsg);
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
public JsonObject getDashboardDetails(String dashboardUID, String requestScheme) throws IOException,
|
||||
GrafanaManagementException {
|
||||
String dashboardAPI = generateGrafanaAPIBaseUri(GrafanaConstants.DASHBOARD_API, requestScheme) + dashboardUID;
|
||||
HttpGet request = new HttpGet(dashboardAPI);
|
||||
JsonObject dashboardResponseJsonBody = getGrafanaAPIJsonResponse(request);
|
||||
JsonObject dashboardDetails = dashboardResponseJsonBody.getAsJsonObject(GrafanaConstants.DASHBOARD_KEY);
|
||||
if (dashboardDetails == null) {
|
||||
throw new DashboardNotFound("Grafana response: " + dashboardResponseJsonBody);
|
||||
}
|
||||
return dashboardResponseJsonBody.getAsJsonObject(GrafanaConstants.DASHBOARD_KEY);
|
||||
}
|
||||
|
||||
public Datasource getDatasource(int datasourceId, String requestScheme) throws IOException, GrafanaManagementException {
|
||||
String datasourceAPI = generateGrafanaAPIBaseUri(GrafanaConstants.DATASOURCE_API, requestScheme) + datasourceId;
|
||||
HttpGet request = new HttpGet(datasourceAPI);
|
||||
JsonObject datasourceDetails = getGrafanaAPIJsonResponse(request);
|
||||
if (datasourceDetails.get(GrafanaConstants.DATASOURCE_NAME_KEY) == null) {
|
||||
throw new DatasourceNotFound("Grafana response: " + datasourceDetails);
|
||||
}
|
||||
String url = datasourceDetails.get(GrafanaConstants.DATASOURCE_URL_KEY).getAsString();
|
||||
String name = datasourceDetails.get(GrafanaConstants.DATASOURCE_NAME_KEY).getAsString();
|
||||
String type = datasourceDetails.get(GrafanaConstants.DATASOURCE_TYPE_KEY).getAsString();
|
||||
String database = datasourceDetails.get(GrafanaConstants.DATASOURCE_DB_KEY).getAsString();
|
||||
Datasource ds = new Datasource(datasourceId, url, name, type, database);
|
||||
CacheManager.getInstance().getDatasourceAPICache().put(datasourceId, ds);
|
||||
return ds;
|
||||
}
|
||||
|
||||
private String generateGrafanaAPIBaseUri(String api, String requestScheme) throws GrafanaEnvVariablesNotDefined {
|
||||
return GrafanaUtil.getGrafanaHTTPBase(requestScheme) + api + Constants.URI_SEPARATOR;
|
||||
}
|
||||
|
||||
|
||||
private JsonObject getGrafanaAPIJsonResponse(HttpRequestBase request) throws IOException,
|
||||
GrafanaManagementException {
|
||||
try(CloseableHttpClient client = HttpClients.createDefault()) {
|
||||
HttpResponse response = invokeAPI(client, request);
|
||||
return GrafanaUtil.getJsonBody(HttpUtil.getResponseString(response));
|
||||
}
|
||||
}
|
||||
|
||||
private HttpResponse invokeAPI(HttpClient client, HttpRequestBase request) throws IOException, GrafanaManagementException {
|
||||
setBasicAuthHeader(request);
|
||||
return client.execute(request);
|
||||
}
|
||||
|
||||
private void setBasicAuthHeader(HttpRequestBase request) throws GrafanaManagementException {
|
||||
String basicAuth = GrafanaUtil.getBasicAuthBase64Header();
|
||||
request.setHeader(HttpHeaders.AUTHORIZATION, basicAuth);
|
||||
}
|
||||
|
||||
private JsonObject getQueryByRefId(JsonArray queries, String refId) {
|
||||
for (int i = 0; i < queries.size(); i++) {
|
||||
JsonObject query = queries.get(i).getAsJsonObject();
|
||||
String queryRefId = query.get(GrafanaConstants.QUERY_REF_ID_KEY).getAsString();
|
||||
if (queryRefId.equals(refId)) {
|
||||
return query;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsonObject getTemplateByRefId(JsonObject dashboard, String refId) {
|
||||
JsonArray templates = dashboard.getAsJsonObject(GrafanaConstants.TEMPLATING_KEY).
|
||||
getAsJsonArray(GrafanaConstants.TEMPLATING_LIST_KEY);
|
||||
for (int i = 0; i < templates.size(); i++) {
|
||||
JsonObject templateObj = templates.get(i).getAsJsonObject();
|
||||
String name = templateObj.get(GrafanaConstants.TEMPLATING_NAME_KEY).getAsString();
|
||||
// RefId in query body corresponds to template name
|
||||
if (refId.equals(name)) {
|
||||
return templateObj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private JsonObject getPanelById(JsonObject dashboard, String panelId) {
|
||||
JsonArray panels = dashboard.getAsJsonArray(GrafanaConstants.PANEL_KEY);
|
||||
for (int i = 0; i < panels.size(); i++) {
|
||||
JsonObject panelObj = panels.get(i).getAsJsonObject();
|
||||
String id = panelObj.get(GrafanaConstants.ID_KEY).getAsString();
|
||||
if (id.equals(panelId)) {
|
||||
return panelObj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.service.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.MaliciousQueryAttempt;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.QueryMisMatch;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.QueryNotFound;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.GrafanaAPIService;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.GrafanaQueryService;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.bean.Datasource;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.cache.CacheManager;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.cache.QueryTemplateCacheKey;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.GrafanaPreparedQueryBuilder;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.PreparedQuery;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.encoder.QueryEncoderFactory;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaConstants;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class GrafanaQueryServiceImpl implements GrafanaQueryService {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GrafanaQueryServiceImpl.class);
|
||||
private final GrafanaAPIService grafanaAPIService;
|
||||
|
||||
public GrafanaQueryServiceImpl(GrafanaAPIService grafanaAPIService) {
|
||||
this.grafanaAPIService = grafanaAPIService;
|
||||
}
|
||||
|
||||
public void buildSafeQuery(JsonObject queryRequestBody, String dashboardUID, String panelId, URI requestUri)
|
||||
throws IOException, SQLException, GrafanaManagementException, DBConnectionException {
|
||||
JsonArray queries = queryRequestBody.getAsJsonArray(GrafanaConstants.QUERY_BODY_QUERIES_KEY);
|
||||
for (int i = 0; i < queries.size(); i++) {
|
||||
JsonObject queryObj = queries.get(i).getAsJsonObject();
|
||||
JsonElement refIdJson = queryObj.get(GrafanaConstants.QUERY_REF_ID_KEY);
|
||||
JsonElement rawSqlJson = queryObj.get(GrafanaConstants.RAW_SQL_KEY);
|
||||
JsonElement datasourceIdJson = queryObj.get(GrafanaConstants.DATASOURCE_ID_KEY);
|
||||
if (refIdJson == null || rawSqlJson == null || datasourceIdJson == null) {
|
||||
String errMsg = "Query json body: refId, rawSql and datasourceId cannot be null";
|
||||
log.error(errMsg);
|
||||
throw new MaliciousQueryAttempt(errMsg);
|
||||
}
|
||||
String refId = refIdJson.getAsString();
|
||||
String rawSql = rawSqlJson.getAsString();
|
||||
int datasourceId = datasourceIdJson.getAsInt();
|
||||
CacheManager cacheManager = CacheManager.getInstance();
|
||||
String encodedQuery = cacheManager.getEncodedQueryCache().getIfPresent(rawSql);
|
||||
if (cacheManager.getEncodedQueryCache().getIfPresent(rawSql) != null) {
|
||||
queryObj.addProperty(GrafanaConstants.RAW_SQL_KEY, encodedQuery);
|
||||
return;
|
||||
}
|
||||
Datasource datasource = cacheManager.getDatasourceAPICache().getIfPresent(datasourceId);
|
||||
if (datasource == null) {
|
||||
datasource = grafanaAPIService.getDatasource(datasourceId, requestUri.getScheme());
|
||||
}
|
||||
String queryTemplate = cacheManager.getQueryTemplateAPICache().
|
||||
getIfPresent(new QueryTemplateCacheKey(dashboardUID, panelId, refId));
|
||||
try {
|
||||
if (queryTemplate != null) {
|
||||
try {
|
||||
encodeQuery(queryObj, datasource, queryTemplate, rawSql);
|
||||
} catch (QueryMisMatch e) {
|
||||
log.error("Error occurred while encoding query, " +
|
||||
"retrying to encode by getting the query template from api instead of cache", e);
|
||||
queryTemplate = grafanaAPIService.getQueryTemplate(dashboardUID, panelId, refId, requestUri.getScheme());
|
||||
encodeQuery(queryObj, datasource, queryTemplate, rawSql);
|
||||
}
|
||||
} else {
|
||||
queryTemplate = grafanaAPIService.getQueryTemplate(dashboardUID, panelId, refId, requestUri.getScheme());
|
||||
encodeQuery(queryObj, datasource, queryTemplate, rawSql);
|
||||
}
|
||||
} catch (QueryNotFound e) {
|
||||
String errMsg = "No query exists for {dashboard: " + dashboardUID +
|
||||
", panelId: " + panelId + ", refId: " + refId + "}";
|
||||
log.error(errMsg);
|
||||
throw new QueryNotFound(errMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeQuery(JsonObject queryObj, Datasource datasource, String queryTemplate, String rawSql)
|
||||
throws SQLException, GrafanaManagementException, DBConnectionException {
|
||||
PreparedQuery pq = GrafanaPreparedQueryBuilder.build(queryTemplate, rawSql);
|
||||
String encodedQuery = QueryEncoderFactory.createEncoder(datasource.getType(), datasource.getName()).encode(pq);
|
||||
CacheManager.getInstance().getEncodedQueryCache().put(rawSql, encodedQuery);
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("Encoded query: " + encodedQuery);
|
||||
}
|
||||
queryObj.addProperty(GrafanaConstants.RAW_SQL_KEY, encodedQuery);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package org.wso2.carbon.device.mgt.core.grafana.mgt.sql.connection;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
|
||||
import org.wso2.carbon.device.mgt.core.config.DeviceManagementConfig;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.GrafanaConfiguration;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.GrafanaConfigurationManager;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.config.ReportMgtConfiguration;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.config.ReportMgtConfigurationManager;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.dao.common.ReportMgtConnectionManager;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
public class GrafanaDatasourceConnectionFactory {
|
||||
|
||||
private static final ReportMgtConfiguration reportMgtConfiguration= ReportMgtConfigurationManager.getInstance().
|
||||
getConfiguration();
|
||||
private static final DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance().
|
||||
getDeviceManagementConfig();
|
||||
|
||||
public static Connection getConnection(String databaseName) throws SQLException, DBConnectionException {
|
||||
if(databaseName.equals(getReportManagementDatasourceName())) {
|
||||
ReportMgtConnectionManager.openDBConnection();
|
||||
return ReportMgtConnectionManager.getDBConnection();
|
||||
} else if (databaseName.equals(getDeviceManagementDatasourceName())) {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
return DeviceManagementDAOFactory.getConnection();
|
||||
} else {
|
||||
throw new RuntimeException("No such datasource with the name: " + databaseName);
|
||||
}
|
||||
}
|
||||
public static void closeConnection(String databaseName) throws SQLException, DBConnectionException {
|
||||
if(databaseName.equals(getReportManagementDatasourceName())) {
|
||||
ReportMgtConnectionManager.closeDBConnection();
|
||||
} else if (databaseName.equals(getDeviceManagementDatasourceName())) {
|
||||
DeviceManagementDAOFactory.closeConnection();
|
||||
} else {
|
||||
throw new RuntimeException("No such datasource with the name: " + databaseName);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getReportManagementDatasourceName() {
|
||||
return reportMgtConfiguration.getDatasourceName();
|
||||
}
|
||||
|
||||
private static String getDeviceManagementDatasourceName() {
|
||||
return deviceManagementConfig.getDeviceManagementConfigRepository().getDataSourceConfig().
|
||||
getJndiLookupDefinition().getJndiName();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.sql.query;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.QueryMisMatch;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaConstants;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class GrafanaPreparedQueryBuilder {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GrafanaPreparedQueryBuilder.class);
|
||||
|
||||
private static final String QUERY_MISMATCH_EXCEPTION_MESSAGE = "Grafana query api request rawSql does not match relevant query template";
|
||||
private static final String COMMA_SEPARATOR = ",";
|
||||
private static final String VAR_PARAM_TEMPLATE = "$param";
|
||||
private static final String GRAFANA_QUOTED_VAR_REGEX = "('\\$(\\d|\\w|_)+')|('\\$\\{.*?\\}')|(\"\\$(\\d|\\w|_)+\")|(\"\\$\\{.*?\\}\")";
|
||||
private static final String GRAFANA_VAR_REGEX = "(\\$(\\d|\\w|_)+)|(\\$\\{.*?\\})";
|
||||
|
||||
|
||||
public static PreparedQuery build(String queryTemplate, String rawQuery) throws QueryMisMatch {
|
||||
// In Grafana, a variable can coexist with a hardcoded parameter (ie: '${__from:date:YYYY-MM-DD} 00:00:00')
|
||||
// hence this function templates the whole parameter in order to make valid prepared statement
|
||||
queryTemplate = templateParamWGrafanaVariables(queryTemplate);
|
||||
|
||||
String queryUpToVarStart = queryTemplate;
|
||||
String rawQueryUpToVarStart = rawQuery;
|
||||
|
||||
// Pattern matcher to get query string before the first grafana variable
|
||||
Pattern toVarStart = Pattern.compile("([^\\$]+(?=\"\\$))|([^\\$]+(?='\\$))|([^\\$]+(?=\\$))");
|
||||
Matcher matchToVarStart = toVarStart.matcher(queryTemplate);
|
||||
|
||||
if (matchToVarStart.find()) {
|
||||
queryUpToVarStart = matchToVarStart.group();
|
||||
if(rawQuery.length() < queryUpToVarStart.length()) {
|
||||
throw new QueryMisMatch(QUERY_MISMATCH_EXCEPTION_MESSAGE);
|
||||
}
|
||||
rawQueryUpToVarStart = rawQuery.substring(0, queryUpToVarStart.length());
|
||||
}
|
||||
if(!queryUpToVarStart.equals(rawQueryUpToVarStart)){
|
||||
throw new QueryMisMatch(QUERY_MISMATCH_EXCEPTION_MESSAGE);
|
||||
}
|
||||
StringBuilder preparedQueryBuilder = new StringBuilder().append(queryUpToVarStart);
|
||||
|
||||
String queryFromVarStart = queryTemplate.substring(queryUpToVarStart.length());
|
||||
String rawQueryFromVarStart = rawQuery.substring(queryUpToVarStart.length());
|
||||
queryTemplate = queryFromVarStart;
|
||||
rawQuery = rawQueryFromVarStart;
|
||||
Pattern varPattern = Pattern.compile(GRAFANA_QUOTED_VAR_REGEX + "|" + GRAFANA_VAR_REGEX);
|
||||
Matcher varMatch = varPattern.matcher(queryTemplate);
|
||||
List<String> parameters = new ArrayList<>();
|
||||
while(varMatch.find()) {
|
||||
String currentVar = varMatch.group();
|
||||
// Pattern matcher to get query string between grafana current variable and next variable
|
||||
matchToVarStart = toVarStart.matcher(queryTemplate.substring(currentVar.length()));
|
||||
|
||||
String matchToLookBehindRawQuery;
|
||||
if (matchToVarStart.find()) {
|
||||
matchToLookBehindRawQuery = matchToVarStart.group();
|
||||
} else {
|
||||
// If next variable does not exist get query string after the current variable
|
||||
matchToLookBehindRawQuery = queryTemplate.substring(currentVar.length());
|
||||
}
|
||||
String currentVarInput;
|
||||
if (matchToLookBehindRawQuery.isEmpty()) {
|
||||
// If there is no string after the current variable, then remaining segment of rawQuery is the
|
||||
// current variable input (rawQuery is sliced up to the next variable)
|
||||
currentVarInput = rawQuery;
|
||||
} else {
|
||||
Matcher lookBehindRQ = Pattern.compile("(.*?)(?=" + Pattern.quote(matchToLookBehindRawQuery) + ")").matcher(rawQuery);
|
||||
if (!lookBehindRQ.find()) {
|
||||
throw new QueryMisMatch(QUERY_MISMATCH_EXCEPTION_MESSAGE);
|
||||
}
|
||||
currentVarInput = lookBehindRQ.group();
|
||||
}
|
||||
if (isTenantIdVar(currentVar)) {
|
||||
preparedQueryBuilder.append(GrafanaUtil.getTenantId());
|
||||
} else {
|
||||
// Grafana variable input can be multi-valued, which are separated by comma by default
|
||||
String[] varValues = splitByComma(currentVarInput);
|
||||
List<String> preparedStatementPlaceHolders = new ArrayList<>();
|
||||
for (String v : varValues) {
|
||||
String param = unQuoteString(v);
|
||||
if (isSafeVariableInput(param)) {
|
||||
preparedStatementPlaceHolders.add(v);
|
||||
} else {
|
||||
parameters.add(param);
|
||||
preparedStatementPlaceHolders.add(PreparedQuery.PREPARED_SQL_PARAM_PLACEHOLDER);
|
||||
}
|
||||
}
|
||||
preparedQueryBuilder.append(String.join(COMMA_SEPARATOR, preparedStatementPlaceHolders));
|
||||
}
|
||||
preparedQueryBuilder.append(matchToLookBehindRawQuery);
|
||||
// Get template and raw query string from next variable
|
||||
queryTemplate = queryTemplate.substring(currentVar.length() + matchToLookBehindRawQuery.length());
|
||||
rawQuery = rawQuery.substring(currentVarInput.length() + matchToLookBehindRawQuery.length());
|
||||
|
||||
varMatch = varPattern.matcher(queryTemplate);
|
||||
}
|
||||
if (!queryTemplate.equals(rawQuery)) {
|
||||
throw new QueryMisMatch(QUERY_MISMATCH_EXCEPTION_MESSAGE);
|
||||
}
|
||||
return new PreparedQuery(preparedQueryBuilder.toString(), parameters);
|
||||
}
|
||||
|
||||
private static String[] splitByComma(String str) {
|
||||
// Using regex to avoid splitting by comma inside quotes
|
||||
return str.split("(\\s|\\t)*,(\\s|\\t)*(?=(?:[^'\"]*['|\"][^'\"]*['|\"])*[^'\"]*$)");
|
||||
}
|
||||
|
||||
private static String templateParamWGrafanaVariables(String queryTemplate) {
|
||||
// TODO: handle escaped quotes and special characters
|
||||
Pattern quotedStringPattern = Pattern.compile("(\"(.+?)\")|('(.+?)')");
|
||||
Matcher quotedStringMatch = quotedStringPattern.matcher(queryTemplate);
|
||||
while(quotedStringMatch.find()) {
|
||||
String quotedString = quotedStringMatch.group();
|
||||
Matcher varMatcher = Pattern.compile(GRAFANA_VAR_REGEX).matcher(quotedString);
|
||||
// If grafana variable exists in single quoted string
|
||||
if(varMatcher.find()) {
|
||||
String var = varMatcher.group();
|
||||
if (!isTenantIdVar(var)) {
|
||||
String templatedQuotedString = templateQuotedString(quotedString);
|
||||
// escape any special characters
|
||||
templatedQuotedString = Matcher.quoteReplacement(templatedQuotedString);
|
||||
queryTemplate = queryTemplate.replaceFirst(Pattern.quote(quotedString), templatedQuotedString);
|
||||
}
|
||||
}
|
||||
}
|
||||
return queryTemplate;
|
||||
}
|
||||
|
||||
private static String templateQuotedString(String quotedString) {
|
||||
return quotedString.replaceFirst("[^']+|[^\"]+",
|
||||
Matcher.quoteReplacement(VAR_PARAM_TEMPLATE));
|
||||
}
|
||||
|
||||
private static boolean isSafeVariableInput(String currentVarInput) {
|
||||
if (StringUtils.isEmpty(currentVarInput)) {
|
||||
return true;
|
||||
}
|
||||
return currentVarInput.matches("\\$?[a-zA-Z0-9-_\\.]+|^\"[a-zA-Z0-9-_\\.\\s]+\"$|^'[a-zA-Z0-9-_\\.\\s]+'$");
|
||||
}
|
||||
|
||||
private static String unQuoteString(String str) {
|
||||
if (isQuoted(str)) {
|
||||
int firstCharIndex = 0;
|
||||
int lastCharIndex = str.length() - 1;
|
||||
return str.substring(firstCharIndex + 1, lastCharIndex);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private static boolean isQuoted(String str) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
return false;
|
||||
}
|
||||
int firstCharIndex = 0;
|
||||
int lastCharIndex = str.length() - 1;
|
||||
return (str.charAt(firstCharIndex) == '\'' && str.charAt(lastCharIndex) == '\'') ||
|
||||
(str.charAt(firstCharIndex) == '"' && str.charAt(lastCharIndex) == '"');
|
||||
}
|
||||
|
||||
private static boolean isTenantIdVar(String var) {
|
||||
return var.equals(GrafanaConstants.TENANT_ID_VAR) || var.equals(singleQuoteString(GrafanaConstants.TENANT_ID_VAR))
|
||||
|| var.equals(doubleQuoteString(GrafanaConstants.TENANT_ID_VAR));
|
||||
}
|
||||
|
||||
private static String doubleQuoteString(String str) {
|
||||
return "\"" + str + "\"";
|
||||
}
|
||||
|
||||
private static String singleQuoteString(String str) {
|
||||
return "'" + str + "'";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.sql.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PreparedQuery {
|
||||
|
||||
public static final String PREPARED_SQL_PARAM_PLACEHOLDER = "?";
|
||||
|
||||
private String preparedSQL;
|
||||
private List<String> parameters;
|
||||
|
||||
public PreparedQuery(String preparedSQL, List<String> parameters) {
|
||||
this.preparedSQL = preparedSQL;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public String getPreparedSQL() {
|
||||
return preparedSQL;
|
||||
}
|
||||
|
||||
public void setPreparedSQL(String preparedSQL) {
|
||||
this.preparedSQL = preparedSQL;
|
||||
}
|
||||
|
||||
public List<String> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(List<String> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.encoder;
|
||||
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.PreparedQuery;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class GenericQueryEncoder implements QueryEncoder{
|
||||
|
||||
public GenericQueryEncoder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encode(PreparedQuery preparedQuery) throws SQLException {
|
||||
return generateEncodedSQL(preparedQuery.getPreparedSQL(), preparedQuery.getParameters());
|
||||
}
|
||||
|
||||
private String generateEncodedSQL(String preparedSQL, List<String> parameters) throws SQLException {
|
||||
List<String> escapedParams = escapeParameters(parameters);
|
||||
Matcher placeHolderMatcher = Pattern.compile(Pattern.quote(PreparedQuery.PREPARED_SQL_PARAM_PLACEHOLDER)).matcher(preparedSQL);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (String param: escapedParams) {
|
||||
if(placeHolderMatcher.find()) {
|
||||
placeHolderMatcher.appendReplacement(sb, Matcher.quoteReplacement(param));
|
||||
} else {
|
||||
String errMsg = "Given parameter count doesn't match parameters available in SQL";
|
||||
throw new SQLException(errMsg);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private List<String> escapeParameters(List<String> parameters) {
|
||||
List<String> escapedParams = new ArrayList<>();
|
||||
for (String param : parameters) {
|
||||
String escapedParam = StringEscapeUtils.escapeSql(param);
|
||||
escapedParams.add(escapedParam);
|
||||
}
|
||||
return escapedParams;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.encoder;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.sql.connection.GrafanaDatasourceConnectionFactory;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.PreparedQuery;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
public class MySQLQueryEncoder implements QueryEncoder {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MySQLQueryEncoder.class);
|
||||
private static final String PREPARED_STATEMENT_STRING_OBJECT_ID_SEPARATOR = ": ";
|
||||
|
||||
private final String databaseName;
|
||||
|
||||
public MySQLQueryEncoder(String databaseName) {
|
||||
this.databaseName = databaseName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encode(PreparedQuery preparedQuery) throws SQLException, DBConnectionException {
|
||||
try {
|
||||
Connection con = GrafanaDatasourceConnectionFactory.getConnection(databaseName);
|
||||
PreparedStatement stmt = con.prepareStatement(preparedQuery.getPreparedSQL());
|
||||
setParameters(stmt, preparedQuery.getParameters());
|
||||
return generateQueryFromPreparedStatement(stmt);
|
||||
} finally {
|
||||
GrafanaDatasourceConnectionFactory.closeConnection(databaseName);
|
||||
}
|
||||
}
|
||||
|
||||
public void setParameters(PreparedStatement stmt, List<String> parameters)
|
||||
throws SQLException {
|
||||
int i = 0;
|
||||
for (String p : parameters) {
|
||||
stmt.setObject(++i, p);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateQueryFromPreparedStatement(PreparedStatement stmt) {
|
||||
String query = stmt.toString().substring(stmt.toString().indexOf(PREPARED_STATEMENT_STRING_OBJECT_ID_SEPARATOR) +
|
||||
PREPARED_STATEMENT_STRING_OBJECT_ID_SEPARATOR.length());
|
||||
// remove unnecessary "]" char at the end
|
||||
if (query.charAt(query.length() - 1) == ']') {
|
||||
query = query.substring(0, query.length() - 1);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.encoder;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.PreparedQuery;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public interface QueryEncoder {
|
||||
|
||||
String encode(PreparedQuery preparedQuery) throws SQLException, DBConnectionException;
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.sql.query.encoder;
|
||||
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaConstants;
|
||||
|
||||
public class QueryEncoderFactory {
|
||||
|
||||
public static QueryEncoder createEncoder(String datasourceType, String databaseName) {
|
||||
if (datasourceType.equals(GrafanaConstants.DATASOURCE_TYPE.MYSQL)) {
|
||||
return new MySQLQueryEncoder(databaseName);
|
||||
} else {
|
||||
return new GenericQueryEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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.wso2.carbon.device.mgt.core.grafana.mgt.util;
|
||||
|
||||
public class GrafanaConstants {
|
||||
|
||||
public static final String QUERY_API_CACHE_NAME = "queryAPICache";
|
||||
public static final String ENCODED_QUERY_CACHE_NAME = "encodedQueryCache";
|
||||
public static final String REFERER_HEADER = "Referer";
|
||||
public static final String CONFIG_XML_NAME = "grafana-config.xml";
|
||||
public static final String X_GRAFANA_ORG_ID_HEADER = "x-org-grafana-id";
|
||||
|
||||
public static class XML {
|
||||
public static final String FEATURES_DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
}
|
||||
|
||||
public static class DATASOURCE_TYPE {
|
||||
public static final String MYSQL = "mysql";
|
||||
public static final String POSTGRESQL = "postgresql";
|
||||
public static final String MICROSOFT_SQL_SERVER = "mssql";
|
||||
public static final String ORACLE = "oracle";
|
||||
}
|
||||
|
||||
public static final int IFRAME_URL_DASHBOARD_UID_INDEX = 1;
|
||||
|
||||
public static final String TENANT_ID_VAR_NAME = "tenantId";
|
||||
public static final String VAR_PREFIX = "$";
|
||||
public static final String TENANT_ID_VAR = VAR_PREFIX + TENANT_ID_VAR_NAME;
|
||||
public static final String QUERY_PARAM_VAR_PREFIX = "var-";
|
||||
public static final String TENANT_ID_VAR_QUERY_PARAM = QUERY_PARAM_VAR_PREFIX + TENANT_ID_VAR_NAME;
|
||||
public static final String API_PATH = "/api";
|
||||
public static final String DASHBOARD_KEY = "dashboard";
|
||||
public static final String DATASOURCE_TYPE_KEY = "type";
|
||||
public static final String DATASOURCE_DB_KEY = "database";
|
||||
public static final String DATASOURCE_ID_KEY = "datasourceId";
|
||||
public static final String DATASOURCE_NAME_KEY = "name";
|
||||
public static final String DATASOURCE_URL_KEY = "name";
|
||||
public static final String PANEL_KEY = "panels";
|
||||
public static final String TEMPLATING_KEY = "templating";
|
||||
public static final String TEMPLATING_NAME_KEY = "name";
|
||||
public static final String TEMPLATE_QUERY_KEY = "query";
|
||||
public static final String TEMPLATING_LIST_KEY = "list";
|
||||
public static final String RAW_SQL_KEY = "rawSql";
|
||||
public static final String QUERY_BODY_QUERIES_KEY = "queries";
|
||||
public static final String DASHBOARD_PANEL_DETAIL_QUERIES_KEY = "targets";
|
||||
public static final String QUERY_REF_ID_KEY = "refId";
|
||||
public static final String PANEL_ID_QUERY_PARAM = "panelId";
|
||||
public static final String ORG_ID_QUERY_PARAM = "panelId";
|
||||
public static final String ID_KEY = "id";
|
||||
|
||||
public static final String WS_LIVE_API = "/api/live/ws";
|
||||
public static final String DASHBOARD_API = "/api/dashboards/uid";
|
||||
public static final String DATASOURCE_API = "/api/datasources";
|
||||
public static final String HTTP_HOST_ENV_VAR = "iot.grafana.http.host";
|
||||
public static final String HTTPS_HOST_ENV_VAR = "iot.grafana.https.host";
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
/* Copyright (c) 2020, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (Pvt) Ltd. 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.wso2.carbon.device.mgt.core.grafana.mgt.util;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.common.util.HttpUtil;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.bean.GrafanaPanelIdentifier;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.GrafanaConfiguration;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.config.GrafanaConfigurationManager;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.GrafanaEnvVariablesNotDefined;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.GrafanaAPIService;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.GrafanaQueryService;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.Constants;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class GrafanaUtil {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GrafanaUtil.class);
|
||||
|
||||
public static boolean isGrafanaAPI(String uri) {
|
||||
return uri.contains(GrafanaConstants.API_PATH);
|
||||
}
|
||||
|
||||
public static String generateGrafanaUrl(String requestPath, String base) {
|
||||
base += Constants.URI_SEPARATOR;
|
||||
return base + requestPath;
|
||||
}
|
||||
public static String getGrafanaWebSocketBase(String requestScheme) throws GrafanaEnvVariablesNotDefined {
|
||||
return getGrafanaBase(requestScheme, Constants.WS_PROTOCOL, Constants.WSS_PROTOCOL);
|
||||
}
|
||||
public static String getGrafanaHTTPBase(String requestScheme) throws GrafanaEnvVariablesNotDefined {
|
||||
return getGrafanaBase(requestScheme, Constants.HTTP_PROTOCOL, Constants.HTTPS_PROTOCOL);
|
||||
}
|
||||
|
||||
public static String getGrafanaBase(String requestScheme, String httpProtocol, String httpsProtocol)
|
||||
throws GrafanaEnvVariablesNotDefined {
|
||||
String grafanaHost = System.getProperty(GrafanaConstants.HTTPS_HOST_ENV_VAR);
|
||||
String scheme = httpsProtocol;
|
||||
if (Constants.HTTP_PROTOCOL.equals(requestScheme) || grafanaHost == null){
|
||||
grafanaHost = System.getProperty(GrafanaConstants.HTTP_HOST_ENV_VAR);
|
||||
scheme = httpProtocol;
|
||||
}
|
||||
if(grafanaHost == null) {
|
||||
String errMsg = "Grafana host is not defined in the iot-server.sh properly.";
|
||||
log.error(errMsg);
|
||||
throw new GrafanaEnvVariablesNotDefined(errMsg);
|
||||
}
|
||||
return scheme + Constants.SCHEME_SEPARATOR + grafanaHost;
|
||||
}
|
||||
|
||||
public static String getPanelId(URI iframeURL) {
|
||||
Map<String, List<String>> queryMap = HttpUtil.getQueryMap(iframeURL);
|
||||
return HttpUtil.getFirstQueryValue(GrafanaConstants.PANEL_ID_QUERY_PARAM, queryMap);
|
||||
}
|
||||
public static String getOrgId(URI iframeURL) {
|
||||
Map<String, List<String>> queryMap = HttpUtil.getQueryMap(iframeURL);
|
||||
return HttpUtil.getFirstQueryValue(GrafanaConstants.ORG_ID_QUERY_PARAM, queryMap);
|
||||
}
|
||||
|
||||
public static String getDashboardUID(URI iframeURL) {
|
||||
return HttpUtil.getRequestSubPathFromEnd(iframeURL, GrafanaConstants.IFRAME_URL_DASHBOARD_UID_INDEX);
|
||||
}
|
||||
|
||||
public static JsonObject getJsonBody(String body) {
|
||||
return new Gson().fromJson(body, JsonObject.class);
|
||||
}
|
||||
|
||||
public static String getBasicAuthBase64Header() throws GrafanaManagementException {
|
||||
GrafanaConfiguration configuration = GrafanaConfigurationManager.getInstance().getGrafanaConfiguration();
|
||||
String username = configuration.getAdminUser().getUsername();
|
||||
String password = configuration.getAdminUser().getPassword();
|
||||
return Constants.BASIC_AUTH_HEADER_PREFIX + GrafanaUtil.getBase64Encode(username, password);
|
||||
}
|
||||
|
||||
public static String getBase64Encode(String key, String value) {
|
||||
return new String(Base64.encodeBase64((key + ":" + value).getBytes()));
|
||||
}
|
||||
|
||||
public static GrafanaPanelIdentifier getPanelIdentifierFromReferer(String referer) {
|
||||
URI refererUri = HttpUtil.createURI(referer);
|
||||
String orgId = GrafanaUtil.getOrgId(refererUri);
|
||||
String dashboardUID = GrafanaUtil.getDashboardUID(refererUri);
|
||||
String panelId = GrafanaUtil.getPanelId(refererUri);
|
||||
return new GrafanaPanelIdentifier(orgId, dashboardUID, panelId);
|
||||
}
|
||||
|
||||
public static int getTenantId() {
|
||||
return PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
|
||||
}
|
||||
|
||||
public static GrafanaAPIService getGrafanaAPIService() {
|
||||
GrafanaAPIService grafanaAPIService;
|
||||
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
|
||||
grafanaAPIService = (GrafanaAPIService) ctx.getOSGiService(
|
||||
GrafanaAPIService.class, null);
|
||||
if (grafanaAPIService == null) {
|
||||
String msg = "Report Management service not initialized.";
|
||||
log.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
return grafanaAPIService;
|
||||
}
|
||||
|
||||
public static GrafanaQueryService getGrafanaQueryService() {
|
||||
GrafanaQueryService grafanaQueryService;
|
||||
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
|
||||
grafanaQueryService = (GrafanaQueryService) ctx.getOSGiService(
|
||||
GrafanaQueryService.class, null);
|
||||
if (grafanaQueryService == null) {
|
||||
String msg = "Report Management service not initialized.";
|
||||
log.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
return grafanaQueryService;
|
||||
}
|
||||
|
||||
}
|
||||
@ -56,6 +56,10 @@ import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManag
|
||||
import org.wso2.carbon.device.mgt.core.device.details.mgt.impl.DeviceInformationManagerImpl;
|
||||
import org.wso2.carbon.device.mgt.core.event.config.EventConfigurationProviderServiceImpl;
|
||||
import org.wso2.carbon.device.mgt.core.geo.service.GeoLocationProviderServiceImpl;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.GrafanaAPIService;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.GrafanaQueryService;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.impl.GrafanaAPIServiceImpl;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.service.impl.GrafanaQueryServiceImpl;
|
||||
import org.wso2.carbon.device.mgt.core.metadata.mgt.MetadataManagementServiceImpl;
|
||||
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOFactory;
|
||||
import org.wso2.carbon.device.mgt.core.notification.mgt.NotificationManagementServiceImpl;
|
||||
@ -330,6 +334,13 @@ public class DeviceManagementServiceComponent {
|
||||
= new NotificationManagementServiceImpl();
|
||||
bundleContext.registerService(NotificationManagementService.class.getName(), notificationManagementService, null);
|
||||
|
||||
/* Registering Grafana Services */
|
||||
GrafanaAPIService grafanaAPIService = new GrafanaAPIServiceImpl();
|
||||
GrafanaQueryService grafanaQueryService = new GrafanaQueryServiceImpl(grafanaAPIService);
|
||||
bundleContext.registerService(GrafanaAPIService.class.getName(), grafanaAPIService, null);
|
||||
bundleContext.registerService(GrafanaQueryService.class.getName(), grafanaQueryService, null);
|
||||
|
||||
|
||||
/* Registering Report Service */
|
||||
ReportManagementService reportManagementService = new ReportManagementServiceImpl();
|
||||
bundleContext.registerService(ReportManagementService.class.getName(), reportManagementService, null);
|
||||
|
||||
@ -1173,10 +1173,10 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
Operation operation = null;
|
||||
try {
|
||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
||||
String sql = "SELECT o.ID, o.TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, om.STATUS, o.OPERATION_CODE, " +
|
||||
"om.ID AS OM_MAPPING_ID, " +
|
||||
String sql = "SELECT o.ID, o.TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, om.STATUS, " +
|
||||
"o.OPERATION_CODE, o.INITIATED_BY, om.ID AS OM_MAPPING_ID, " +
|
||||
"om.UPDATED_TIMESTAMP FROM (SELECT ID, TYPE, CREATED_TIMESTAMP, RECEIVED_TIMESTAMP," +
|
||||
"OPERATION_CODE FROM DM_OPERATION WHERE id = ?) o INNER JOIN (SELECT * FROM " +
|
||||
"OPERATION_CODE, INITIATED_BY FROM DM_OPERATION WHERE id = ?) o INNER JOIN (SELECT * FROM " +
|
||||
"DM_ENROLMENT_OP_MAPPING dm where dm.OPERATION_ID = ? AND dm.ENROLMENT_ID = ?) om " +
|
||||
"ON o.ID = om.OPERATION_ID ";
|
||||
stmt = conn.prepareStatement(sql);
|
||||
@ -1198,6 +1198,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
new Timestamp((rs.getLong("UPDATED_TIMESTAMP") * 1000)).toString());
|
||||
}
|
||||
operation.setCode(rs.getString("OPERATION_CODE"));
|
||||
operation.setInitiatedBy(rs.getString("INITIATED_BY"));
|
||||
OperationDAOUtil.setActivityId(operation, rs.getInt("ID"));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
@ -1215,11 +1216,11 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
Operation operation;
|
||||
List<Operation> operations = new ArrayList<Operation>();
|
||||
List<Operation> operations = new ArrayList<>();
|
||||
try {
|
||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
||||
String sql = "SELECT o.ID, TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, o.OPERATION_CODE, om.ID AS OM_MAPPING_ID," +
|
||||
"om.UPDATED_TIMESTAMP FROM DM_OPERATION o " +
|
||||
String sql = "SELECT o.ID, TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, o.OPERATION_CODE, " +
|
||||
"o.INITIATED_BY, om.ID AS OM_MAPPING_ID, om.UPDATED_TIMESTAMP FROM DM_OPERATION o " +
|
||||
"INNER JOIN (SELECT * FROM DM_ENROLMENT_OP_MAPPING dm " +
|
||||
"WHERE dm.ENROLMENT_ID = ? AND dm.STATUS = ?) om ON o.ID = om.OPERATION_ID ORDER BY o.CREATED_TIMESTAMP DESC";
|
||||
stmt = conn.prepareStatement(sql);
|
||||
@ -1239,6 +1240,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
new Timestamp((rs.getLong("UPDATED_TIMESTAMP") * 1000)).toString());
|
||||
}
|
||||
operation.setCode(rs.getString("OPERATION_CODE"));
|
||||
operation.setInitiatedBy(rs.getString("INITIATED_BY"));
|
||||
operation.setStatus(status);
|
||||
OperationDAOUtil.setActivityId(operation, rs.getInt("ID"));
|
||||
operations.add(operation);
|
||||
@ -1263,7 +1265,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
try {
|
||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
||||
String sql = "SELECT o.ID, TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, o.OPERATION_CODE, " +
|
||||
"om.ID AS OM_MAPPING_ID, om.UPDATED_TIMESTAMP FROM DM_OPERATION o " +
|
||||
"o.INITIATED_BY, om.ID AS OM_MAPPING_ID, om.UPDATED_TIMESTAMP FROM DM_OPERATION o " +
|
||||
"INNER JOIN (SELECT * FROM DM_ENROLMENT_OP_MAPPING dm " +
|
||||
"WHERE dm.ENROLMENT_ID = ? AND dm.STATUS = ?) om ON o.ID = om.OPERATION_ID ORDER BY " +
|
||||
"o.CREATED_TIMESTAMP DESC LIMIT ?,?";
|
||||
@ -1286,6 +1288,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
new Timestamp((rs.getLong("UPDATED_TIMESTAMP") * 1000)).toString());
|
||||
}
|
||||
operation.setCode(rs.getString("OPERATION_CODE"));
|
||||
operation.setInitiatedBy(rs.getString("INITIATED_BY"));
|
||||
operation.setStatus(status);
|
||||
OperationDAOUtil.setActivityId(operation, rs.getInt("OM_MAPPING_ID"));
|
||||
operations.add(operation);
|
||||
@ -1309,8 +1312,8 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
try {
|
||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
||||
String sql = "SELECT o.ID, o.TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, " +
|
||||
"o.OPERATION_CODE, om.STATUS, om.ID AS OM_MAPPING_ID, om.UPDATED_TIMESTAMP FROM DM_OPERATION o " +
|
||||
"INNER JOIN (SELECT * FROM DM_ENROLMENT_OP_MAPPING dm " +
|
||||
"o.OPERATION_CODE, o.INITIATED_BY, om.STATUS, om.ID AS OM_MAPPING_ID, om.UPDATED_TIMESTAMP " +
|
||||
"FROM DM_OPERATION o INNER JOIN (SELECT * FROM DM_ENROLMENT_OP_MAPPING dm " +
|
||||
"WHERE dm.ENROLMENT_ID = ?) om ON o.ID = om.OPERATION_ID " +
|
||||
"ORDER BY o.CREATED_TIMESTAMP DESC, o.ID DESC";
|
||||
stmt = conn.prepareStatement(sql);
|
||||
@ -1329,6 +1332,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
new Timestamp((rs.getLong("UPDATED_TIMESTAMP") * 1000)).toString());
|
||||
}
|
||||
operation.setCode(rs.getString("OPERATION_CODE"));
|
||||
operation.setInitiatedBy(rs.getString("INITIATED_BY"));
|
||||
operation.setStatus(Operation.Status.valueOf(rs.getString("STATUS")));
|
||||
operations.add(operation);
|
||||
}
|
||||
@ -1345,7 +1349,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
public List<? extends Operation> getOperationsForDevice(int enrolmentId, PaginationRequest request)
|
||||
throws OperationManagementDAOException {
|
||||
Operation operation;
|
||||
List<Operation> operations = new ArrayList<Operation>();
|
||||
List<Operation> operations = new ArrayList<>();
|
||||
String createdTo = null;
|
||||
String createdFrom = null;
|
||||
DateFormat simple = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
@ -1363,74 +1367,75 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
Long updatedTo = request.getOperationLogFilters().getUpdatedDayTo();
|
||||
List<String> operationCode = request.getOperationLogFilters().getOperationCode();
|
||||
List<String> status = request.getOperationLogFilters().getStatus();
|
||||
String sql = "SELECT " +
|
||||
"o.ID, " +
|
||||
"TYPE, " +
|
||||
"o.CREATED_TIMESTAMP, " +
|
||||
"o.RECEIVED_TIMESTAMP, " +
|
||||
"o.OPERATION_CODE, " +
|
||||
"om.STATUS, " +
|
||||
"om.ID AS OM_MAPPING_ID, " +
|
||||
"om.UPDATED_TIMESTAMP " +
|
||||
"FROM " +
|
||||
"DM_OPERATION o " +
|
||||
"INNER JOIN " +
|
||||
"(SELECT dm.OPERATION_ID, " +
|
||||
"dm.ID, " +
|
||||
"dm.STATUS, " +
|
||||
"dm.UPDATED_TIMESTAMP " +
|
||||
"FROM " +
|
||||
"DM_ENROLMENT_OP_MAPPING dm " +
|
||||
"WHERE " +
|
||||
"dm.ENROLMENT_ID = ?";
|
||||
StringBuilder sql = new StringBuilder("SELECT " +
|
||||
"o.ID, " +
|
||||
"TYPE, " +
|
||||
"o.CREATED_TIMESTAMP, " +
|
||||
"o.RECEIVED_TIMESTAMP, " +
|
||||
"o.OPERATION_CODE, " +
|
||||
"o.INITIATED_BY, " +
|
||||
"om.STATUS, " +
|
||||
"om.ID AS OM_MAPPING_ID, " +
|
||||
"om.UPDATED_TIMESTAMP " +
|
||||
"FROM " +
|
||||
"DM_OPERATION o " +
|
||||
"INNER JOIN " +
|
||||
"(SELECT dm.OPERATION_ID, " +
|
||||
"dm.ID, " +
|
||||
"dm.STATUS, " +
|
||||
"dm.UPDATED_TIMESTAMP " +
|
||||
"FROM " +
|
||||
"DM_ENROLMENT_OP_MAPPING dm " +
|
||||
"WHERE " +
|
||||
"dm.ENROLMENT_ID = ?");
|
||||
|
||||
if (updatedFrom != null && updatedFrom != 0 && updatedTo != null && updatedTo != 0) {
|
||||
sql = sql + " AND dm.UPDATED_TIMESTAMP BETWEEN ? AND ?";
|
||||
sql.append(" AND dm.UPDATED_TIMESTAMP BETWEEN ? AND ?");
|
||||
isUpdatedDayProvided = true;
|
||||
}
|
||||
sql = sql + ") om ON o.ID = om.OPERATION_ID ";
|
||||
sql.append(") om ON o.ID = om.OPERATION_ID ");
|
||||
if (createdFrom != null && !createdFrom.isEmpty() && createdTo != null && !createdTo.isEmpty()) {
|
||||
sql = sql + " WHERE o.CREATED_TIMESTAMP BETWEEN ? AND ?";
|
||||
sql.append(" WHERE o.CREATED_TIMESTAMP BETWEEN ? AND ?");
|
||||
isCreatedDayProvided = true;
|
||||
}
|
||||
if ((isCreatedDayProvided) && (status != null && !status.isEmpty())) {
|
||||
int size = status.size();
|
||||
sql = sql + " AND (om.STATUS = ? ";
|
||||
sql.append(" AND (om.STATUS = ? ");
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
sql = sql + " OR om.STATUS = ?";
|
||||
sql.append(" OR om.STATUS = ?");
|
||||
}
|
||||
sql = sql + ")";
|
||||
sql.append(")");
|
||||
isStatusProvided = true;
|
||||
} else if ((!isCreatedDayProvided) && (status != null && !status.isEmpty())) {
|
||||
int size = status.size();
|
||||
sql = sql + " WHERE (om.STATUS = ? ";
|
||||
sql.append(" WHERE (om.STATUS = ? ");
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
sql = sql + " OR om.STATUS = ?";
|
||||
sql.append(" OR om.STATUS = ?");
|
||||
}
|
||||
sql = sql + ")";
|
||||
sql.append(")");
|
||||
isStatusProvided = true;
|
||||
}
|
||||
if ((isCreatedDayProvided || isStatusProvided) && (operationCode != null && !operationCode.isEmpty())) {
|
||||
int size = operationCode.size();
|
||||
sql = sql + " AND (o.OPERATION_CODE = ? ";
|
||||
sql.append(" AND (o.OPERATION_CODE = ? ");
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
sql = sql + " OR o.OPERATION_CODE = ?";
|
||||
sql.append(" OR o.OPERATION_CODE = ?");
|
||||
}
|
||||
sql = sql + ")";
|
||||
sql.append(")");
|
||||
isOperationCodeProvided = true;
|
||||
} else if ((!isCreatedDayProvided && !isStatusProvided) && (operationCode != null && !operationCode.isEmpty())) {
|
||||
int size = operationCode.size();
|
||||
sql = sql + " WHERE (o.OPERATION_CODE = ? ";
|
||||
sql.append(" WHERE (o.OPERATION_CODE = ? ");
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
sql = sql + " OR o.OPERATION_CODE = ?";
|
||||
sql.append(" OR o.OPERATION_CODE = ?");
|
||||
}
|
||||
sql = sql + ")";
|
||||
sql.append(")");
|
||||
isOperationCodeProvided = true;
|
||||
}
|
||||
sql = sql + " ORDER BY o.CREATED_TIMESTAMP DESC LIMIT ?,?";
|
||||
sql.append(" ORDER BY o.CREATED_TIMESTAMP DESC LIMIT ?,?");
|
||||
try {
|
||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
|
||||
int paramIndex = 1;
|
||||
stmt.setInt(paramIndex++, enrolmentId);
|
||||
if (isUpdatedDayProvided) {
|
||||
@ -1442,15 +1447,13 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
stmt.setString(paramIndex++, createdTo);
|
||||
}
|
||||
if (isStatusProvided) {
|
||||
int size = status.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
stmt.setString(paramIndex++, status.get(i));
|
||||
for (String s : status) {
|
||||
stmt.setString(paramIndex++, s);
|
||||
}
|
||||
}
|
||||
if (isOperationCodeProvided) {
|
||||
int size = operationCode.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
stmt.setString(paramIndex++, operationCode.get(i));
|
||||
for (String s : operationCode) {
|
||||
stmt.setString(paramIndex++, s);
|
||||
}
|
||||
}
|
||||
stmt.setInt(paramIndex++, request.getStartIndex());
|
||||
@ -1468,6 +1471,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
new Timestamp((rs.getLong("UPDATED_TIMESTAMP") * 1000)).toString());
|
||||
}
|
||||
operation.setCode(rs.getString("OPERATION_CODE"));
|
||||
operation.setInitiatedBy(rs.getString("INITIATED_BY"));
|
||||
operation.setStatus(Operation.Status.valueOf(rs.getString("STATUS")));
|
||||
OperationDAOUtil.setActivityId(operation, rs.getInt("ID"));
|
||||
operations.add(operation);
|
||||
@ -1594,7 +1598,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
try {
|
||||
Connection connection = OperationManagementDAOFactory.getConnection();
|
||||
stmt = connection.prepareStatement("SELECT o.ID, o.TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, " +
|
||||
"o.OPERATION_CODE, om.ID AS OM_MAPPING_ID, om.UPDATED_TIMESTAMP FROM DM_OPERATION o " +
|
||||
"o.OPERATION_CODE, o.INITIATED_BY, om.ID AS OM_MAPPING_ID, om.UPDATED_TIMESTAMP FROM DM_OPERATION o " +
|
||||
"INNER JOIN (SELECT * FROM DM_ENROLMENT_OP_MAPPING dm " +
|
||||
"WHERE dm.ENROLMENT_ID = ? AND dm.STATUS = ?) om ON o.ID = om.OPERATION_ID " +
|
||||
"ORDER BY om.UPDATED_TIMESTAMP ASC, om.ID ASC LIMIT 1");
|
||||
@ -1616,6 +1620,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
new Timestamp((rs.getLong("UPDATED_TIMESTAMP") * 1000)).toString());
|
||||
}
|
||||
operation.setCode(rs.getString("OPERATION_CODE"));
|
||||
operation.setInitiatedBy(rs.getString("INITIATED_BY"));
|
||||
operation.setStatus(Operation.Status.PENDING);
|
||||
OperationDAOUtil.setActivityId(operation, rs.getInt("ID"));
|
||||
}
|
||||
@ -1636,10 +1641,10 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
List<Operation> operations = new ArrayList<>();
|
||||
try {
|
||||
Connection conn = OperationManagementDAOFactory.getConnection();
|
||||
String sql = "SELECT o.ID, TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, OPERATION_CODE, om.ID AS OM_MAPPING_ID, " +
|
||||
"om.UPDATED_TIMESTAMP FROM (SELECT o.ID, TYPE, CREATED_TIMESTAMP, RECEIVED_TIMESTAMP, OPERATION_CODE " +
|
||||
"FROM DM_OPERATION o WHERE o.TYPE = ?) o " +
|
||||
"INNER JOIN (SELECT * FROM DM_ENROLMENT_OP_MAPPING dm " +
|
||||
String sql = "SELECT o.ID, TYPE, o.CREATED_TIMESTAMP, o.RECEIVED_TIMESTAMP, OPERATION_CODE, o.INITIATED_BY," +
|
||||
" om.ID AS OM_MAPPING_ID, om.UPDATED_TIMESTAMP FROM " +
|
||||
"(SELECT o.ID, TYPE, CREATED_TIMESTAMP, RECEIVED_TIMESTAMP, OPERATION_CODE, INITIATED_BY " +
|
||||
"FROM DM_OPERATION o WHERE o.TYPE = ?) o INNER JOIN (SELECT * FROM DM_ENROLMENT_OP_MAPPING dm " +
|
||||
"WHERE dm.ENROLMENT_ID = ? AND dm.STATUS = ?) om ON o.ID = om.OPERATION_ID ORDER BY o.CREATED_TIMESTAMP ASC";
|
||||
|
||||
stmt = conn.prepareStatement(sql);
|
||||
@ -1660,6 +1665,7 @@ public class GenericOperationDAOImpl implements OperationDAO {
|
||||
new Timestamp((rs.getLong("UPDATED_TIMESTAMP") * 1000)).toString());
|
||||
}
|
||||
operation.setCode(rs.getString("OPERATION_CODE"));
|
||||
operation.setInitiatedBy(rs.getString("INITIATED_BY"));
|
||||
OperationDAOUtil.setActivityId(operation, rs.getInt("ID"));
|
||||
operations.add(operation);
|
||||
}
|
||||
|
||||
@ -18,7 +18,14 @@
|
||||
|
||||
package org.wso2.carbon.device.mgt.core.report.mgt;
|
||||
|
||||
import org.wso2.carbon.utils.CarbonUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class Constants {
|
||||
public static final String DEFAULT_CONFIG_FILE_LOCATION = CarbonUtils.getCarbonConfigDirPath() + File.separator +
|
||||
Constants.REPORT_MGT_CONFIG_XML_FILE;
|
||||
public static final String REPORT_MGT_CONFIG_XML_FILE = "reporting-mgt.xml";
|
||||
// device types
|
||||
public static final String ANDROID = "android";
|
||||
public static final String IOS = "ios";
|
||||
@ -29,5 +36,14 @@ public class Constants {
|
||||
// OS version value generating properties
|
||||
public static final int NUM_OF_OS_VERSION_DIGITS= 5;
|
||||
public static final int NUM_OF_OS_VERSION_POSITIONS = 3;
|
||||
public static final String BASIC_AUTH_HEADER_PREFIX = "Basic ";
|
||||
public static final String HTTP_PROTOCOL = "http";
|
||||
public static final String HTTPS_PROTOCOL = "https";
|
||||
public static final String WSS_PROTOCOL = "wss";
|
||||
public static final String WS_PROTOCOL = "ws";
|
||||
public static final String SCHEME_SEPARATOR = "://";
|
||||
public static final String URI_SEPARATOR = "/";
|
||||
public static final String URI_QUERY_SEPARATOR = "?";
|
||||
public static final String COLON = ":";
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (pvt) Ltd. 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.wso2.carbon.device.mgt.core.report.mgt.config;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* Represents the Application Management Configuration.
|
||||
*/
|
||||
@XmlRootElement(name = "ReportManagementConfiguration")
|
||||
public class ReportMgtConfiguration {
|
||||
|
||||
private String datasourceName;
|
||||
|
||||
@XmlElement(name = "DatasourceName", required = true)
|
||||
public String getDatasourceName() {
|
||||
return datasourceName;
|
||||
}
|
||||
|
||||
public void setDatasourceName(String datasourceName) {
|
||||
this.datasourceName = datasourceName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (pvt) Ltd. 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.wso2.carbon.device.mgt.core.report.mgt.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.InvalidConfigurationException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.Constants;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* ConfigurationManager is responsible for the managing Application Management related configurations.
|
||||
*/
|
||||
public class ReportMgtConfigurationManager {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ReportMgtConfigurationManager.class);
|
||||
|
||||
private ReportMgtConfiguration configuration;
|
||||
|
||||
private static String configPath;
|
||||
|
||||
private static volatile ReportMgtConfigurationManager configurationManager;
|
||||
|
||||
private ReportMgtConfigurationManager() {
|
||||
|
||||
}
|
||||
|
||||
public static ReportMgtConfigurationManager getInstance() {
|
||||
if (configurationManager == null) {
|
||||
synchronized (ReportMgtConfigurationManager.class) {
|
||||
if (configurationManager == null) {
|
||||
configurationManager = new ReportMgtConfigurationManager();
|
||||
try {
|
||||
configurationManager.initConfig();
|
||||
} catch (ReportManagementException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return configurationManager;
|
||||
}
|
||||
|
||||
public static synchronized void setConfigLocation(String configPath) throws InvalidConfigurationException {
|
||||
if (ReportMgtConfigurationManager.configPath == null) {
|
||||
ReportMgtConfigurationManager.configPath = configPath;
|
||||
} else {
|
||||
throw new InvalidConfigurationException("Configuration path " + configPath + " is already defined");
|
||||
}
|
||||
}
|
||||
|
||||
private void initConfig() throws ReportManagementException {
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(ReportMgtConfiguration.class);
|
||||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
if (configPath == null) {
|
||||
configPath = Constants.DEFAULT_CONFIG_FILE_LOCATION;
|
||||
}
|
||||
//TODO: Add validation for the configurations
|
||||
this.configuration = (ReportMgtConfiguration) unmarshaller.unmarshal(new File(configPath));
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
throw new InvalidConfigurationException("Error occurred while initializing application config: "
|
||||
+ configPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
public ReportMgtConfiguration getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (pvt) Ltd. 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.wso2.carbon.device.mgt.core.report.mgt.dao.common;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DBConnectionException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.IllegalTransactionStateException;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.config.ReportMgtConfigurationManager;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* This class intends to act as the primary entity that hides all DAO instantiation related complexities and logic so
|
||||
* that the business objection handling layer doesn't need to be aware of the same providing seamless plug-ability of
|
||||
* different data sources, connection acquisition mechanisms as well as different forms of DAO implementations to the
|
||||
* high-level implementations that require Application management related metadata persistence.
|
||||
*/
|
||||
public class ReportMgtConnectionManager {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ReportMgtConnectionManager.class);
|
||||
|
||||
private static final ThreadLocal<Connection> currentConnection = new ThreadLocal<>();
|
||||
private static DataSource dataSource;
|
||||
|
||||
static {
|
||||
String dataSourceName = ReportMgtConfigurationManager.getInstance().getConfiguration().getDatasourceName();
|
||||
init(dataSourceName);
|
||||
}
|
||||
|
||||
public static void init(String datasourceName) {
|
||||
resolveDataSource(datasourceName);
|
||||
}
|
||||
|
||||
public static String getDatabaseType() {
|
||||
try {
|
||||
return dataSource.getConnection().getMetaData().getDatabaseProductName();
|
||||
} catch (SQLException e) {
|
||||
log.error("Error occurred while retrieving config.datasource connection", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the datasource from the datasource definition.
|
||||
*
|
||||
* @param dataSourceName Name of the datasource
|
||||
* @return DataSource resolved by the datasource name
|
||||
*/
|
||||
public static DataSource resolveDataSource(String dataSourceName) {
|
||||
try {
|
||||
dataSource = InitialContext.doLookup(dataSourceName);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error in looking up data source: " + e.getMessage(), e);
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public static void openDBConnection() throws DBConnectionException {
|
||||
Connection conn = currentConnection.get();
|
||||
if (conn != null) {
|
||||
throw new IllegalTransactionStateException("Database connection has already been obtained.");
|
||||
}
|
||||
try {
|
||||
conn = dataSource.getConnection();
|
||||
} catch (SQLException e) {
|
||||
throw new DBConnectionException("Failed to get a database connection.", e);
|
||||
}
|
||||
currentConnection.set(conn);
|
||||
}
|
||||
|
||||
public static Connection getDBConnection() throws DBConnectionException {
|
||||
if (dataSource == null) {
|
||||
String dataSourceName = ReportMgtConfigurationManager.getInstance().getConfiguration().getDatasourceName();
|
||||
init(dataSourceName);
|
||||
}
|
||||
Connection conn = currentConnection.get();
|
||||
if (conn == null) {
|
||||
try {
|
||||
conn = dataSource.getConnection();
|
||||
currentConnection.set(conn);
|
||||
} catch (SQLException e) {
|
||||
throw new DBConnectionException("Failed to get database connection.", e);
|
||||
}
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
||||
public static void closeDBConnection() {
|
||||
Connection conn = currentConnection.get();
|
||||
if (conn == null) {
|
||||
throw new IllegalTransactionStateException("Database connection is not active.");
|
||||
}
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
log.error("Error occurred while closing the connection", e);
|
||||
}
|
||||
currentConnection.remove();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -17,6 +17,10 @@
|
||||
|
||||
package org.wso2.carbon.device.mgt.core.util;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
@ -26,11 +30,21 @@ import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.EventPublishingException;
|
||||
import org.wso2.carbon.device.mgt.core.DeviceManagementConstants;
|
||||
import org.wso2.carbon.device.mgt.core.report.mgt.Constants;
|
||||
|
||||
import javax.ws.rs.core.PathSegment;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpReportingUtil {
|
||||
|
||||
private static final Log log = LogFactory.getLog(HttpReportingUtil.class);
|
||||
private static final String IS_EVENT_PUBLISHING_ENABLED = "isEventPublishingEnabled";
|
||||
|
||||
public static String getReportingHost() {
|
||||
@ -51,6 +65,115 @@ public class HttpReportingUtil {
|
||||
"invoking API. API endpoint: " + endpoint, e);
|
||||
}
|
||||
}
|
||||
public static String getRequestSubPathFromEnd(URI requestUri, int position) {
|
||||
String[] pathList = requestUri.getPath().split("/");
|
||||
if (pathList.length - 1 >= position) {
|
||||
return pathList[pathList.length - 1 - position];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getRequestSubPath(String fullPath, int position) {
|
||||
String[] pathList = fullPath.split("/");
|
||||
if (pathList.length - 1 > position) {
|
||||
String path = pathList[position + 1];
|
||||
if(path.contains(Constants.URI_QUERY_SEPARATOR)) {
|
||||
path = path.substring(0, path.indexOf(Constants.URI_QUERY_SEPARATOR));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getResponseString(HttpResponse response) throws IOException {
|
||||
try (BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String line;
|
||||
while ((line = rd.readLine()) != null) {
|
||||
result.append(line);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
public static boolean isQueryParamExist(String param, URI request) {
|
||||
Map<String, List<String>> queryMap = getQueryMap(request);
|
||||
return queryMap.containsKey(param);
|
||||
}
|
||||
public static String getFirstQueryValue(String param, Map<String, List<String>> queryMap) {
|
||||
List<String> valueList = queryMap.get(param);
|
||||
String firstValue = null;
|
||||
if(valueList != null) {
|
||||
firstValue = valueList.get(0);
|
||||
}
|
||||
return firstValue;
|
||||
}
|
||||
public static Map<String, List<String>> getQueryMap(String uri) {
|
||||
String query = getQueryFromURIPath(uri);
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
if (query != null) {
|
||||
String[] params = query.split("&");
|
||||
for (String param : params) {
|
||||
String[] paramArr = param.split("=");
|
||||
if (paramArr.length == 2) {
|
||||
String name = paramArr[0];
|
||||
String value = paramArr[1];
|
||||
if (!map.containsKey(name)) {
|
||||
List<String> valueList = new ArrayList<>();
|
||||
map.put(name, valueList);
|
||||
}
|
||||
map.get(name).add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
public static Map<String, List<String>> getQueryMap(URI request) {
|
||||
String query = request.getQuery();
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
if (query != null) {
|
||||
String[] params = query.split("&");
|
||||
for (String param : params) {
|
||||
String[] paramArr = param.split("=");
|
||||
if (paramArr.length == 2) {
|
||||
String name = paramArr[0];
|
||||
String value = paramArr[1];
|
||||
if (!map.containsKey(name)) {
|
||||
List<String> valueList = new ArrayList<>();
|
||||
map.put(name, valueList);
|
||||
}
|
||||
map.get(name).add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
public static String getQueryFromURIPath(String uri) {
|
||||
String query = null;
|
||||
if (uri.length() > "?".length() && uri.contains("?")) {
|
||||
query = uri.substring(uri.lastIndexOf("?") + "?".length());
|
||||
}
|
||||
if (StringUtils.isEmpty(query)) {
|
||||
query = null;
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
public static String getMemeType(HttpResponse response) {
|
||||
String memeType = "";
|
||||
Header contentType = response.getEntity().getContentType();
|
||||
if (contentType != null) {
|
||||
memeType = contentType.getValue().split(";")[0].trim();
|
||||
}
|
||||
return memeType;
|
||||
}
|
||||
public static String getGrafanaBaseUrl(String scheme) {
|
||||
String host = "localhost";
|
||||
String port = "3000";
|
||||
if (scheme.equals(Constants.HTTP_PROTOCOL)) {
|
||||
port = "3000";
|
||||
}
|
||||
return host + Constants.COLON + port;
|
||||
}
|
||||
|
||||
public static boolean isPublishingEnabledForTenant() {
|
||||
Object configuration = DeviceManagerUtil.getConfiguration(IS_EVENT_PUBLISHING_ENABLED);
|
||||
|
||||
@ -140,6 +140,7 @@ public class DefaultTokenHandler extends HttpServlet {
|
||||
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setCode(HttpStatus.SC_OK);
|
||||
proxyResponse.setStatus(ProxyResponse.Status.SUCCESS);
|
||||
proxyResponse.setData(payload);
|
||||
return proxyResponse;
|
||||
}
|
||||
|
||||
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||
*
|
||||
* Entgra (Pvt) Ltd. 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 io.entgra.ui.request.interceptor;
|
||||
|
||||
import io.entgra.ui.request.interceptor.beans.AuthData;
|
||||
import io.entgra.ui.request.interceptor.beans.ProxyResponse;
|
||||
import io.entgra.ui.request.interceptor.util.GrafanaHandlerUtil;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerConstants;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerUtil;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.common.util.HttpUtil;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.GrafanaEnvVariablesNotDefined;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaUtil;
|
||||
import javax.servlet.annotation.MultipartConfig;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.ws.rs.ProcessingException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
|
||||
@MultipartConfig
|
||||
@WebServlet(
|
||||
name = "GrafanaRequestHandler",
|
||||
description = "This servlet intercepts the iframe requests initiated from the user interface and validate before" +
|
||||
" forwarding to the backend",
|
||||
urlPatterns = {
|
||||
"/grafana/*"
|
||||
}
|
||||
)
|
||||
public class GrafanaHandler extends HttpServlet {
|
||||
private static final Log log = LogFactory.getLog(GrafanaHandler.class);
|
||||
private static final long serialVersionUID = -6508020875358160165L;
|
||||
private static AuthData authData;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpGet grafanaRequest = new HttpGet();
|
||||
HandlerUtil.copyRequestHeaders(req, grafanaRequest, true);
|
||||
if (!GrafanaUtil.isGrafanaAPI(req.getRequestURI())) {
|
||||
proxyPassGrafanaRequest(grafanaRequest, resp, req);
|
||||
return;
|
||||
}
|
||||
grafanaRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse grafanaAPIResponse = executeGrafanaAPIRequest(grafanaRequest, req);
|
||||
String keyManagerUrl = HandlerUtil.getKeyManagerUrl(req.getScheme());
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(grafanaAPIResponse.getExecutorResponse())) {
|
||||
grafanaAPIResponse = HandlerUtil.retryRequestWithRefreshedToken(req, grafanaRequest, keyManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(grafanaAPIResponse)) {
|
||||
HandlerUtil.handleError(resp, grafanaAPIResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (grafanaAPIResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
if (grafanaAPIResponse.getCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
grafanaAPIResponse = HandlerUtil.retryRequestWithRefreshedToken(req, grafanaRequest, keyManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(grafanaAPIResponse)) {
|
||||
HandlerUtil.handleError(resp, grafanaAPIResponse);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
log.error("Error occurred while invoking the GET API endpoint.");
|
||||
HandlerUtil.handleError(resp, grafanaAPIResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
handleSuccess(resp, grafanaAPIResponse);
|
||||
}
|
||||
} catch (ProcessingException e) {
|
||||
String msg = "Grafana server is down or invalid grafana dashboard url provided";
|
||||
log.error(msg, e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Error occurred when processing Iframe request.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpPost grafanaRequest = new HttpPost();
|
||||
HandlerUtil.generateRequestEntity(req, grafanaRequest);
|
||||
HandlerUtil.copyRequestHeaders(req, grafanaRequest, true);
|
||||
if (!GrafanaUtil.isGrafanaAPI(req.getRequestURI())) {
|
||||
proxyPassGrafanaRequest(grafanaRequest, resp, req);
|
||||
return;
|
||||
}
|
||||
grafanaRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse grafanaAPIResponse = executeGrafanaAPIRequest(grafanaRequest, req);
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(grafanaAPIResponse.getExecutorResponse())) {
|
||||
String keyManagerUrl = HandlerUtil.getKeyManagerUrl(req.getScheme());
|
||||
grafanaAPIResponse = HandlerUtil.retryRequestWithRefreshedToken(req, grafanaRequest, keyManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(grafanaAPIResponse)) {
|
||||
handleError(resp, grafanaAPIResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (grafanaAPIResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while invoking the POST API endpoint.");
|
||||
handleError(resp, grafanaAPIResponse);
|
||||
return;
|
||||
}
|
||||
handleSuccess(resp, grafanaAPIResponse);
|
||||
}
|
||||
} catch (FileUploadException e) {
|
||||
log.error("Error occurred when processing Multipart POST request.", e);
|
||||
} catch (ProcessingException e) {
|
||||
String msg = "Grafana server is down or invalid grafana dashboard url provided";
|
||||
log.error(msg, e);
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred when processing Iframe request.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSuccess(HttpServletResponse resp, ProxyResponse grafanaAPIResponse) throws IOException{
|
||||
String contentType = HandlerUtil.getHeaderValue(HttpHeaders.CONTENT_TYPE, grafanaAPIResponse.getHeaders());
|
||||
resp.setContentType(contentType);
|
||||
resp.setStatus(grafanaAPIResponse.getCode());
|
||||
addXFrameOptionsHeaders(resp);
|
||||
resp.getWriter().print(grafanaAPIResponse.getData());
|
||||
}
|
||||
|
||||
private void handleError(HttpServletResponse resp, int errCode, String errMsg) throws IOException {
|
||||
resp.sendError(errCode, errMsg);
|
||||
}
|
||||
|
||||
private void handleError(HttpServletResponse resp, ProxyResponse proxyResponse) throws IOException {
|
||||
resp.sendError(proxyResponse.getCode());
|
||||
}
|
||||
|
||||
/***
|
||||
* Validates the incoming request.
|
||||
*
|
||||
* @param req {@link HttpServletRequest}
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @return If request is a valid one, returns TRUE, otherwise return FALSE
|
||||
* @throws IOException If and error occurs while witting error response to client side
|
||||
*/
|
||||
private boolean validateRequest(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException {
|
||||
|
||||
if (req.getMethod() == null) {
|
||||
String errMsg = "Bad Request, Request method is empty";
|
||||
log.error(errMsg);
|
||||
handleError(resp, HttpStatus.SC_BAD_REQUEST, errMsg);
|
||||
return false;
|
||||
}
|
||||
if (HandlerUtil.isPropertyDefined(HandlerConstants.IOT_REPORTING_WEBAPP_HOST_ENV_VAR)) {
|
||||
String errMsg = "Reporting Endpoint is not defined in the iot-server.sh properly.";
|
||||
log.error(errMsg);
|
||||
resp.sendError(500, errMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
String errMsg = "Unauthorized, You are not logged in. Please log in to the portal";
|
||||
log.error(errMsg);
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED, errMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
authData = (AuthData) session.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY);
|
||||
if (authData == null) {
|
||||
String errMsg = "Unauthorized, Access token not found in the current session";
|
||||
log.error(errMsg);
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED, errMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private ProxyResponse executeGrafanaAPIRequest(HttpRequestBase requestBase, HttpServletRequest request)
|
||||
throws IOException {
|
||||
URI grafanaUri = HttpUtil.createURI(generateGrafanaAPIUrl(request));
|
||||
requestBase.setURI(grafanaUri);
|
||||
return HandlerUtil.execute(requestBase);
|
||||
}
|
||||
|
||||
private String generateGrafanaAPIUrl(HttpServletRequest request) {
|
||||
String apiBase = generateGrafanaAPIBase(request);
|
||||
String grafanaUri = getURIWithQuery(request);
|
||||
return apiBase + grafanaUri;
|
||||
}
|
||||
|
||||
private String generateGrafanaAPIBase(HttpServletRequest request) {
|
||||
return HandlerUtil.getIOTGatewayBase(request) + HandlerConstants.GRAFANA_API;
|
||||
}
|
||||
|
||||
private String getURIWithQuery(HttpServletRequest request) {
|
||||
String uri = request.getPathInfo();
|
||||
if (request.getQueryString() != null) {
|
||||
uri += HandlerConstants.URI_QUERY_SEPARATOR + request.getQueryString();
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
private void proxyPassGrafanaRequest(HttpRequestBase requestBase, HttpServletResponse response,
|
||||
HttpServletRequest request) throws IOException {
|
||||
try (CloseableHttpClient client = HandlerUtil.getHttpClient()) {
|
||||
String grafanaUriStr = GrafanaHandlerUtil.generateGrafanaUrl(HttpUtil.createURI(getURIWithQuery(request)),
|
||||
GrafanaUtil.getGrafanaHTTPBase(request.getScheme()));
|
||||
URI grafanaURI = HttpUtil.createURI(grafanaUriStr);
|
||||
requestBase.setURI(grafanaURI);
|
||||
HttpResponse grafanaResponse = invokeGrafanaAPI(client, requestBase);
|
||||
forwardGrafanaResponse(grafanaResponse, response);
|
||||
} catch (GrafanaEnvVariablesNotDefined e) {
|
||||
handleError(response, HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage());
|
||||
} catch (GrafanaManagementException e) {
|
||||
String errMsg = "Error occurred while retrieving grafana user credentials";
|
||||
log.error(errMsg, e);
|
||||
handleError(response, HttpStatus.SC_INTERNAL_SERVER_ERROR, errMsg);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpResponse invokeGrafanaAPI(HttpClient client, HttpRequestBase request) throws IOException, GrafanaManagementException {
|
||||
setBasicAuthHeader(request);
|
||||
return client.execute(request);
|
||||
}
|
||||
|
||||
private void setBasicAuthHeader(HttpRequestBase request) throws GrafanaManagementException {
|
||||
String basicAuth = GrafanaUtil.getBasicAuthBase64Header();
|
||||
request.setHeader(HttpHeaders.AUTHORIZATION, basicAuth);
|
||||
}
|
||||
|
||||
private void forwardGrafanaResponse(HttpResponse grafanaResponse, HttpServletResponse response) throws IOException {
|
||||
InputStream responseContent = grafanaResponse.getEntity().getContent();
|
||||
String grafanaContentType = HandlerUtil.getMemeType(grafanaResponse);
|
||||
response.setHeader(HttpHeaders.CONTENT_TYPE, grafanaContentType);
|
||||
addXFrameOptionsHeaders(response);
|
||||
byte[] buffer = new byte[10240];
|
||||
try (InputStream input = responseContent; OutputStream output = response.getOutputStream()) {
|
||||
for (int length = 0; (length = input.read(buffer)) > 0;) {
|
||||
output.write(buffer, 0, length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addXFrameOptionsHeaders(HttpServletResponse response) {
|
||||
response.setHeader(HandlerConstants.X_FRAME_OPTIONS, HandlerConstants.X_FRAME_OPTIONS_SAMEORIGIN);
|
||||
}
|
||||
|
||||
}
|
||||
@ -18,37 +18,21 @@
|
||||
|
||||
package io.entgra.ui.request.interceptor;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.entgra.ui.request.interceptor.beans.AuthData;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerConstants;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerUtil;
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpHead;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.cookie.SM;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.entity.mime.content.InputStreamBody;
|
||||
import io.entgra.ui.request.interceptor.beans.ProxyResponse;
|
||||
|
||||
import javax.servlet.annotation.MultipartConfig;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
@ -56,8 +40,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
@MultipartConfig
|
||||
@WebServlet(
|
||||
@ -79,14 +61,15 @@ public class InvokerHandler extends HttpServlet {
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpPost postRequest = new HttpPost(generateBackendRequestURL(req));
|
||||
generateRequestEntity(req, postRequest);
|
||||
HttpPost postRequest = new HttpPost(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
HandlerUtil.generateRequestEntity(req, postRequest);
|
||||
postRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(postRequest);
|
||||
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, postRequest, kmManagerUrl);
|
||||
if (proxyResponse == null) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, postRequest, kmManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(proxyResponse)) {
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -108,19 +91,24 @@ public class InvokerHandler extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpGet getRequest = new HttpGet(generateBackendRequestURL(req));
|
||||
copyRequestHeaders(req, getRequest, false);
|
||||
HttpGet getRequest = new HttpGet(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
HandlerUtil.copyRequestHeaders(req, getRequest, false);
|
||||
getRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(getRequest);
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, getRequest, kmManagerUrl);
|
||||
if (proxyResponse == null) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, getRequest, kmManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(proxyResponse)) {
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
if (proxyResponse.getCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, getRequest, kmManagerUrl);
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, getRequest, kmManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(proxyResponse)) {
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
log.error("Error occurred while invoking the GET API endpoint.");
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
@ -138,13 +126,14 @@ public class InvokerHandler extends HttpServlet {
|
||||
protected void doHead(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpHead headRequest = new HttpHead(generateBackendRequestURL(req));
|
||||
copyRequestHeaders(req, headRequest, false);
|
||||
HttpHead headRequest = new HttpHead(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
HandlerUtil.copyRequestHeaders(req, headRequest, false);
|
||||
headRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(headRequest);
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, headRequest, kmManagerUrl);
|
||||
if (proxyResponse == null) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, headRequest, kmManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(proxyResponse)) {
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -164,14 +153,15 @@ public class InvokerHandler extends HttpServlet {
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpPut putRequest = new HttpPut(generateBackendRequestURL(req));
|
||||
generateRequestEntity(req, putRequest);
|
||||
HttpPut putRequest = new HttpPut(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
HandlerUtil.generateRequestEntity(req, putRequest);
|
||||
putRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(putRequest);
|
||||
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, putRequest, kmManagerUrl);
|
||||
if (proxyResponse == null) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, putRequest, kmManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(proxyResponse)) {
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -193,13 +183,14 @@ public class InvokerHandler extends HttpServlet {
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpDelete deleteRequest = new HttpDelete(generateBackendRequestURL(req));
|
||||
copyRequestHeaders(req, deleteRequest, false);
|
||||
HttpDelete deleteRequest = new HttpDelete(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
HandlerUtil.copyRequestHeaders(req, deleteRequest, false);
|
||||
deleteRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(deleteRequest);
|
||||
if (HandlerConstants.TOKEN_IS_EXPIRED.equals(proxyResponse.getExecutorResponse())) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, resp, deleteRequest, kmManagerUrl);
|
||||
if (proxyResponse == null) {
|
||||
proxyResponse = HandlerUtil.retryRequestWithRefreshedToken(req, deleteRequest, kmManagerUrl);
|
||||
if (!HandlerUtil.isResponseSuccessful(proxyResponse)) {
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -215,83 +206,6 @@ public class InvokerHandler extends HttpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate te request entity for POST and PUT requests from the incoming request.
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}.
|
||||
* @param proxyRequest proxy request instance.
|
||||
* @throws FileUploadException If unable to parse the incoming request for multipart content extraction.
|
||||
* @throws IOException If error occurred while generating the request body.
|
||||
*/
|
||||
private void generateRequestEntity(HttpServletRequest req, HttpEntityEnclosingRequestBase proxyRequest)
|
||||
throws FileUploadException, IOException {
|
||||
if (ServletFileUpload.isMultipartContent(req)) {
|
||||
ServletFileUpload servletFileUpload = new ServletFileUpload(new DiskFileItemFactory());
|
||||
List<FileItem> fileItemList = servletFileUpload.parseRequest(req);
|
||||
MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
|
||||
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
|
||||
for (FileItem item: fileItemList) {
|
||||
if (!item.isFormField()) {
|
||||
entityBuilder.addPart(item.getFieldName(), new InputStreamBody(item.getInputStream(),
|
||||
ContentType.create(item.getContentType()), item.getName()));
|
||||
} else {
|
||||
entityBuilder.addTextBody(item.getFieldName(), item.getString());
|
||||
}
|
||||
}
|
||||
proxyRequest.setEntity(entityBuilder.build());
|
||||
copyRequestHeaders(req, proxyRequest, false);
|
||||
} else {
|
||||
if (StringUtils.isNotEmpty(req.getHeader(HttpHeaders.CONTENT_LENGTH)) ||
|
||||
StringUtils.isNotEmpty(req.getHeader(HttpHeaders.TRANSFER_ENCODING))) {
|
||||
InputStreamEntity entity = new InputStreamEntity(req.getInputStream(),
|
||||
Long.parseLong(req.getHeader(HttpHeaders.CONTENT_LENGTH)));
|
||||
proxyRequest.setEntity(entity);
|
||||
}
|
||||
copyRequestHeaders(req, proxyRequest, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the target URL for the proxy request.
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @return Target URL
|
||||
*/
|
||||
private String generateBackendRequestURL(HttpServletRequest req) {
|
||||
StringBuilder urlBuilder = new StringBuilder();
|
||||
urlBuilder.append(apiEndpoint).append(HandlerConstants.API_COMMON_CONTEXT)
|
||||
.append(req.getPathInfo().replace(" ", "%20"));
|
||||
if (StringUtils.isNotEmpty(req.getQueryString())) {
|
||||
urlBuilder.append("?").append(req.getQueryString());
|
||||
}
|
||||
return urlBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy incoming request headers to the proxy request.
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param httpRequest proxy request instance.
|
||||
* @param preserveContentType <code>true</code> if content type header needs to be preserved.
|
||||
* This should be set to <code>false</code> when handling multipart requests as Http
|
||||
* client will generate the Content-Type header automatically.
|
||||
*/
|
||||
private void copyRequestHeaders(HttpServletRequest req, HttpRequestBase httpRequest, boolean preserveContentType) {
|
||||
Enumeration<String> headerNames = req.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH) ||
|
||||
headerName.equalsIgnoreCase(SM.COOKIE) ||
|
||||
(!preserveContentType && headerName.equalsIgnoreCase(HttpHeaders.CONTENT_TYPE))) {
|
||||
continue;
|
||||
}
|
||||
Enumeration<String> headerValues = req.getHeaders(headerName);
|
||||
while (headerValues.hasMoreElements()) {
|
||||
httpRequest.setHeader(headerName, headerValues.nextElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Validates the incoming request.
|
||||
*
|
||||
@ -305,8 +219,7 @@ public class InvokerHandler extends HttpServlet {
|
||||
apiEndpoint = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_GW_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getGatewayPort(req.getScheme());
|
||||
|
||||
kmManagerUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeymanagerPort(req.getScheme());
|
||||
kmManagerUrl = HandlerUtil.getKeyManagerUrl(req.getScheme());
|
||||
|
||||
if (HandlerConstants.REPORTS.equalsIgnoreCase(req.getHeader(HandlerConstants.APP_NAME))){
|
||||
apiEndpoint = System.getProperty("iot.reporting.webapp.host");
|
||||
@ -339,107 +252,4 @@ public class InvokerHandler extends HttpServlet {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry request again after refreshing the access token
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param resp resp {@link HttpServletResponse}
|
||||
* @param httpRequest subclass of {@link HttpRequestBase} related to the current request.
|
||||
* @return {@link ProxyResponse} if successful and <code>null</code> if failed.
|
||||
* @throws IOException If an error occurs when try to retry the request.
|
||||
*/
|
||||
private ProxyResponse retryRequestWithRefreshedToken(HttpServletRequest req, HttpServletResponse resp,
|
||||
HttpRequestBase httpRequest) throws IOException {
|
||||
if (refreshToken(req, resp)) {
|
||||
httpRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(httpRequest);
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while invoking the API after refreshing the token.");
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return null;
|
||||
}
|
||||
return proxyResponse;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* This method is responsible to get the refresh token
|
||||
*
|
||||
* @param req {@link HttpServletRequest}
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @return If successfully renew tokens, returns TRUE otherwise return FALSE
|
||||
* @throws IOException If an error occurs while witting error response to client side or invoke token renewal API
|
||||
*/
|
||||
private static boolean refreshToken(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("refreshing the token");
|
||||
}
|
||||
|
||||
HttpPost tokenEndpoint = new HttpPost(
|
||||
kmManagerUrl + HandlerConstants.TOKEN_ENDPOINT);
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
log.error("Couldn't find a session, hence it is required to login and proceed.");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return false;
|
||||
}
|
||||
|
||||
StringEntity tokenEndpointPayload = new StringEntity(
|
||||
"grant_type=refresh_token&refresh_token=" + authData.getRefreshToken() + "&scope=PRODUCTION",
|
||||
ContentType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
tokenEndpoint.setEntity(tokenEndpointPayload);
|
||||
String encodedClientApp = authData.getEncodedClientApp();
|
||||
tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC +
|
||||
encodedClientApp);
|
||||
tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
|
||||
|
||||
ProxyResponse tokenResultResponse = HandlerUtil.execute(tokenEndpoint);
|
||||
if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while refreshing access token.");
|
||||
HandlerUtil.handleError(resp, tokenResultResponse);
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonParser jsonParser = new JsonParser();
|
||||
JsonElement jTokenResult = jsonParser.parse(tokenResultResponse.getData());
|
||||
|
||||
if (jTokenResult.isJsonObject()) {
|
||||
JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
|
||||
AuthData newAuthData = new AuthData();
|
||||
|
||||
newAuthData.setAccessToken(jTokenResultAsJsonObject.get("access_token").getAsString());
|
||||
newAuthData.setRefreshToken(jTokenResultAsJsonObject.get("refresh_token").getAsString());
|
||||
newAuthData.setScope(jTokenResultAsJsonObject.get("scope").getAsString());
|
||||
newAuthData.setClientId(authData.getClientId());
|
||||
newAuthData.setClientSecret(authData.getClientSecret());
|
||||
newAuthData.setEncodedClientApp(authData.getEncodedClientApp());
|
||||
newAuthData.setUsername(authData.getUsername());
|
||||
authData = newAuthData;
|
||||
session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, newAuthData);
|
||||
return true;
|
||||
}
|
||||
|
||||
log.error("Error Occurred in token renewal process.");
|
||||
handleError(resp, HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle error requests
|
||||
*
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @param errorCode HTTP error status code
|
||||
* @throws IOException If error occurred when trying to send the error response.
|
||||
*/
|
||||
private static void handleError(HttpServletResponse resp, int errorCode)
|
||||
throws IOException {
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setCode(errorCode);
|
||||
proxyResponse.setExecutorResponse(
|
||||
HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(errorCode));
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +123,7 @@ public class LoginHandler extends HttpServlet {
|
||||
|
||||
if (getTokenAndPersistInSession(req, resp, clientId, clientSecret, encodedClientApp, scopes)) {
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setStatus(ProxyResponse.Status.SUCCESS);
|
||||
proxyResponse.setCode(HttpStatus.SC_OK);
|
||||
HandlerUtil.handleSuccess(resp, proxyResponse);
|
||||
return;
|
||||
@ -210,7 +211,7 @@ public class LoginHandler extends HttpServlet {
|
||||
+ HandlerConstants.COLON + HandlerUtil.getCorePort(req.getScheme());
|
||||
uiConfigUrl = iotCoreUrl + HandlerConstants.UI_CONFIG_ENDPOINT;
|
||||
kmManagerUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeymanagerPort(req.getScheme());
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeyManagerPort(req.getScheme());
|
||||
|
||||
if (username == null || password == null) {
|
||||
String msg = "Invalid login request. Username or Password is not received for login request.";
|
||||
|
||||
@ -45,6 +45,7 @@ public class LogoutHandler extends HttpServlet {
|
||||
}
|
||||
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setStatus(ProxyResponse.Status.SUCCESS);
|
||||
proxyResponse.setCode(HttpStatus.SC_OK);
|
||||
try {
|
||||
HandlerUtil.handleSuccess(resp, proxyResponse);
|
||||
|
||||
@ -20,37 +20,22 @@ package io.entgra.ui.request.interceptor;
|
||||
|
||||
import io.entgra.ui.request.interceptor.util.HandlerConstants;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerUtil;
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpHead;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.cookie.SM;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.entity.mime.content.InputStreamBody;
|
||||
import io.entgra.ui.request.interceptor.beans.ProxyResponse;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
@WebServlet(
|
||||
name = "OTPRequestHandlerServlet",
|
||||
@ -70,7 +55,7 @@ public class OTPInvokerHandler extends HttpServlet {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpPost postRequest = new HttpPost(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
generateRequestEntity(req, postRequest);
|
||||
HandlerUtil.generateRequestEntity(req, postRequest);
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(postRequest);
|
||||
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
@ -92,7 +77,7 @@ public class OTPInvokerHandler extends HttpServlet {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpGet getRequest = new HttpGet(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
copyRequestHeaders(req, getRequest, false);
|
||||
HandlerUtil.copyRequestHeaders(req, getRequest, false);
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(getRequest);
|
||||
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
@ -112,7 +97,7 @@ public class OTPInvokerHandler extends HttpServlet {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpHead headRequest = new HttpHead(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
copyRequestHeaders(req, headRequest, false);
|
||||
HandlerUtil.copyRequestHeaders(req, headRequest, false);
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(headRequest);
|
||||
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
@ -132,7 +117,7 @@ public class OTPInvokerHandler extends HttpServlet {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpPut putRequest = new HttpPut(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
generateRequestEntity(req, putRequest);
|
||||
HandlerUtil.generateRequestEntity(req, putRequest);
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(putRequest);
|
||||
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
@ -154,7 +139,7 @@ public class OTPInvokerHandler extends HttpServlet {
|
||||
try {
|
||||
if (validateRequest(req, resp)) {
|
||||
HttpDelete deleteRequest = new HttpDelete(HandlerUtil.generateBackendRequestURL(req, apiEndpoint));
|
||||
copyRequestHeaders(req, deleteRequest, false);
|
||||
HandlerUtil.copyRequestHeaders(req, deleteRequest, false);
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(deleteRequest);
|
||||
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
@ -169,67 +154,6 @@ public class OTPInvokerHandler extends HttpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate te request entity for POST and PUT requests from the incoming request.
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}.
|
||||
* @param proxyRequest proxy request instance.
|
||||
* @throws FileUploadException If unable to parse the incoming request for multipart content extraction.
|
||||
* @throws IOException If error occurred while generating the request body.
|
||||
*/
|
||||
private void generateRequestEntity(HttpServletRequest req, HttpEntityEnclosingRequestBase proxyRequest)
|
||||
throws FileUploadException, IOException {
|
||||
if (ServletFileUpload.isMultipartContent(req)) {
|
||||
ServletFileUpload servletFileUpload = new ServletFileUpload(new DiskFileItemFactory());
|
||||
List<FileItem> fileItemList = servletFileUpload.parseRequest(req);
|
||||
MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
|
||||
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
|
||||
for (FileItem item: fileItemList) {
|
||||
if (!item.isFormField()) {
|
||||
entityBuilder.addPart(item.getFieldName(), new InputStreamBody(item.getInputStream(),
|
||||
ContentType.create(item.getContentType()), item.getName()));
|
||||
} else {
|
||||
entityBuilder.addTextBody(item.getFieldName(), item.getString());
|
||||
}
|
||||
}
|
||||
proxyRequest.setEntity(entityBuilder.build());
|
||||
copyRequestHeaders(req, proxyRequest, false);
|
||||
} else {
|
||||
if (StringUtils.isNotEmpty(req.getHeader(HttpHeaders.CONTENT_LENGTH)) ||
|
||||
StringUtils.isNotEmpty(req.getHeader(HttpHeaders.TRANSFER_ENCODING))) {
|
||||
InputStreamEntity entity = new InputStreamEntity(req.getInputStream(),
|
||||
Long.parseLong(req.getHeader(HttpHeaders.CONTENT_LENGTH)));
|
||||
proxyRequest.setEntity(entity);
|
||||
}
|
||||
copyRequestHeaders(req, proxyRequest, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy incoming request headers to the proxy request.
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param httpRequest proxy request instance.
|
||||
* @param preserveContentType <code>true</code> if content type header needs to be preserved.
|
||||
* This should be set to <code>false</code> when handling multipart requests as Http
|
||||
* client will generate the Content-Type header automatically.
|
||||
*/
|
||||
private void copyRequestHeaders(HttpServletRequest req, HttpRequestBase httpRequest, boolean preserveContentType) {
|
||||
Enumeration<String> headerNames = req.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH) ||
|
||||
headerName.equalsIgnoreCase(SM.COOKIE) ||
|
||||
(!preserveContentType && headerName.equalsIgnoreCase(HttpHeaders.CONTENT_TYPE))) {
|
||||
continue;
|
||||
}
|
||||
Enumeration<String> headerValues = req.getHeaders(headerName);
|
||||
while (headerValues.hasMoreElements()) {
|
||||
httpRequest.setHeader(headerName, headerValues.nextElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Validates the incoming request.
|
||||
*
|
||||
@ -246,25 +170,10 @@ public class OTPInvokerHandler extends HttpServlet {
|
||||
|
||||
if (StringUtils.isBlank(req.getHeader(HandlerConstants.OTP_HEADER))) {
|
||||
log.error("Unauthorized, Please provide OTP token.");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
HandlerUtil.handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle error requests
|
||||
*
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @param errorCode HTTP error status code
|
||||
* @throws IOException If error occurred when trying to send the error response.
|
||||
*/
|
||||
private static void handleError(HttpServletResponse resp, int errorCode)
|
||||
throws IOException {
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setCode(errorCode);
|
||||
proxyResponse.setExecutorResponse(
|
||||
HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(errorCode));
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ public class PermissionScopeHandler extends HttpServlet {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put(HandlerConstants.USER_SCOPES, authData.getScope());
|
||||
proxyResponse.setCode(HttpStatus.SC_OK);
|
||||
proxyResponse.setStatus(ProxyResponse.Status.SUCCESS);
|
||||
proxyResponse.setData(jsonObject.toString());
|
||||
HandlerUtil.handleSuccess(resp, proxyResponse);
|
||||
return;
|
||||
|
||||
@ -53,7 +53,7 @@ public class SsoLoginCallbackHandler extends HttpServlet {
|
||||
String iotsCoreUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_CORE_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getCorePort(req.getScheme());
|
||||
String keyManagerUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeymanagerPort(req.getScheme());
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeyManagerPort(req.getScheme());
|
||||
|
||||
if (session == null) {
|
||||
String baseContextPath = req.getContextPath();
|
||||
|
||||
@ -108,7 +108,7 @@ public class SsoLoginHandler extends HttpServlet {
|
||||
apiMgtUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_APIM_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getAPIManagerPort(req.getScheme());
|
||||
keyManagerUrl = req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeymanagerPort(req.getScheme());
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeyManagerPort(req.getScheme());
|
||||
|
||||
// Fetch ui config and persists in session
|
||||
String uiConfigUrl = iotsCoreUrl + HandlerConstants.UI_CONFIG_ENDPOINT;
|
||||
|
||||
@ -45,6 +45,7 @@ public class SsoLogoutHandler extends HttpServlet {
|
||||
}
|
||||
removeCookie(HandlerConstants.COMMON_AUTH_ID_KEY, "/", resp);
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setStatus(ProxyResponse.Status.SUCCESS);
|
||||
proxyResponse.setCode(HttpStatus.SC_OK);
|
||||
|
||||
HttpSession session = req.getSession(false);
|
||||
|
||||
@ -57,7 +57,7 @@ public class UserHandler extends HttpServlet {
|
||||
String keymanagerUrl =
|
||||
req.getScheme() + HandlerConstants.SCHEME_SEPARATOR +
|
||||
System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeymanagerPort(req.getScheme());
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeyManagerPort(req.getScheme());
|
||||
HttpSession httpSession = req.getSession(false);
|
||||
if (httpSession == null) {
|
||||
HandlerUtil.sendUnAuthorizeResponse(resp);
|
||||
@ -86,7 +86,11 @@ public class UserHandler extends HttpServlet {
|
||||
|
||||
if (tokenStatus.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
if (tokenStatus.getCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
tokenStatus = HandlerUtil.retryRequestWithRefreshedToken(req, resp, tokenEndpoint, keymanagerUrl);
|
||||
tokenStatus = HandlerUtil.retryRequestWithRefreshedToken(req, tokenEndpoint, keymanagerUrl);
|
||||
if(!HandlerUtil.isResponseSuccessful(tokenStatus)) {
|
||||
HandlerUtil.handleError(resp, tokenStatus);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
log.error("Error occurred while invoking the API to get token status.");
|
||||
HandlerUtil.handleError(resp, tokenStatus);
|
||||
@ -108,6 +112,7 @@ public class UserHandler extends HttpServlet {
|
||||
return;
|
||||
}
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setStatus(ProxyResponse.Status.SUCCESS);
|
||||
proxyResponse.setCode(HttpStatus.SC_OK);
|
||||
proxyResponse.setData(
|
||||
jTokenResultAsJsonObject.get("username").getAsString().replaceAll("@carbon.super", ""));
|
||||
|
||||
@ -17,11 +17,20 @@
|
||||
*/
|
||||
package io.entgra.ui.request.interceptor.beans;
|
||||
|
||||
import org.apache.http.Header;
|
||||
|
||||
public class ProxyResponse {
|
||||
|
||||
public static class Status {
|
||||
public static int SUCCESS = 1;
|
||||
public static int ERROR = 0;
|
||||
}
|
||||
|
||||
private int code;
|
||||
private String data;
|
||||
private String executorResponse;
|
||||
private int status;
|
||||
private Header[] headers;
|
||||
|
||||
public int getCode() { return code; }
|
||||
|
||||
@ -34,4 +43,21 @@ public class ProxyResponse {
|
||||
public String getExecutorResponse() { return executorResponse; }
|
||||
|
||||
public void setExecutorResponse(String executorResponse) { this.executorResponse = executorResponse; }
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Header[] getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Header[] headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package io.entgra.ui.request.interceptor.util;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class GrafanaHandlerUtil {
|
||||
public static String getGrafanaUri(URI req) {
|
||||
StringBuilder grafanaUriBuilder = new StringBuilder();
|
||||
grafanaUriBuilder.append(req.getPath().replace(" ", "%20"));
|
||||
if (StringUtils.isNotEmpty(req.getQuery())) {
|
||||
grafanaUriBuilder.append("?").append(req.getQuery());
|
||||
}
|
||||
return grafanaUriBuilder.toString();
|
||||
}
|
||||
|
||||
public static String generateGrafanaUrl(URI request, String base) {
|
||||
return base + GrafanaHandlerUtil.getGrafanaUri(request);
|
||||
}
|
||||
}
|
||||
@ -31,6 +31,11 @@ public class HandlerConstants {
|
||||
public static final String SSO_LOGIN_CALLBACK = "/ssoLoginCallback";
|
||||
public static final String BASIC = "Basic ";
|
||||
public static final String BEARER = "Bearer ";
|
||||
public static final String X_FRAME_OPTIONS = "X-Frame-Options";
|
||||
public static final String X_FRAME_OPTIONS_SAMEORIGIN = "SAMEORIGIN";
|
||||
public static final String UPGRADE = "Upgrade";
|
||||
public static final String WEB_SOCKET = "websocket";
|
||||
public static final String HTTP_UPGRADE = "HTTP/1.1";
|
||||
public static final String TAGS_KEY = "tags";
|
||||
public static final String APP_NAME_KEY = "applicationName";
|
||||
public static final String SESSION_AUTH_DATA_KEY = "authInfo";
|
||||
@ -58,10 +63,13 @@ public class HandlerConstants {
|
||||
public static final String LOGIN_CACHE_CAPACITY_KEY = "loginCacheCapacity";
|
||||
|
||||
public static final String SCHEME_SEPARATOR = "://";
|
||||
public static final String URI_SEPARATOR = "/";
|
||||
public static final String QUERY_PARAM_KEY_VALUE_SEP = "=";
|
||||
public static final String COLON = ":";
|
||||
public static final String HTTP_PROTOCOL = "http";
|
||||
public static final String HTTPS_PROTOCOL = "https";
|
||||
public static final String UNDERSCORE = "_";
|
||||
public static final String URI_QUERY_SEPARATOR = "?";
|
||||
|
||||
public static final int INTERNAL_ERROR_CODE = 500;
|
||||
public static final long TIMEOUT = 1200;
|
||||
@ -71,9 +79,12 @@ public class HandlerConstants {
|
||||
public static final String AX_PREFIX = "ax2251:";
|
||||
public static final String PAYLOADS_DIR = "repository/resources/payloads";
|
||||
public static final String SOAP_ACTION_HEADER = "SOAPAction";
|
||||
public static final String REFERER_HEADER = "Referer";
|
||||
|
||||
public static final String WSS_PROTOCOL = "wss";
|
||||
public static final String WS_PROTOCOL = "ws";
|
||||
public static final String REMOTE_SESSION_CONTEXT = "/remote/session/clients";
|
||||
public static final String GRAFANA_API = "/api/device-mgt/v1.0/reports/grafana";
|
||||
|
||||
public static final String IOT_CORE_HOST_ENV_VAR = "iot.core.host";
|
||||
public static final String IOT_CORE_HTTP_PORT_ENV_VAR = "iot.core.http.port";
|
||||
@ -89,5 +100,6 @@ public class HandlerConstants {
|
||||
public static final String IOT_REMOTE_SESSION_HOST_ENV_VAR = "iot.remotesession.server.host";
|
||||
public static final String IOT_REMOTE_SESSION_HTTPS_PORT_ENV_VAR = "iot.remotesession.server.https.port";
|
||||
public static final String IOT_GW_HTTPS_PORT_ENV_VAR = "iot.gateway.https.port";
|
||||
public static final String IOT_REPORTING_WEBAPP_HOST_ENV_VAR = "iot.reporting.webapp.host";
|
||||
public static final String USER_SCOPES = "userScopes";
|
||||
}
|
||||
|
||||
@ -25,19 +25,26 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.entgra.ui.request.interceptor.beans.AuthData;
|
||||
import io.entgra.ui.request.interceptor.cache.LoginCache;
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.*;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.cookie.SM;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.entity.mime.content.InputStreamBody;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.xml.serialize.OutputFormat;
|
||||
@ -46,6 +53,7 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.w3c.dom.Document;
|
||||
import io.entgra.ui.request.interceptor.beans.ProxyResponse;
|
||||
import org.wso2.carbon.device.mgt.core.common.util.HttpUtil;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@ -60,6 +68,8 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
public class HandlerUtil {
|
||||
|
||||
@ -83,54 +93,64 @@ public class HandlerUtil {
|
||||
log.error("Received null response for http request : " + httpRequest.getMethod() + " " + httpRequest
|
||||
.getURI().toString());
|
||||
proxyResponse.setCode(HandlerConstants.INTERNAL_ERROR_CODE);
|
||||
proxyResponse.setStatus(ProxyResponse.Status.ERROR);
|
||||
proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(
|
||||
HandlerConstants.INTERNAL_ERROR_CODE));
|
||||
return proxyResponse;
|
||||
} else {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
try (BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String line;
|
||||
while ((line = rd.readLine()) != null) {
|
||||
result.append(line);
|
||||
}
|
||||
|
||||
String jsonString = result.toString();
|
||||
if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED) {
|
||||
proxyResponse.setCode(statusCode);
|
||||
proxyResponse.setData(jsonString);
|
||||
proxyResponse.setExecutorResponse("SUCCESS");
|
||||
return proxyResponse;
|
||||
} else if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
|
||||
if (jsonString.contains("Access token expired") || jsonString
|
||||
.contains("Invalid input. Access token validation failed")) {
|
||||
proxyResponse.setCode(statusCode);
|
||||
proxyResponse.setExecutorResponse(HandlerConstants.TOKEN_IS_EXPIRED);
|
||||
return proxyResponse;
|
||||
} else {
|
||||
log.error(
|
||||
"Received " + statusCode + " response for http request : " + httpRequest.getMethod()
|
||||
+ " " + httpRequest.getURI().toString() + ". Error message: " + jsonString);
|
||||
proxyResponse.setCode(statusCode);
|
||||
proxyResponse.setData(jsonString);
|
||||
proxyResponse.setExecutorResponse(
|
||||
HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(statusCode));
|
||||
return proxyResponse;
|
||||
}
|
||||
}
|
||||
log.error("Received " + statusCode +
|
||||
" response for http request : " + httpRequest.getMethod() + " " + httpRequest.getURI()
|
||||
.toString() + ". Error message: " + jsonString);
|
||||
String jsonString = getResponseString(response);
|
||||
if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_CREATED) {
|
||||
proxyResponse.setCode(statusCode);
|
||||
proxyResponse.setData(jsonString);
|
||||
proxyResponse
|
||||
.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(statusCode));
|
||||
proxyResponse.setStatus(ProxyResponse.Status.SUCCESS);
|
||||
proxyResponse.setExecutorResponse("SUCCESS");
|
||||
proxyResponse.setHeaders(response.getAllHeaders());
|
||||
return proxyResponse;
|
||||
} else if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
|
||||
if (isTokenExpired(jsonString)) {
|
||||
proxyResponse.setCode(statusCode);
|
||||
proxyResponse.setStatus(ProxyResponse.Status.ERROR);
|
||||
proxyResponse.setExecutorResponse(HandlerConstants.TOKEN_IS_EXPIRED);
|
||||
} else {
|
||||
log.error(
|
||||
"Received " + statusCode + " response for http request : " + httpRequest.getMethod()
|
||||
+ " " + httpRequest.getURI().toString() + ". Error message: " + jsonString);
|
||||
proxyResponse.setCode(statusCode);
|
||||
proxyResponse.setData(jsonString);
|
||||
proxyResponse.setStatus(ProxyResponse.Status.ERROR);
|
||||
proxyResponse.setExecutorResponse(
|
||||
HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(statusCode));
|
||||
}
|
||||
return proxyResponse;
|
||||
}
|
||||
log.error("Received " + statusCode +
|
||||
" response for http request : " + httpRequest.getMethod() + " " + httpRequest.getURI()
|
||||
.toString() + ". Error message: " + jsonString);
|
||||
proxyResponse.setCode(statusCode);
|
||||
proxyResponse.setData(jsonString);
|
||||
proxyResponse.setStatus(ProxyResponse.Status.ERROR);
|
||||
proxyResponse
|
||||
.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + getStatusKey(statusCode));
|
||||
return proxyResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isTokenExpired(String jsonBody) {
|
||||
return jsonBody.contains("Access token expired") || jsonBody
|
||||
.contains("Invalid input. Access token validation failed");
|
||||
}
|
||||
|
||||
public static String getMemeType(HttpResponse response) {
|
||||
String memeType = "";
|
||||
Header contentType = response.getEntity().getContentType();
|
||||
if (contentType != null) {
|
||||
memeType = contentType.getValue().split(";")[0].trim();
|
||||
}
|
||||
return memeType;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* @param statusCode Provide status code, e.g:- 400, 401, 500 etc
|
||||
@ -172,6 +192,7 @@ public class HandlerUtil {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***
|
||||
* Handle error requests.
|
||||
*
|
||||
@ -183,6 +204,7 @@ public class HandlerUtil {
|
||||
Gson gson = new Gson();
|
||||
if (proxyResponse == null) {
|
||||
proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setStatus(ProxyResponse.Status.ERROR);
|
||||
proxyResponse.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
proxyResponse.setExecutorResponse(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil
|
||||
.getStatusKey(HandlerConstants.INTERNAL_ERROR_CODE));
|
||||
@ -200,17 +222,27 @@ public class HandlerUtil {
|
||||
/**
|
||||
* Handle error requests with custom error codes.
|
||||
*
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @param errorCode HTTP error status code
|
||||
* @throws IOException If error occurred when trying to send the error response.
|
||||
*/
|
||||
public static void handleError(HttpServletResponse resp, int errorCode)
|
||||
throws IOException {
|
||||
ProxyResponse proxyResponse = constructProxyResponseByErrorCode(errorCode);
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
}
|
||||
|
||||
public static ProxyResponse constructProxyResponseByErrorCode(int errorCode) {
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setCode(errorCode);
|
||||
proxyResponse.setStatus(ProxyResponse.Status.ERROR);
|
||||
proxyResponse.setExecutorResponse(
|
||||
HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(errorCode));
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return proxyResponse;
|
||||
}
|
||||
|
||||
public static boolean isResponseSuccessful(ProxyResponse response) {
|
||||
return response.getStatus() == ProxyResponse.Status.SUCCESS;
|
||||
}
|
||||
|
||||
/***
|
||||
@ -265,12 +297,17 @@ public class HandlerUtil {
|
||||
* @param scheme https or https
|
||||
* @return {@link String} keymanager port
|
||||
*/
|
||||
public static String getKeymanagerPort(String scheme) {
|
||||
String keymanagerPort = System.getProperty(HandlerConstants.IOT_KM_HTTPS_PORT_ENV_VAR);
|
||||
public static String getKeyManagerPort(String scheme) {
|
||||
String keyManagerPort = System.getProperty(HandlerConstants.IOT_KM_HTTPS_PORT_ENV_VAR);
|
||||
if (HandlerConstants.HTTP_PROTOCOL.equals(scheme)) {
|
||||
keymanagerPort = System.getProperty(HandlerConstants.IOT_KM_HTTP_PORT_ENV_VAR);
|
||||
keyManagerPort = System.getProperty(HandlerConstants.IOT_KM_HTTP_PORT_ENV_VAR);
|
||||
}
|
||||
return keymanagerPort;
|
||||
return keyManagerPort;
|
||||
}
|
||||
|
||||
public static String getKeyManagerUrl(String scheme) {
|
||||
return scheme + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_KM_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getKeyManagerPort(scheme);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -324,6 +361,7 @@ public class HandlerUtil {
|
||||
public static void sendUnAuthorizeResponse(HttpServletResponse resp)
|
||||
throws IOException {
|
||||
ProxyResponse proxyResponse = new ProxyResponse();
|
||||
proxyResponse.setStatus(ProxyResponse.Status.ERROR);
|
||||
proxyResponse.setCode(HttpStatus.SC_UNAUTHORIZED);
|
||||
proxyResponse.setExecutorResponse(
|
||||
HandlerConstants.EXECUTOR_EXCEPTION_PREFIX + HandlerUtil.getStatusKey(HttpStatus.SC_UNAUTHORIZED));
|
||||
@ -333,7 +371,7 @@ public class HandlerUtil {
|
||||
/**
|
||||
* Generates the target URL for the proxy request.
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param apiEndpoint API Endpoint URL
|
||||
* @return Target URL
|
||||
*/
|
||||
@ -347,6 +385,47 @@ public class HandlerUtil {
|
||||
return urlBuilder.toString();
|
||||
}
|
||||
|
||||
public static String getIOTGatewayBase(HttpServletRequest req) {
|
||||
return req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + System.getProperty(HandlerConstants.IOT_GW_HOST_ENV_VAR)
|
||||
+ HandlerConstants.COLON + HandlerUtil.getGatewayPort(req.getScheme());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate te request entity for POST and PUT requests from the incoming request.
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}.
|
||||
* @param proxyRequest proxy request instance.
|
||||
* @throws FileUploadException If unable to parse the incoming request for multipart content extraction.
|
||||
* @throws IOException If error occurred while generating the request body.
|
||||
*/
|
||||
public static void generateRequestEntity(HttpServletRequest req, HttpEntityEnclosingRequestBase proxyRequest)
|
||||
throws FileUploadException, IOException {
|
||||
if (ServletFileUpload.isMultipartContent(req)) {
|
||||
ServletFileUpload servletFileUpload = new ServletFileUpload(new DiskFileItemFactory());
|
||||
List<FileItem> fileItemList = servletFileUpload.parseRequest(req);
|
||||
MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
|
||||
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
|
||||
for (FileItem item : fileItemList) {
|
||||
if (!item.isFormField()) {
|
||||
entityBuilder.addPart(item.getFieldName(), new InputStreamBody(item.getInputStream(),
|
||||
ContentType.create(item.getContentType()), item.getName()));
|
||||
} else {
|
||||
entityBuilder.addTextBody(item.getFieldName(), item.getString());
|
||||
}
|
||||
}
|
||||
proxyRequest.setEntity(entityBuilder.build());
|
||||
HandlerUtil.copyRequestHeaders(req, proxyRequest, false);
|
||||
} else {
|
||||
if (StringUtils.isNotEmpty(req.getHeader(HttpHeaders.CONTENT_LENGTH)) ||
|
||||
StringUtils.isNotEmpty(req.getHeader(HttpHeaders.TRANSFER_ENCODING))) {
|
||||
InputStreamEntity entity = new InputStreamEntity(req.getInputStream(),
|
||||
Long.parseLong(req.getHeader(HttpHeaders.CONTENT_LENGTH)));
|
||||
proxyRequest.setEntity(entity);
|
||||
}
|
||||
HandlerUtil.copyRequestHeaders(req, proxyRequest, true);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Constructs the application registration payload for DCR.
|
||||
*
|
||||
@ -376,7 +455,7 @@ public class HandlerUtil {
|
||||
* @return {@link JsonObject} of UI configurations
|
||||
*/
|
||||
public static JsonObject getUIConfigAndPersistInSession(String uiConfigUrl, String gatewayUrl, HttpSession httpSession,
|
||||
HttpServletResponse resp) throws IOException {
|
||||
HttpServletResponse resp) throws IOException {
|
||||
HttpGet uiConfigEndpoint = new HttpGet(uiConfigUrl);
|
||||
ProxyResponse uiConfigResponse = HandlerUtil.execute(uiConfigEndpoint);
|
||||
String executorResponse = uiConfigResponse.getExecutorResponse();
|
||||
@ -448,7 +527,7 @@ public class HandlerUtil {
|
||||
log.error("Error occurred while sending the response into the socket. ", e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
log.error("Error while creating the document builder.");
|
||||
} catch ( SAXException e) {
|
||||
} catch (SAXException e) {
|
||||
log.error("Error while parsing xml file.", e);
|
||||
}
|
||||
|
||||
@ -496,56 +575,76 @@ public class HandlerUtil {
|
||||
/**
|
||||
* Retry request again after refreshing the access token
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param resp resp {@link HttpServletResponse}
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param httpRequest subclass of {@link HttpRequestBase} related to the current request.
|
||||
* @return {@link ProxyResponse} if successful and <code>null</code> if failed.
|
||||
* @throws IOException If an error occurs when try to retry the request.
|
||||
*/
|
||||
public static ProxyResponse retryRequestWithRefreshedToken(HttpServletRequest req, HttpServletResponse resp,
|
||||
HttpRequestBase httpRequest, String apiEndpoint) throws IOException {
|
||||
if (refreshToken(req, resp, apiEndpoint)) {
|
||||
public static ProxyResponse retryRequestWithRefreshedToken(HttpServletRequest req, HttpRequestBase httpRequest,
|
||||
String apiEndpoint) throws IOException {
|
||||
ProxyResponse retryResponse = refreshToken(req, apiEndpoint);
|
||||
if (isResponseSuccessful(retryResponse)) {
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
log.error("Unauthorized, You are not logged in. Please log in to the portal");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return null;
|
||||
return constructProxyResponseByErrorCode(HttpStatus.SC_UNAUTHORIZED);
|
||||
}
|
||||
httpRequest.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BEARER + authData.getAccessToken());
|
||||
ProxyResponse proxyResponse = HandlerUtil.execute(httpRequest);
|
||||
if (proxyResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while invoking the API after refreshing the token.");
|
||||
HandlerUtil.handleError(resp, proxyResponse);
|
||||
return null;
|
||||
return proxyResponse;
|
||||
}
|
||||
return proxyResponse;
|
||||
|
||||
}
|
||||
return null;
|
||||
return retryResponse;
|
||||
}
|
||||
|
||||
/***
|
||||
* This method is responsible to get the refresh token
|
||||
*
|
||||
* @param req {@link HttpServletRequest}
|
||||
* @param resp {@link HttpServletResponse}
|
||||
* @return If successfully renew tokens, returns TRUE otherwise return FALSE
|
||||
* @throws IOException If an error occurs while witting error response to client side or invoke token renewal API
|
||||
*/
|
||||
private static boolean refreshToken(HttpServletRequest req, HttpServletResponse resp, String keymanagerUrl)
|
||||
private static ProxyResponse refreshToken(HttpServletRequest req, String keymanagerUrl)
|
||||
throws IOException {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("refreshing the token");
|
||||
}
|
||||
|
||||
HttpPost tokenEndpoint = new HttpPost(keymanagerUrl + HandlerConstants.TOKEN_ENDPOINT);
|
||||
ProxyResponse tokenResultResponse;
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
log.error("Couldn't find a session, hence it is required to login and proceed.");
|
||||
handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return false;
|
||||
tokenResultResponse = constructProxyResponseByErrorCode(HttpStatus.SC_UNAUTHORIZED);
|
||||
// handleError(resp, HttpStatus.SC_UNAUTHORIZED);
|
||||
return tokenResultResponse;
|
||||
}
|
||||
|
||||
authData = (AuthData) session.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY);
|
||||
tokenResultResponse = getTokenResult(authData, keymanagerUrl);
|
||||
if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while refreshing access token.");
|
||||
// HandlerUtil.handleError(resp, tokenResultResponse);
|
||||
return tokenResultResponse;
|
||||
}
|
||||
|
||||
JsonParser jsonParser = new JsonParser();
|
||||
JsonElement jTokenResult = jsonParser.parse(tokenResultResponse.getData());
|
||||
|
||||
if (jTokenResult.isJsonObject()) {
|
||||
setNewAuthData(constructAuthDataFromTokenResult(jTokenResult, authData), session);
|
||||
return tokenResultResponse;
|
||||
}
|
||||
|
||||
log.error("Error Occurred in token renewal process.");
|
||||
tokenResultResponse = constructProxyResponseByErrorCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
// handleError(resp, HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
return tokenResultResponse;
|
||||
}
|
||||
public static ProxyResponse getTokenResult(AuthData authData, String keymanagerUrl) throws IOException {
|
||||
HttpPost tokenEndpoint = new HttpPost(keymanagerUrl + HandlerConstants.TOKEN_ENDPOINT);
|
||||
StringEntity tokenEndpointPayload = new StringEntity(
|
||||
"grant_type=refresh_token&refresh_token=" + authData.getRefreshToken() + "&scope=PRODUCTION",
|
||||
ContentType.APPLICATION_FORM_URLENCODED);
|
||||
@ -555,35 +654,75 @@ public class HandlerUtil {
|
||||
tokenEndpoint.setHeader(HttpHeaders.AUTHORIZATION, HandlerConstants.BASIC +
|
||||
encodedClientApp);
|
||||
tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
|
||||
return HandlerUtil.execute(tokenEndpoint);
|
||||
}
|
||||
|
||||
ProxyResponse tokenResultResponse = HandlerUtil.execute(tokenEndpoint);
|
||||
if (tokenResultResponse.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
|
||||
log.error("Error occurred while refreshing access token.");
|
||||
HandlerUtil.handleError(resp, tokenResultResponse);
|
||||
return false;
|
||||
public static void setNewAuthData(AuthData newAuthData, HttpSession session) {
|
||||
authData = newAuthData;
|
||||
session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, newAuthData);
|
||||
}
|
||||
|
||||
public static AuthData constructAuthDataFromTokenResult(JsonElement tokenResult, AuthData authData) {
|
||||
JsonObject jTokenResultAsJsonObject = tokenResult.getAsJsonObject();
|
||||
AuthData newAuthData = new AuthData();
|
||||
newAuthData.setAccessToken(jTokenResultAsJsonObject.get("access_token").getAsString());
|
||||
newAuthData.setRefreshToken(jTokenResultAsJsonObject.get("refresh_token").getAsString());
|
||||
newAuthData.setScope(jTokenResultAsJsonObject.get("scope").getAsString());
|
||||
newAuthData.setClientId(authData.getClientId());
|
||||
newAuthData.setClientSecret(authData.getClientSecret());
|
||||
newAuthData.setEncodedClientApp(authData.getEncodedClientApp());
|
||||
newAuthData.setUsername(authData.getUsername());
|
||||
return newAuthData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy incoming request headers to the proxy request.
|
||||
*
|
||||
* @param req incoming {@link HttpServletRequest}
|
||||
* @param httpRequest proxy request instance.
|
||||
* @param preserveContentType <code>true</code> if content type header needs to be preserved.
|
||||
* This should be set to <code>false</code> when handling multipart requests as Http
|
||||
* client will generate the Content-Type header automatically.
|
||||
*/
|
||||
public static void copyRequestHeaders(HttpServletRequest req, HttpRequestBase httpRequest, boolean preserveContentType) {
|
||||
Enumeration<String> headerNames = req.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH) ||
|
||||
headerName.equalsIgnoreCase(SM.COOKIE) ||
|
||||
(!preserveContentType && headerName.equalsIgnoreCase(HttpHeaders.CONTENT_TYPE))) {
|
||||
continue;
|
||||
}
|
||||
Enumeration<String> headerValues = req.getHeaders(headerName);
|
||||
while (headerValues.hasMoreElements()) {
|
||||
httpRequest.setHeader(headerName, headerValues.nextElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JsonParser jsonParser = new JsonParser();
|
||||
JsonElement jTokenResult = jsonParser.parse(tokenResultResponse.getData());
|
||||
|
||||
if (jTokenResult.isJsonObject()) {
|
||||
JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
|
||||
AuthData newAuthData = new AuthData();
|
||||
|
||||
newAuthData.setAccessToken(jTokenResultAsJsonObject.get("access_token").getAsString());
|
||||
newAuthData.setRefreshToken(jTokenResultAsJsonObject.get("refresh_token").getAsString());
|
||||
newAuthData.setScope(jTokenResultAsJsonObject.get("scope").getAsString());
|
||||
newAuthData.setClientId(authData.getClientId());
|
||||
newAuthData.setClientSecret(authData.getClientSecret());
|
||||
newAuthData.setEncodedClientApp(authData.getEncodedClientApp());
|
||||
newAuthData.setUsername(authData.getUsername());
|
||||
authData = newAuthData;
|
||||
session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, newAuthData);
|
||||
return true;
|
||||
public static String getHeaderValue(String headerName, Header[] headers) {
|
||||
String headerValue = null;
|
||||
for(Header header : headers) {
|
||||
if (header.getName().equalsIgnoreCase(headerName)) {
|
||||
headerValue = header.getValue();
|
||||
}
|
||||
}
|
||||
return headerValue;
|
||||
}
|
||||
|
||||
log.error("Error Occurred in token renewal process.");
|
||||
handleError(resp, HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
return false;
|
||||
public static String getResponseString(HttpResponse response) throws IOException {
|
||||
try (BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
||||
StringBuilder responseBuilder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = rd.readLine()) != null) {
|
||||
responseBuilder.append(line);
|
||||
}
|
||||
return responseBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isPropertyDefined(String property) {
|
||||
return StringUtils.isEmpty(System.getProperty(property));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package io.entgra.ui.request.interceptor.websocket;
|
||||
|
||||
import io.entgra.ui.request.interceptor.beans.AuthData;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerConstants;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
|
||||
public class GrafanaLiveSecurityFilter implements Filter {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GrafanaLiveSecurityFilter.class);
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
HttpServletRequest req = (HttpServletRequest) servletRequest;
|
||||
HttpSession session = req.getSession(false);
|
||||
if (session == null) {
|
||||
log.error("Unauthorized, You are not logged in. Please log in to the portal");
|
||||
return;
|
||||
}
|
||||
AuthData authData = (AuthData) session.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY);
|
||||
if (authData == null) {
|
||||
log.error("Unauthorized, Access token not found in the current session");
|
||||
return;
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
package io.entgra.ui.request.interceptor.websocket;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.ContainerProvider;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
import java.net.URI;
|
||||
import io.entgra.ui.request.interceptor.util.HandlerConstants;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.GrafanaManagementException;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaUtil;
|
||||
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ClientEndpoint
|
||||
public class GrafanaWebSocketClient extends Endpoint {
|
||||
|
||||
private static final Log log = LogFactory.getLog(GrafanaWebSocketClient.class);
|
||||
private Session grafanaServerSession;
|
||||
private Consumer<String> messageConsumer;
|
||||
|
||||
public GrafanaWebSocketClient(URI endpointURI) {
|
||||
try {
|
||||
ClientEndpointConfig clientEndpointConfig = handShakeRequestConfig();
|
||||
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
|
||||
container.connectToServer(this, clientEndpointConfig, endpointURI);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ClientEndpointConfig handShakeRequestConfig() {
|
||||
ClientEndpointConfig.Configurator clientEndpointConfigConfigurator = new ClientEndpointConfig.Configurator() {
|
||||
@Override
|
||||
public void beforeRequest(Map<String, List<String>> headers) {
|
||||
try {
|
||||
headers.put(HttpHeaders.AUTHORIZATION,
|
||||
Collections.singletonList(GrafanaUtil.getBasicAuthBase64Header()));
|
||||
} catch (GrafanaManagementException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
return ClientEndpointConfig.Builder.create().
|
||||
configurator(clientEndpointConfigConfigurator).build();
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
@Override
|
||||
public void onOpen(Session grafanaServerSession, EndpointConfig endpointConfig) {
|
||||
// Due to a bug (https://bz.apache.org/bugzilla/show_bug.cgi?format=multiple&id=57788)
|
||||
// in the tomcat version used, this has to coded like this
|
||||
grafanaServerSession.addMessageHandler(String.class, message -> messageConsumer.accept(message));
|
||||
this.grafanaServerSession = grafanaServerSession;
|
||||
}
|
||||
|
||||
@OnClose
|
||||
@Override
|
||||
public void onClose(Session session, CloseReason reason) {
|
||||
log.info("Server session closed: " + reason);
|
||||
this.grafanaServerSession = null;
|
||||
}
|
||||
|
||||
@OnError
|
||||
@Override
|
||||
public void onError(Session session, Throwable t) {
|
||||
log.error("Error occurred in grafana server session: " + t.toString());
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
public void sendMessageToServer(String message) {
|
||||
if (grafanaServerSession.getAsyncRemote() != null) {
|
||||
grafanaServerSession.getAsyncRemote().sendText(message);
|
||||
}
|
||||
}
|
||||
|
||||
public Session getGrafanaServerSession() {
|
||||
return grafanaServerSession;
|
||||
}
|
||||
|
||||
public void addMessageConsumer(Consumer<String> messageConsumer) {
|
||||
this.messageConsumer = messageConsumer;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package io.entgra.ui.request.interceptor.websocket;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.exception.GrafanaEnvVariablesNotDefined;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaConstants;
|
||||
import org.wso2.carbon.device.mgt.core.grafana.mgt.util.GrafanaUtil;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.OnError;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
@ServerEndpoint(value = "/grafana/api/live/ws")
|
||||
public class GrafanaWebSocketHandler {
|
||||
private static final Log log = LogFactory.getLog(GrafanaWebSocketHandler.class);
|
||||
private GrafanaWebSocketClient grafanaClient;
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session browserSession) throws GrafanaEnvVariablesNotDefined {
|
||||
URI grafanaUri = browserSession.getRequestURI();
|
||||
String grafanaWebSocketUrl = getGrafanaWebSocketUrl(grafanaUri);
|
||||
try {
|
||||
grafanaClient = new GrafanaWebSocketClient(new URI(grafanaWebSocketUrl));
|
||||
grafanaClient.addMessageConsumer(message -> sendMessageToBrowser(browserSession, message));
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("Invalid web socket uri provided", e);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(CloseReason reason) throws IOException {
|
||||
log.info("Browser session closed: " + reason);
|
||||
if (grafanaClient.getGrafanaServerSession() != null) {
|
||||
grafanaClient.getGrafanaServerSession().close();
|
||||
}
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(String message) {
|
||||
grafanaClient.sendMessageToServer(message);
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Throwable t) {
|
||||
log.error("Error occurred in grafana browser session: " + t.toString());
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
public void sendMessageToBrowser(Session browserSession, String message) {
|
||||
try {
|
||||
// Avoid grafana client sending messages when browser session is already closed
|
||||
if(browserSession.isOpen()) {
|
||||
browserSession.getBasicRemote().sendText(message);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error occurred while sending message to browser", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getGrafanaWebSocketUrl(URI requestUri) throws GrafanaEnvVariablesNotDefined {
|
||||
return GrafanaUtil.getGrafanaWebSocketBase(requestUri.getScheme()) + GrafanaConstants.WS_LIVE_API;
|
||||
}
|
||||
}
|
||||
@ -88,6 +88,15 @@
|
||||
<param-value>Cache-Control: no-store, no-cache, must-revalidate, private</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
<filter>
|
||||
<filter-name>GrafanaLiveSecurityFilter</filter-name>
|
||||
<filter-class>io.entgra.ui.request.interceptor.websocket.GrafanaLiveSecurityFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>GrafanaLiveSecurityFilter</filter-name>
|
||||
<url-pattern>/grafana/api/live/ws</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>HttpHeaderSecurityFilter</filter-name>
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
<!--
|
||||
~ Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
~
|
||||
~ Entgra (pvt) Ltd. 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.
|
||||
-->
|
||||
|
||||
<datasources-configuration xmlns:svns="http://org.wso2.securevault/configuration">
|
||||
<providers>
|
||||
<provider>org.wso2.carbon.ndatasource.rdbms.RDBMSDataSourceReader</provider>
|
||||
</providers>
|
||||
|
||||
<datasources>
|
||||
|
||||
<datasource>
|
||||
<name>jdbc/MDM_REPORTS_DS</name>
|
||||
<description>The datasource used for Report Management</description>
|
||||
<jndiConfig>
|
||||
<name>jdbc/MDM_REPORTS_DS</name>
|
||||
</jndiConfig>
|
||||
<definition type="RDBMS">
|
||||
<configuration>
|
||||
<url>jdbc:mysql://localhost:3306/DM_DB?autoReconnect=true&relaxAutoCommit=true&useSSL=false</url>
|
||||
<username>root</username>
|
||||
<password>root</password>
|
||||
<driverClassName>com.mysql.cj.jdbc.Driver</driverClassName>
|
||||
<maxActive>50</maxActive>
|
||||
<maxWait>60000</maxWait>
|
||||
<testOnBorrow>true</testOnBorrow>
|
||||
<validationQuery>SELECT 1</validationQuery>
|
||||
<validationInterval>30000</validationInterval>
|
||||
</configuration>
|
||||
</definition>
|
||||
</datasource>
|
||||
</datasources>
|
||||
</datasources-configuration>
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
|
||||
<!--
|
||||
~ Copyright (c) 2021, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||
~
|
||||
~ Entgra (Pvt) Ltd. 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.
|
||||
-->
|
||||
|
||||
<GrafanaConfiguration>
|
||||
<Cache >
|
||||
<CacheConfiguration name="queryAPICache">
|
||||
<Capacity>100</Capacity>
|
||||
</CacheConfiguration>
|
||||
<CacheConfiguration name="encodedQueryCache">
|
||||
<Capacity>100</Capacity>
|
||||
</CacheConfiguration>
|
||||
</Cache>
|
||||
<AdminUser>
|
||||
<!-- properties can be listed and can be picked up in the relevant implementation class as required-->
|
||||
<Username>admin</Username>
|
||||
<Password>admin2</Password>
|
||||
</AdminUser>
|
||||
</GrafanaConfiguration>
|
||||
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!--
|
||||
~ Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
~
|
||||
~ Entgra (pvt) Ltd. 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.
|
||||
-->
|
||||
<ReportManagementConfiguration>
|
||||
<DatasourceName>jdbc/MDM_REPORTS_DS</DatasourceName>
|
||||
</ReportManagementConfiguration>
|
||||
16
pom.xml
16
pom.xml
@ -314,6 +314,16 @@
|
||||
<artifactId>io.entgra.transport.mgt.sms.handler.common</artifactId>
|
||||
<version>${carbon.device.mgt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||
<artifactId>io.entgra.analytics.mgt.grafana.proxy.core</artifactId>
|
||||
<version>${carbon.device.mgt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||
<artifactId>io.entgra.analytics.mgt.grafana.proxy.common</artifactId>
|
||||
<version>${carbon.device.mgt.version}</version>
|
||||
</dependency>
|
||||
<!-- Device Management dependencies -->
|
||||
|
||||
<!-- Governance dependencies -->
|
||||
@ -1259,6 +1269,11 @@
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${google.gson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${google.guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
@ -2085,6 +2100,7 @@
|
||||
<commons-json.version>3.0.0.wso2v1</commons-json.version>
|
||||
<json.smart.version>1.3</json.smart.version>
|
||||
<google.gson.version>2.8.5</google.gson.version>
|
||||
<google.guava.version>31.0.1-jre</google.guava.version>
|
||||
<squareup.okhttp3.version>4.6.0</squareup.okhttp3.version>
|
||||
<okio.version>1.13.0</okio.version>
|
||||
<github.openfeign.version>9.3.1</github.openfeign.version>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user