Added grafana integration See merge request entgra/carbon-device-mgt!829merge-requests/833/merge
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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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>
|
Loading…
Reference in new issue