diff --git a/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/AverageLoadAverageBean.java b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/AverageLoadAverageBean.java new file mode 100755 index 0000000000..0276197fa7 --- /dev/null +++ b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/AverageLoadAverageBean.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.stratos.common.beans.healthStatistics; + +/* +* This bean class may use to create the data transfer objects for Load Average data of clusters and members. +* */ +public class AverageLoadAverageBean { + + private static final long serialVersionUID = -7788619177798333712L; + + private final String clusterId; + private final Long timeStamp; + private final Double memberAverageLoadAverage; + private final String memberId; + + public AverageLoadAverageBean(String clusterId, Long timeStamp, Double memberAverageLoadAverage, String memberId) { + this.clusterId = clusterId; + this.timeStamp = timeStamp; + this.memberAverageLoadAverage = memberAverageLoadAverage; + this.memberId = memberId; + } + + public String getClusterId() { + return clusterId; + } + + public Double getMemberAverageLoadAverage() { + return memberAverageLoadAverage; + } + + public Long getTimeStamp() { + return timeStamp; + } + + public String getMemberId() { + return memberId; + } + +} diff --git a/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/AverageMemoryConsumptionBean.java b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/AverageMemoryConsumptionBean.java new file mode 100644 index 0000000000..fd7bd620db --- /dev/null +++ b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/AverageMemoryConsumptionBean.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.stratos.common.beans.healthStatistics; + +/* +* This bean class may use to create the data transfer objects for Average Memory data of clusters and members. +* */ +public class AverageMemoryConsumptionBean { + + private static final long serialVersionUID = -7788619177798333711L; + + private final String clusterId; + private final Double memberAverageMemoryConsumption; + private final Long timeStamp; + private final String memberId; + + public AverageMemoryConsumptionBean(final String clusterId,final Double memberAverageMemoryConsumption,final Long timeStamp,final String memberId) { + this.clusterId = clusterId; + this.memberAverageMemoryConsumption = memberAverageMemoryConsumption; + this.timeStamp = timeStamp; + this.memberId = memberId; + } + + public String getClusterId() { + return clusterId; + } + + public Double getMemberAverageMemoryConsumption() { + return memberAverageMemoryConsumption; + } + + public Long getTimeStamp() { + return timeStamp; + } + + public String getMemberId() { + return memberId; + } + +} + diff --git a/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/InFlightRequestBean.java b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/InFlightRequestBean.java new file mode 100755 index 0000000000..ad179c0cad --- /dev/null +++ b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/beans/healthStatistics/InFlightRequestBean.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.stratos.common.beans.healthStatistics; + +/* +* This bean class may use to create the data transfer objects for Inflight request data of clusters. +* */ +public class InFlightRequestBean { + + private static final long serialVersionUID = -7788619177798333712L; + + private final String clusterId; + private final Long timeStamp; + private final Double inFlightRequestCount; + + public InFlightRequestBean(String clusterId, Long timeStamp, Double inFlightRequestCount) { + this.clusterId = clusterId; + this.timeStamp = timeStamp; + this.inFlightRequestCount = inFlightRequestCount; + } + + public String getClusterId() { + return clusterId; + } + + public Double getInFlightRequestCount() { + return inFlightRequestCount; + } + + public Long getTimeStamp() { + return timeStamp; + } + +} diff --git a/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/statistics/publisher/wso2/cep/WSO2CEPHealthStatisticsPublisher.java b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/statistics/publisher/wso2/cep/WSO2CEPHealthStatisticsPublisher.java index 1dc42409a0..5b07060e4f 100644 --- a/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/statistics/publisher/wso2/cep/WSO2CEPHealthStatisticsPublisher.java +++ b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/statistics/publisher/wso2/cep/WSO2CEPHealthStatisticsPublisher.java @@ -56,6 +56,7 @@ private static StreamDefinition createStreamDefinition() { payloadData.add(new Attribute("cluster_instance_id", AttributeType.STRING)); payloadData.add(new Attribute("network_partition_id", AttributeType.STRING)); payloadData.add(new Attribute("member_id", AttributeType.STRING)); + payloadData.add(new Attribute("timeStamp", AttributeType.LONG)); payloadData.add(new Attribute("partition_id", AttributeType.STRING)); payloadData.add(new Attribute("health_description", AttributeType.STRING)); payloadData.add(new Attribute("value", AttributeType.DOUBLE)); @@ -90,6 +91,7 @@ public void publish(String clusterId, String clusterInstanceId, String networkPa payload.add(clusterInstanceId); payload.add(networkPartitionId); payload.add(memberId); + payload.add(System.currentTimeMillis()); payload.add(partitionId); payload.add(health); payload.add(value); diff --git a/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/statistics/publisher/wso2/cep/WSO2CEPInFlightRequestPublisher.java b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/statistics/publisher/wso2/cep/WSO2CEPInFlightRequestPublisher.java index 2ed888381a..e3c10b7d64 100644 --- a/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/statistics/publisher/wso2/cep/WSO2CEPInFlightRequestPublisher.java +++ b/components/org.apache.stratos.common/src/main/java/org/apache/stratos/common/statistics/publisher/wso2/cep/WSO2CEPInFlightRequestPublisher.java @@ -53,6 +53,7 @@ private static StreamDefinition createStreamDefinition() { // Set payload definition payloadData.add(new Attribute("cluster_id", AttributeType.STRING)); payloadData.add(new Attribute("cluster_instance_id", AttributeType.STRING)); + payloadData.add(new Attribute("timeStamp", AttributeType.LONG)); payloadData.add(new Attribute("network_partition_id", AttributeType.STRING)); payloadData.add(new Attribute("in_flight_request_count", AttributeType.DOUBLE)); streamDefinition.setPayloadData(payloadData); @@ -76,6 +77,7 @@ public void publish(String clusterId, String clusterInstanceId, String networkPa List payload = new ArrayList(); payload.add(clusterId); payload.add(clusterInstanceId); + payload.add(System.currentTimeMillis()); payload.add(networkPartitionId); payload.add((double) inFlightRequestCount); diff --git a/components/org.apache.stratos.manager.console/console/applications_form.jag b/components/org.apache.stratos.manager.console/console/applications_form.jag index ad1745ca8b..4381916ab0 100644 --- a/components/org.apache.stratos.manager.console/console/applications_form.jag +++ b/components/org.apache.stratos.manager.console/console/applications_form.jag @@ -26,6 +26,7 @@ var log = new Log("apachestratos.applications_form"), error = [], list_data, caramel = require('caramel'), + config = require('/config/console.json'), context = caramel.configs().context, menuJson = require('/controllers/menu/menu.json'), util = require('/controllers/rest/rest_calls.jag'), @@ -49,7 +50,8 @@ if (!elements) { var applicationName = elements.applicationId; //get application json - applicationJSON = util.RESTCalls.getApplicationJSON(applicationName); + applicationJSONapplicationJSON = util.RESTCalls.getApplicationJSON(applicationName); + var applicationAlias = applicationJSON.alias; if(elements.action == 'view'){ @@ -90,6 +92,7 @@ if (!elements) { } +var healthStatisticEnable=config.healthStatistics.UI_enable; var formtype = elements.formtype; @@ -109,6 +112,7 @@ switch (formtype) { var caramelData = { breadcrumbPathLevelOne: breadcrumbPathLevelOne, breadcrumbPathLevelTwo: '', + healthStatisticEnable:healthStatisticEnable, left_menu: leftMenu, isForm: isForm, isEdit: isEdit, diff --git a/components/org.apache.stratos.manager.console/console/config/console.json b/components/org.apache.stratos.manager.console/console/config/console.json index 45cd1c1adf..055b2d4357 100644 --- a/components/org.apache.stratos.manager.console/console/config/console.json +++ b/components/org.apache.stratos.manager.console/console/config/console.json @@ -1,5 +1,8 @@ { "backendServerConfiguration": { "url": "%https.host%/api/v4.1" + }, + "healthStatistics": { + "UI_enable": "false" } } \ No newline at end of file diff --git a/components/org.apache.stratos.manager.console/console/controllers/healthStatistics/healthStatistics_getrequest.jag b/components/org.apache.stratos.manager.console/console/controllers/healthStatistics/healthStatistics_getrequest.jag new file mode 100644 index 0000000000..ed16a5275e --- /dev/null +++ b/components/org.apache.stratos.manager.console/console/controllers/healthStatistics/healthStatistics_getrequest.jag @@ -0,0 +1,117 @@ +<% +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + var log = new Log("apachestratos.configure_request"), + util = require('/controllers/rest/rest_calls.jag'), + formtype = request.getParameter('formtype'), + ChartType = request.getParameter('chartType'), + Duration = request.getParameter('duration'), + IdValue = request.getParameter('idValue'); + + var formSubmit; + var DurationVal; + + //creatingTimeObjects + var startTime = new Date(); + var endTime = new Date(); + + //add login validator for pages + include('/controllers/login/validator.jag'); + + //checking the interval for the required data to check + if( "30Min" != Duration){ + + switch (Duration) { + + case "1Hour": + DurationVal = 1; + break; + case "1Day": + DurationVal = 24; + break; + case "1Week": + DurationVal = 168; + break; + case "1Month": + DurationVal = 672; + break; + } + + //substratcting hour from current time + startTime.setHours(endTime.getHours() - DurationVal); + + } else { + + //substratcting hour from current time + startTime.setMinutes(endTime.getMinutes() - 30); + + } + + //switch to trigger the rest call when needs + try { + switch (formtype) { + + case "MemoryConsumption": + + if("Cluster" == ChartType){ + + formSubmit = util.RESTCalls.getClusterMemoryAverageDetails(IdValue, startTime.getTime(),endTime.getTime()); + break; + } + else{ + formSubmit = util.RESTCalls.getMemberMemoryAvrageDetails(IdValue, startTime.getTime(),endTime.getTime()); + break; + } + + case "LoadAverage": + + if("Cluster" == ChartType){ + formSubmit = util.RESTCalls.getClusterLoadAverageDetails(IdValue, startTime.getTime(),endTime.getTime()); + break; + } + else{ + formSubmit = util.RESTCalls.getMemberLoadAverageDetails(IdValue, startTime.getTime(),endTime.getTime()); + break; + } + + case "InFlight": + formSubmit = util.RESTCalls.getFlightRequestDetails(IdValue, startTime.getTime(),endTime.getTime()); + break; + + default: + session.put("deploy-status", { "message": "Sorry Endpoint Error", "status": "error" }); + } + + //vaidating the response and return + if (formSubmit == undefined) + { + print({"status": 'error', "message": "No Data found!"}); + + } else { + print(formSubmit); + } + + } catch (e) { + log.warn(e); + print({"status": 'error', "message": e.toString()}); + } + +%> \ No newline at end of file diff --git a/components/org.apache.stratos.manager.console/console/controllers/rest/rest_calls.jag b/components/org.apache.stratos.manager.console/console/controllers/rest/rest_calls.jag index 7b020fa0cf..7cabd61ab1 100644 --- a/components/org.apache.stratos.manager.console/console/controllers/rest/rest_calls.jag +++ b/components/org.apache.stratos.manager.console/console/controllers/rest/rest_calls.jag @@ -27,6 +27,33 @@ RESTCalls = new function(){ return this.sendReceive("GET","/tenants",{}); }; + this.getFlightRequestDetails = function(Id,startDate,endDate){ + + return this.sendReceive("GET","/cluster/flightRequestCount/" +Id+"/"+startDate+"/"+endDate,{}); + }; + + this.getClusterMemoryAverageDetails = function(Id,startDate,endDate){ + + return this.sendReceive("GET","/cluster/averageMemory/" +Id+"/"+startDate+"/"+endDate,{}); + + }; + + this.getClusterLoadAverageDetails = function(Id,startDate,endDate){ + + return this.sendReceive("GET","/cluster/averageLoad/" +Id+"/"+startDate+"/"+endDate,{}); + + }; + + this.getMemberLoadAverageDetails = function(Id,startDate,endDate){ + + return this.sendReceive("GET","/member/averageLoad/" +Id+"/"+startDate+"/"+endDate,{}); + }; + + this.getMemberMemoryAvrageDetails = function(Id,startDate,endDate){ + + return this.sendReceive("GET","/member/averageMemory/" +Id+"/"+startDate+"/"+endDate,{}); + }; + this.deployPartitionDefinition = function(partitionDefinition){ return this.send("POST","/networkPartitions", partitionDefinition); }; @@ -346,7 +373,7 @@ RESTCalls = new function(){ var backendServerURL = config.backendServerConfiguration.url; //handle url null issue if(backendServerURL.indexOf('null') >= 0 ){ - return request.getContextPath()+'/login/'; + return request.getContextPath()+'/login/'; }else { // getting the access token from the session. var endpoint = backendServerURL + urlPostFix; @@ -370,18 +397,22 @@ RESTCalls = new function(){ } if (responseREST.xhr.status >= 200 && responseREST.xhr.status < 300) { //if success if (responseREST.data != null && responseREST.data != undefined) { + session.put("get-status", { "message": parse(responseREST.data).message, "status": "success" }); } } else if (responseREST.xhr.status >= 300 && responseREST.xhr.status < 400) { //if redirects if (responseREST.data != null && responseREST.data != undefined) { + session.put("get-status", { "message": parse(responseREST.data).message, "status": "warning" }); } } else if (responseREST.xhr.status >= 400 && responseREST.xhr.status < 500) { //if client error if (responseREST.data != null && responseREST.data != undefined) { + session.put("get-status", { "message": parse(responseREST.data).message, "status": "error" }); } } else if (responseREST.xhr.status >= 500 && responseREST.xhr.status < 600) { //if server error if (responseREST.data != null && responseREST.data != undefined) { + session.put("get-status", { "message": parse(responseREST.data).message, "status": "error" }); } } else { diff --git a/components/org.apache.stratos.manager.console/console/health_statistics.jag b/components/org.apache.stratos.manager.console/console/health_statistics.jag new file mode 100644 index 0000000000..5b3e6a1d4f --- /dev/null +++ b/components/org.apache.stratos.manager.console/console/health_statistics.jag @@ -0,0 +1,52 @@ +<% +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +//add login validator for pages +include('/controllers/login/validator.jag'); +include('/controllers/menu/menu_generator.jag'); + +var log = new Log("apacheStratos.appconfig"), + error = [], + caramel = require('caramel'), + alias = request.getParameter('alias'), //applicaion name + context = caramel.configs().context, + util = require('/controllers/rest/rest_calls.jag'), + menuJson = require('/controllers/menu/menu.json'), + util = require('/controllers/rest/rest_calls.jag'), + id = request.getParameter('id'), + type = request.getParameter('type'), + userPermissions = session.get('PERMISSIONS'); + + //create left menu + var leftMenu = menuGenerator(context, menuJson.menu, userPermissions); + var log = new Log(); + +//rendering the data +caramel.render({ + breadcrumbPathLevelOne: 'health_statistics', + id:id, + type: type, + alias: alias, + left_menu: leftMenu, + error: error +}); + +%> \ No newline at end of file diff --git a/components/org.apache.stratos.manager.console/console/jaggery.conf b/components/org.apache.stratos.manager.console/console/jaggery.conf index 7e1fa497db..a97299bb94 100644 --- a/components/org.apache.stratos.manager.console/console/jaggery.conf +++ b/components/org.apache.stratos.manager.console/console/jaggery.conf @@ -23,10 +23,16 @@ "path": "/configure_form.jag" }, { - "url": "/users/", - "path": "/users.jag" + "url": "/users/", + "path": "/users.jag" + }, + { + "url": "/healthStatistics/", + "path": "/health_statistics.jag" }, { + + "url": "/users/*", "path": "/users_form.jag" }, diff --git a/components/org.apache.stratos.manager.console/console/themes/theme0/css/custom.css b/components/org.apache.stratos.manager.console/console/themes/theme0/css/custom.css index a8b1b3a159..a4d59ab42b 100644 --- a/components/org.apache.stratos.manager.console/console/themes/theme0/css/custom.css +++ b/components/org.apache.stratos.manager.console/console/themes/theme0/css/custom.css @@ -73,8 +73,8 @@ body{ background: url('../images/stratos_background.png') no-repeat; background .slidewindow .tab-handles .slidewindow-handle, .slidewindow.right .tab-handles .slidewindow-handle { display: block; float: none; } .slidewindow-content { - background-color: white; - font-size:16px; + background-color: white; + font-size:16px; position: relative; float: left; z-index: 1; @@ -106,7 +106,84 @@ body{ background: url('../images/stratos_background.png') no-repeat; background position: relative; float: left; z-index: 0; - cursor:pointer; + cursor:pointer; +} + +.lineChart--areaLine { + fill: none; + stroke: #6bb7c7; + stroke-width: 3; +} + +.charts--headline { + text-align: center; + color: #444; + background-color: #fff; + padding: 1em; +} + +.lineChart--area { + fill: url(#lineChart--gradientBackgroundArea); +} + +.lineChart--areaLine { + fill: none; + stroke: #6bb7c7; + stroke-width: 1; +} + +.lineChart--bubble--label { + fill: none; + stroke: #6bb7c7; + font-size: 10.7px; + font-weight: 100; +} + +.lineChart--bubble--value { + fill: #fff; + stroke: #fff; + font-size: 15px; + font-weight: 100; +} + +.lineChart--circle { + fill: #6bb7c7; + stroke: #fff; + stroke-width: 1; +} + +.lineChart--circle__highlighted { + fill: #fff; + stroke: #3f94a7; +} + +.lineChart--gradientBackgroundArea--top { + stop-color: #6bb7c7; + stop-opacity: 0.1; +} + +.lineChart--gradientBackgroundArea--bottom { + stop-color: #6bb7c7; + stop-opacity: 0.6; +} + +.lineChart--svg { + border: 1px solid #eee; +} + +.lineChart--xAxisTicks .domain, .lineChart--xAxis .domain, .lineChart--yAxisTicks .domain { + display: none; +} + +.lineChart--xAxis .tick line { + display: none; +} + +.lineChart--xAxisTicks .tick line, .lineChart--yAxisTicks .tick line { + fill: none; + stroke: #b3b3b3; + stroke-width: 1; + stroke-dasharray: 2,2; } @@ -233,4 +310,84 @@ div#textform>div>h3 { h3.panel-title { color: #999; -} \ No newline at end of file +} + + +svg { + font: 10px sans-serif; +} + +.area { + fill: #00BFFF; + clip-path: url(#clip); +} + +.axis path, +.axis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} + +.d3-tip { + line-height: 1; + font-weight: bold; + padding: 12px; + background: rgba(0, 0, 0, 0.8); + color: #fff; + border-radius: 2px; +} + +/* Creates a small triangle extender for the tooltip */ +.d3-tip:after { + box-sizing: border-box; + display: inline; + font-size: 10px; + width: 100%; + line-height: 1; + color: rgba(0, 0, 0, 0.8); + content: "\25BC"; + position: absolute; + text-align: center; +} + +/* Style northward tooltips differently */ +.d3-tip.n:after { + margin: -1px 0 0 0; + top: 100%; + left: 0; +} + +.brush .extent { + stroke: #fff; + fill-opacity: .125; + shape-rendering: crispEdges; +} +svg { + font: 10px sans-serif; +} + +.brush .extent { + stroke: #fff; + fill-opacity: .125; + shape-rendering: crispEdges; +} + + +.x.axis path { + display: none; +} + +.line { + fill: none; + stroke: green; + stroke-width: 1.5px; +} + +.area1 { + fill: orange; +} + +.area2 { + fill: red; +} diff --git a/components/org.apache.stratos.manager.console/console/themes/theme0/helpers/health_statistics.js b/components/org.apache.stratos.manager.console/console/themes/theme0/helpers/health_statistics.js new file mode 100644 index 0000000000..dffd20b697 --- /dev/null +++ b/components/org.apache.stratos.manager.console/console/themes/theme0/helpers/health_statistics.js @@ -0,0 +1,28 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +var resources = function (page, meta) { + return { + js: ['custom/script.js', 'd3js-v3/d3.v3.min.js' , + 'd3.tip-v0.6.3/d3.tip.v0.6.3.js','health_statistics/health_statistics.js'], + css: ['bootstrap-switch-3.0.2/bootstrap-switch.min.css', 'custom/style.css'] + }; +}; diff --git a/components/org.apache.stratos.manager.console/console/themes/theme0/js/custom/applications_topology.js b/components/org.apache.stratos.manager.console/console/themes/theme0/js/custom/applications_topology.js index 4e617ea5eb..bd4535372c 100644 --- a/components/org.apache.stratos.manager.console/console/themes/theme0/js/custom/applications_topology.js +++ b/components/org.apache.stratos.manager.console/console/themes/theme0/js/custom/applications_topology.js @@ -18,12 +18,13 @@ * under the License. * */ - + //create JSON from topology -function genTree(data){ +function genTree(data) { var rawout = []; - var rootnode ={}; + var alias; + var rootnode = {}; rootnode.name = data.id; rootnode.parent = null; rootnode.status = data.status; @@ -31,8 +32,8 @@ function genTree(data){ rawout.push(rootnode); //application instances - function applicationInstances(items, collector, parent){ - for(var prop in items){ + function applicationInstances(items, collector, parent) { + for (var prop in items) { if (items.hasOwnProperty(prop)) { var cur_name = items[prop].instanceId, status = items[prop].status, @@ -45,10 +46,10 @@ function genTree(data){ } } - function clusterInstances(items, collector, parent){ - for(var prop in items){ + function clusterInstances(items, collector, parent) { + for (var prop in items) { if (items.hasOwnProperty(prop)) { - var cur_name = items[prop].clusterId + items[prop].instanceId, + var cur_name = items[prop].clusterId, alias = items[prop].alias, hostNames = items[prop].hostNames.toString(), serviceName = items[prop].serviceName, @@ -69,20 +70,21 @@ function genTree(data){ } } - function groupInstances(items, collector, parent){ - for(var prop in items){ + function groupInstances(items, collector, parent) { + for (var prop in items) { if (items.hasOwnProperty(prop)) { var cur_name = items[prop].groupId + items[prop].instanceId, instanceId = items[prop].instanceId, groupId = items[prop].groupId, status = items[prop].status; var type = 'groups'; - rawout.push({"name": cur_name, "parent": parent, "type": type, "status": status, - "groupId":groupId, "instanceId":instanceId + rawout.push({ + "name": cur_name, "parent": parent, "type": type, "status": status, + "groupId": groupId, "instanceId": instanceId }); clusterInstances(items[prop].clusterInstances, collector, cur_name); - if(items[prop].hasOwnProperty('groupInstances')){ + if (items[prop].hasOwnProperty('groupInstances')) { groupInstances(items[prop].groupInstances, collector, cur_name) } @@ -90,8 +92,8 @@ function genTree(data){ } } - function clustermembers(items, collector, parent){ - for(var prop in items){ + function clustermembers(items, collector, parent) { + for (var prop in items) { if (items.hasOwnProperty(prop)) { var cur_name = items[prop].memberId, defaultPrivateIP = items[prop].defaultPrivateIP, @@ -101,9 +103,10 @@ function genTree(data){ partitionId = items[prop].partitionId, status = items[prop].status; var type = 'members'; - rawout.push({"name": cur_name, "parent": parent, "type": type, "status": status, - "defaultPrivateIP":defaultPrivateIP, "defaultPublicIP":defaultPublicIP,"ports":ports, - "networkPartitionId":networkPartitionId, "partitionId":partitionId + rawout.push({ + "name": cur_name, "parent": parent, "type": type, "status": status, + "defaultPrivateIP": defaultPrivateIP, "defaultPublicIP": defaultPublicIP, "ports": ports, + "networkPartitionId": networkPartitionId, "partitionId": partitionId }); } } @@ -139,7 +142,7 @@ function genTree(data){ function update(source) { - // ************** Generate the tree diagram ***************** + // ************** Generate the tree diagram ***************** var margin = {top: 80, right: 120, bottom: 20, left: 120}, width = 900 - margin.right - margin.left, height = 900 - margin.top - margin.bottom; @@ -147,8 +150,10 @@ function update(source) { var i = 0; var tree = d3.layout.tree() - .separation(function(a, b) { return ((a.parent == source) && (b.parent == source)) ? 5 : 4; }) - .size([height+100, width]); + .separation(function (a, b) { + return ((a.parent == source) && (b.parent == source)) ? 5 : 4; + }) + .size([height + 100, width]); var diagonal = d3.svg.diagonal() .projection(function (d) { @@ -156,8 +161,8 @@ function update(source) { }); function redraw() { svg.attr("transform", - "translate(" + d3.event.translate + ")" - + " scale(" + d3.event.scale + ")"); + "translate(" + d3.event.translate + ")" + + " scale(" + d3.event.scale + ")"); } var svg = d3.select(".application-topology").append("svg") @@ -193,29 +198,39 @@ function update(source) { }) .attr('data-content', function (d) { if (d.type == 'clusters') { - if(d.accessUrls != ''){ + if (d.accessUrls != '') { var accessURLHTML = "Access URLs: "; - for(var i=0;i"+ d.accessUrls[i] + - "
" ; + for (var i = 0; i < d.accessUrls.length; i++) { + accessURLHTML += "" + d.accessUrls[i] + + "
"; } - }else{ - var accessURLHTML =''; + } else { + var accessURLHTML = ''; + } + + var stringHTML = "Cluster Id: " + d.name + "
" + + "Cluster Alias: " + d.alias + "
" + + accessURLHTML + + "HostNames: " + d.hostNames + "
" + + "Service Name: " + d.serviceName + "
" + + "Status: " + d.status + "

"; + + //enabling the health statistics button + if(healthStatisticEnable){ + div_html = stringHTML.concat(" "); + } + //enabling the health statistics button + else{ + div_html = stringHTML; } - div_html = "Cluster Id: " + d.name + "
" + - "Cluster Alias: " + d.alias + "
" + - accessURLHTML + - "HostNames: " + d.hostNames + "
" + - "Service Name: " + d.serviceName + "
" + - "Status: " + d.status; } else if (d.type == 'members') { - if((typeof d.ports != 'undefined') && (d.ports.length > 0)) { + if ((typeof d.ports != 'undefined') && (d.ports.length > 0)) { var portsHTML = "Ports:
"; - for(var i=0;i" + - "Default Private IP: " + d.defaultPrivateIP + "
" + - "Default Public IP: " + d.defaultPublicIP + "
" + - portsHTML + - "Network Partition Id: " + d.networkPartitionId + "
" + - "Partition Id: " + d.partitionId + "
" + - "Status: " + d.status; + + var stringHTML = "Member Id: " + d.name + "
" + + "Default Private IP: " + d.defaultPrivateIP + "
" + + "Default Public IP: " + d.defaultPublicIP + "
" + + portsHTML + + "Network Partition Id: " + d.networkPartitionId + "
" + + "Partition Id: " + d.partitionId + "
" + + "Status: " + d.status + "

"; + + //enabling the health statistics button + if(healthStatisticEnable){ + div_html = stringHTML.concat(" "); + } + //disabling the health statistics button + else{ + + div_html = stringHTML; + } + } else if (d.type == 'groups') { div_html = "Group Instance Id: " + d.instanceId + "
" + - "Status: " + d.status; + "Status: " + d.status; } else if (d.type == 'applicationInstances') { div_html = "Instance Id: " + d.name + "
" + - "Status: " + d.status; + "Status: " + d.status; } else { - div_html = "Alias: " + d.name + "
"+ - "Status: " + d.status; + div_html = "Alias: " + d.name + "
" + + "Status: " + d.status; + alias = d.name; } - return div_html; + return div_html; }); - // add popover on nodes + + // add popover on nodes nodeEnter.append("rect") .attr("x", -15) .attr("y", -15) @@ -296,13 +325,13 @@ function update(source) { .attr("dy", ".35em") .attr("text-anchor", "middle") .text(function (d) { - if(d.type == 'members') { + if (d.type == 'members') { return ''; - }else if(d.type == 'clusters') { + } else if (d.type == 'clusters') { return d.alias; - }else if(d.type == 'groups'){ + } else if (d.type == 'groups') { return d.groupId; - }else{ + } else { return d.name; } @@ -317,20 +346,20 @@ function update(source) { // Enter the links. link.enter().insert("path", "g") - .style('fill','none') - .style('stroke-width','2') - .style('stroke','#ccc') + .style('fill', 'none') + .style('stroke-width', '2') + .style('stroke', '#ccc') .attr("class", "link") .attr("d", diagonal); //enable popovers on nodes $('svg .node').popover({ 'trigger': 'manual' - ,'container': '.application-topology' - ,'placement': 'auto' - ,'white-space': 'nowrap' - ,'html':'true' - ,delay: {show: 50, hide: 400} + , 'container': '.application-topology' + , 'placement': 'auto' + , 'white-space': 'nowrap' + , 'html': 'true' + , delay: {show: 50, hide: 400} }); var timer, @@ -339,24 +368,28 @@ function update(source) { $(elem).popover('hide'); } $('svg .node').hover( - function() { + function () { var self = this; clearTimeout(timer); $('.popover').hide(); //Hide any open popovers on other elements. popover_parent = self $(self).popover('show'); }, - function() { + function () { var self = this; - timer = setTimeout(function(){hidePopover(self)},300); + timer = setTimeout(function () { + hidePopover(self) + }, 300); }); $(document).on({ - mouseenter: function() { + mouseenter: function () { clearTimeout(timer); }, - mouseleave: function() { + mouseleave: function () { var self = this; - timer = setTimeout(function(){hidePopover(popover_parent)},300); + timer = setTimeout(function () { + hidePopover(popover_parent) + }, 300); } }, '.popover'); @@ -365,15 +398,15 @@ function update(source) { //Application view // repaint -function Repaint(){ - $("#whiteboard").resize(function(){ +function Repaint() { + $("#whiteboard").resize(function () { jsPlumb.repaintEverything(); }); } // drag -function DragEl(el){ - jsPlumb.draggable($(el) ,{ - containment:"#whiteboard" +function DragEl(el) { + jsPlumb.draggable($(el), { + containment: "#whiteboard" }); } @@ -381,10 +414,10 @@ function DragEl(el){ // JsPlumb Config var color = "gray", exampleColor = "#00f", - arrowCommon = { foldback:0.7, fillStyle:color, width:14 }; + arrowCommon = {foldback: 0.7, fillStyle: color, width: 14}; jsPlumb.importDefaults({ - Connector : [ "Bezier", { curviness:63 } ], + Connector: ["Bezier", {curviness: 63}], /*Overlays: [ [ "Arrow", { location:0.7 }, arrowCommon ], ]*/ @@ -392,63 +425,65 @@ jsPlumb.importDefaults({ var nodeDropOptions = { - activeClass:"dragActive" + activeClass: "dragActive" }; var bottomConnectorOptions = { - endpoint:"Rectangle", - paintStyle:{ width:25, height:21, fillStyle:'#666' }, - isSource:true, - connectorStyle : { strokeStyle:"#666" }, - isTarget:false, - maxConnections:20 + endpoint: "Rectangle", + paintStyle: {width: 25, height: 21, fillStyle: '#666'}, + isSource: true, + connectorStyle: {strokeStyle: "#666"}, + isTarget: false, + maxConnections: 20 }; var endpointOptions = { - isTarget:true, - endpoint:"Dot", - paintStyle:{ - fillStyle:"gray" + isTarget: true, + endpoint: "Dot", + paintStyle: { + fillStyle: "gray" }, dropOptions: nodeDropOptions, - maxConnections:1 + maxConnections: 1 }; var groupOptions = { - isTarget:true, - endpoint:"Dot", - paintStyle:{ - fillStyle:"gray" + isTarget: true, + endpoint: "Dot", + paintStyle: { + fillStyle: "gray" }, dropOptions: nodeDropOptions, - maxConnections:1 + maxConnections: 1 }; var generatedCartridgeEndpointOptions = { - isTarget:false, - endpoint:"Dot", - paintStyle:{ - fillStyle:"gray" + isTarget: false, + endpoint: "Dot", + paintStyle: { + fillStyle: "gray" }, dropOptions: '', - maxConnections:1 + maxConnections: 1 }; var generatedGroupOptions = { - isTarget:false, - endpoint:"Dot", - paintStyle:{ - fillStyle:"gray" + isTarget: false, + endpoint: "Dot", + paintStyle: { + fillStyle: "gray" }, dropOptions: nodeDropOptions, - maxConnections:1 + maxConnections: 1 }; function dagrePosition(){ // construct dagre graph from JsPlumb graph var g = new dagre.graphlib.Graph(); - g.setGraph({ranksep:'80'}); - g.setDefaultEdgeLabel(function() { return {}; }); + g.setGraph({ranksep: '80'}); + g.setDefaultEdgeLabel(function () { + return {}; + }); var nodes = $(".stepnode"); for (var i = 0; i < nodes.length; i++) { @@ -458,53 +493,57 @@ function dagrePosition(){ var edges = jsPlumb.getAllConnections(); for (var i = 0; i < edges.length; i++) { var c = edges[i]; - g.setEdge(c.source.id,c.target.id ); + g.setEdge(c.source.id, c.target.id); } // calculate the layout (i.e. node positions) dagre.layout(g); // Applying the calculated layout - g.nodes().forEach(function(v) { + g.nodes().forEach(function (v) { $("#" + v).css("left", g.node(v).x + "px"); $("#" + v).css("top", g.node(v).y + "px"); }); jsPlumb.repaintEverything(); } //add group to editor -var cartridgeCounter =0; +var cartridgeCounter = 0; //add group to editor -function addJsplumbGroup(groupJSON, cartridgeCounter){ +function addJsplumbGroup(groupJSON, cartridgeCounter) { - var divRoot = $('
').attr({'id':cartridgeCounter+'-'+groupJSON.alias,'data-type':'group','data-ctype':groupJSON.alias}) + var divRoot = $('
').attr({ + 'id': cartridgeCounter + '-' + groupJSON.alias, + 'data-type': 'group', + 'data-ctype': groupJSON.alias + }) .text(groupJSON.alias) .addClass('input-false') .addClass('application') .attr('data-toggle', 'tooltip') - .attr('title',groupJSON.alias) + .attr('title', groupJSON.alias) .addClass('stepnode') .appendTo('#whiteboard'); jsPlumb.addEndpoint($(divRoot), { - anchor:"BottomCenter" + anchor: "BottomCenter" }, bottomConnectorOptions); DragEl($(divRoot)); - if(groupJSON['components']['cartridges']) { + if (groupJSON['components']['cartridges']) { genJsplumbCartridge(groupJSON['components']['cartridges'], divRoot, groupJSON.alias); } - if(groupJSON['components']['groups']){ + if (groupJSON['components']['groups']) { genJsplumbGroups(groupJSON['components']['groups'], divRoot, groupJSON.alias); } - function genJsplumbCartridge(item, currentParent, parentName){ + function genJsplumbCartridge(item, currentParent, parentName) { for (var prop in item) { var id = item[prop].type; - var divCartridge = $('
').attr({'id':cartridgeCounter+'-'+parentName+'-'+item[prop].type} ) + var divCartridge = $('
').attr({'id': cartridgeCounter + '-' + parentName + '-' + item[prop].type}) .text(item[prop].type) .addClass('input-false') .addClass('stepnode') .attr('data-toggle', 'tooltip') - .attr('title',item[prop].type ) + .attr('title', item[prop].type) .appendTo('#whiteboard'); @@ -514,12 +553,12 @@ function addJsplumbGroup(groupJSON, cartridgeCounter){ //add connection options jsPlumb.connect({ - source:$(currentParent), - target:$(divCartridge), - paintStyle:{strokeStyle:"blue", lineWidth:1 }, - Connector : [ "Bezier", { curviness:63 } ], - anchors:["BottomCenter", "TopCenter"], - endpoint:"Dot" + source: $(currentParent), + target: $(divCartridge), + paintStyle: {strokeStyle: "blue", lineWidth: 1}, + Connector: ["Bezier", {curviness: 63}], + anchors: ["BottomCenter", "TopCenter"], + endpoint: "Dot" }); DragEl($(divCartridge)); @@ -528,17 +567,21 @@ function addJsplumbGroup(groupJSON, cartridgeCounter){ function genJsplumbGroups(item, currentParent, parentName) { for (var prop in item) { - var divGroup = $('
').attr({'id':cartridgeCounter+'-'+parentName+'-'+item[prop]['name'],'data-type':'group','data-ctype':item[prop]['name'] }) + var divGroup = $('
').attr({ + 'id': cartridgeCounter + '-' + parentName + '-' + item[prop]['name'], + 'data-type': 'group', + 'data-ctype': item[prop]['name'] + }) .text(item[prop]['name']) .addClass('stepnode') .attr('data-toggle', 'tooltip') - .attr('title',item[prop]['name']) + .attr('title', item[prop]['name']) .addClass('input-false') .appendTo('#whiteboard'); jsPlumb.addEndpoint($(divGroup), { - anchor:"BottomCenter" + anchor: "BottomCenter" }, bottomConnectorOptions); jsPlumb.addEndpoint($(divGroup), { @@ -547,33 +590,30 @@ function addJsplumbGroup(groupJSON, cartridgeCounter){ //add connection options jsPlumb.connect({ - source:$(currentParent), - target:$(divGroup), - paintStyle:{strokeStyle:"blue", lineWidth:1 }, - Connector : [ "Bezier", { curviness:63 } ], - anchors:["BottomCenter", "TopCenter"], - endpoint:"Dot" + source: $(currentParent), + target: $(divGroup), + paintStyle: {strokeStyle: "blue", lineWidth: 1}, + Connector: ["Bezier", {curviness: 63}], + anchors: ["BottomCenter", "TopCenter"], + endpoint: "Dot" }); DragEl($(divGroup)); - if(item[prop].hasOwnProperty('cartridges')) { - genJsplumbCartridge(item[prop].cartridges, divGroup, parentName+'-'+item[prop]['name'] ); + if (item[prop].hasOwnProperty('cartridges')) { + genJsplumbCartridge(item[prop].cartridges, divGroup, parentName + '-' + item[prop]['name']); } - if(item[prop].hasOwnProperty('groups')) { - genJsplumbGroups(item[prop].groups, divGroup, parentName+'-'+item[prop]['name']) + if (item[prop].hasOwnProperty('groups')) { + genJsplumbGroups(item[prop].groups, divGroup, parentName + '-' + item[prop]['name']) } } } - - - } var initapp = 0; -$("a[href='#application']").on('shown.bs.tab', function(e) { - if(initapp == 0){ +$("a[href='#application']").on('shown.bs.tab', function (e) { + if (initapp == 0) { addJsplumbGroup(applicationJSON, cartridgeCounter); //reposition after group add dagrePosition(); @@ -581,5 +621,20 @@ $("a[href='#application']").on('shown.bs.tab', function(e) { } }); +//function to send topology data to the health statistics ui +function showHealthStat(element){ + var currentURL = window.location.href; + var splitTense = currentURL.split('console'); + var newURL = splitTense[0] + "console/healthStatistics/"; + + var form = $('
' + + '' + + '' + + '' + '
'); + + $('body').append(form); + $(form).submit(); +} + diff --git a/components/org.apache.stratos.manager.console/console/themes/theme0/js/d3.tip-v0.6.3/d3.tip.v0.6.3.js b/components/org.apache.stratos.manager.console/console/themes/theme0/js/d3.tip-v0.6.3/d3.tip.v0.6.3.js new file mode 100644 index 0000000000..6cfa3cb66b --- /dev/null +++ b/components/org.apache.stratos.manager.console/console/themes/theme0/js/d3.tip-v0.6.3/d3.tip.v0.6.3.js @@ -0,0 +1,280 @@ +// d3.tip +// Copyright (c) 2013 Justin Palmer +// +// Tooltips for d3.js SVG visualizations + +// Public - contructs a new tooltip +// +// Returns a tip +d3.tip = function() { + var direction = d3_tip_direction, + offset = d3_tip_offset, + html = d3_tip_html, + node = initNode(), + svg = null, + point = null, + target = null + + function tip(vis) { + svg = getSVGNode(vis) + point = svg.createSVGPoint() + document.body.appendChild(node) + } + + // Public - show the tooltip on the screen + // + // Returns a tip + tip.show = function() { + var args = Array.prototype.slice.call(arguments) + if(args[args.length - 1] instanceof SVGElement) target = args.pop() + + var content = html.apply(this, args), + poffset = offset.apply(this, args), + dir = direction.apply(this, args), + nodel = d3.select(node), i = 0, + coords + + nodel.html(content) + .style({ opacity: 1, 'pointer-events': 'all' }) + + while(i--) nodel.classed(directions[i], false) + coords = direction_callbacks.get(dir).apply(this) + nodel.classed(dir, true).style({ + top: (coords.top + poffset[0]) + 'px', + left: (coords.left + poffset[1]) + 'px' + }) + + return tip + } + + // Public - hide the tooltip + // + // Returns a tip + tip.hide = function() { + nodel = d3.select(node) + nodel.style({ opacity: 0, 'pointer-events': 'none' }) + return tip + } + + // Public: Proxy attr calls to the d3 tip container. Sets or gets attribute value. + // + // n - name of the attribute + // v - value of the attribute + // + // Returns tip or attribute value + tip.attr = function(n, v) { + if (arguments.length < 2 && typeof n === 'string') { + return d3.select(node).attr(n) + } else { + var args = Array.prototype.slice.call(arguments) + d3.selection.prototype.attr.apply(d3.select(node), args) + } + + return tip + } + + // Public: Proxy style calls to the d3 tip container. Sets or gets a style value. + // + // n - name of the property + // v - value of the property + // + // Returns tip or style property value + tip.style = function(n, v) { + if (arguments.length < 2 && typeof n === 'string') { + return d3.select(node).style(n) + } else { + var args = Array.prototype.slice.call(arguments) + d3.selection.prototype.style.apply(d3.select(node), args) + } + + return tip + } + + // Public: Set or get the direction of the tooltip + // + // v - One of n(north), s(south), e(east), or w(west), nw(northwest), + // sw(southwest), ne(northeast) or se(southeast) + // + // Returns tip or direction + tip.direction = function(v) { + if (!arguments.length) return direction + direction = v == null ? v : d3.functor(v) + + return tip + } + + // Public: Sets or gets the offset of the tip + // + // v - Array of [x, y] offset + // + // Returns offset or + tip.offset = function(v) { + if (!arguments.length) return offset + offset = v == null ? v : d3.functor(v) + + return tip + } + + // Public: sets or gets the html value of the tooltip + // + // v - String value of the tip + // + // Returns html value or tip + tip.html = function(v) { + if (!arguments.length) return html + html = v == null ? v : d3.functor(v) + + return tip + } + + function d3_tip_direction() { return 'n' } + function d3_tip_offset() { return [0, 0] } + function d3_tip_html() { return ' ' } + + var direction_callbacks = d3.map({ + n: direction_n, + s: direction_s, + e: direction_e, + w: direction_w, + nw: direction_nw, + ne: direction_ne, + sw: direction_sw, + se: direction_se + }), + + directions = direction_callbacks.keys() + + function direction_n() { + var bbox = getScreenBBox() + return { + top: bbox.n.y - node.offsetHeight, + left: bbox.n.x - node.offsetWidth / 2 + } + } + + function direction_s() { + var bbox = getScreenBBox() + return { + top: bbox.s.y, + left: bbox.s.x - node.offsetWidth / 2 + } + } + + function direction_e() { + var bbox = getScreenBBox() + return { + top: bbox.e.y - node.offsetHeight / 2, + left: bbox.e.x + } + } + + function direction_w() { + var bbox = getScreenBBox() + return { + top: bbox.w.y - node.offsetHeight / 2, + left: bbox.w.x - node.offsetWidth + } + } + + function direction_nw() { + var bbox = getScreenBBox() + return { + top: bbox.nw.y - node.offsetHeight, + left: bbox.nw.x - node.offsetWidth + } + } + + function direction_ne() { + var bbox = getScreenBBox() + return { + top: bbox.ne.y - node.offsetHeight, + left: bbox.ne.x + } + } + + function direction_sw() { + var bbox = getScreenBBox() + return { + top: bbox.sw.y, + left: bbox.sw.x - node.offsetWidth + } + } + + function direction_se() { + var bbox = getScreenBBox() + return { + top: bbox.se.y, + left: bbox.e.x + } + } + + function initNode() { + var node = d3.select(document.createElement('div')) + node.style({ + position: 'absolute', + opacity: 0, + pointerEvents: 'none', + boxSizing: 'border-box' + }) + + return node.node() + } + + function getSVGNode(el) { + el = el.node() + if(el.tagName.toLowerCase() == 'svg') + return el + + return el.ownerSVGElement + } + + // Private - gets the screen coordinates of a shape + // + // Given a shape on the screen, will return an SVGPoint for the directions + // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest), + // sw(southwest). + // + // +-+-+ + // | | + // + + + // | | + // +-+-+ + // + // Returns an Object {n, s, e, w, nw, sw, ne, se} + function getScreenBBox() { + var targetel = target || d3.event.target, + bbox = {}, + matrix = targetel.getScreenCTM(), + tbbox = targetel.getBBox(), + width = tbbox.width, + height = tbbox.height, + x = tbbox.x, + y = tbbox.y, + scrollTop = document.documentElement.scrollTop || document.body.scrollTop, + scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft + + + point.x = x + scrollLeft + point.y = y + scrollTop + bbox.nw = point.matrixTransform(matrix) + point.x += width + bbox.ne = point.matrixTransform(matrix) + point.y += height + bbox.se = point.matrixTransform(matrix) + point.x -= width + bbox.sw = point.matrixTransform(matrix) + point.y -= height / 2 + bbox.w = point.matrixTransform(matrix) + point.x += width + bbox.e = point.matrixTransform(matrix) + point.x -= width / 2 + point.y -= height / 2 + bbox.n = point.matrixTransform(matrix) + point.y += height + bbox.s = point.matrixTransform(matrix) + + return bbox + } + + return tip +}; diff --git a/components/org.apache.stratos.manager.console/console/themes/theme0/js/health_statistics/health_statistics.js b/components/org.apache.stratos.manager.console/console/themes/theme0/js/health_statistics/health_statistics.js new file mode 100644 index 0000000000..be1d3845f5 --- /dev/null +++ b/components/org.apache.stratos.manager.console/console/themes/theme0/js/health_statistics/health_statistics.js @@ -0,0 +1,433 @@ + /* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + var jsonDataLoadAvg; + var jsonDataFlightRequest; + var jsonDataMemoryAvg; + var DURATION = 100; + + + //onclick function which will trigger the option for 30mints,1 hour etc + function DurationOnClick(element) { + + var buttonId = element.id; + var buttonName = $(element).attr("name"); + var chartType = $('#chartType').val(); + var idValue = $('#IdValue').val(); + + //here the spinner will indicate untill the data loads to the map + if ('InFlight' != buttonName) { + + if ('LoadAverage' == buttonName) { + $('#container2').empty(); + $('#container2').html(''); + + } else { + + $('#container1').empty(); + $('#container1').html(''); + + } + } else { + $('#container3').empty(); + $('#container3').html(''); + + } + + //calls the rest caller function to draw the charts + restCaller(buttonName, idValue, chartType, buttonId); + + } + + //ajax call to the UI back end get the data to the charts + function restCaller(buttonName, idValue, chartType, buttonId) { + + var html1 = ' ' + + '' + + ' ' + + ' '; + var html2 = ' ' + + ' ' + + ' ' + + ' '; + var html3 = ' ' + + ' ' + + ' ' + + ' '; + + $.ajax({ + type: "GET", + url: caramel.context + "/controllers/healthStatistics/healthStatistics_getrequest.jag", + dataType: 'json', + data: {"formtype": buttonName, "idValue": idValue, "chartType": chartType, "duration": buttonId}, + success: function (data) { + + if ('error' != data.status) { + + if ('InFlight' == buttonName) { + + $('#lineChartSVGchart3').empty(); + $('#container3').empty(); + $('#container3').append(html3); + jsonDataFlightRequest = data; + generalChart('chart3', jsonDataFlightRequest, buttonName); + + } + else if ('LoadAverage' == buttonName) { + $('#lineChartSVGchart2').empty(); + $('#container2').empty(); + $('#container2').append(html2); + jsonDataLoadAvg = data; + generalChart('chart2', jsonDataLoadAvg, buttonName); + } + else { + $('#lineChartSVGchart1').empty(); + $('#container1').empty(); + $('#container1').append(html1); + jsonDataMemoryAvg = data; + generalChart('chart1', jsonDataMemoryAvg, buttonName); + } + + } else { + //print error message in any case. + var n = noty({text: data.message, layout: 'bottomRight', type: 'error'}); + } + } + }).always(function () { + }); + + } + + //body onload function will trigger when the page loads + function bodyOnLoad() { + + var buttonNames; + var chartType = $('#chartType').val(); + if ("Cluster" != chartType) { + + buttonNames = ["LoadAverage", "MemoryConsumption"]; + + } else { + + buttonNames = ["InFlight", "LoadAverage", "MemoryConsumption"]; + } + + buttonNames.forEach(function (entry) { + initialLoad(entry, chartType); + }); + + } + + //initialy acalling to the REST API and get data for the chart + function initialLoad(buttonName, chartType) { + + var idValue = $('#IdValue').val(); + var buttonId = "1Hour"; + restCaller(buttonName, idValue, chartType, buttonId); + + } + + + function generalChart(chart, dataset, buttonName) { + + var elementId = chart; + var dataChart; + var drawchart; + + if ('InFlight' != buttonName) { + + if ('LoadAverage' == buttonName) { + dataChart = "data.memberAverageLoadAverage"; + drawchart = "d.memberAverageLoadAverage"; + + } else { + dataChart = "data.memberAverageMemoryConsumption"; + drawchart = "d.memberAverageMemoryConsumption"; + } + } else { + dataChart = "data.inFlightRequestCount"; + drawchart = "d.inFlightRequestCount"; + } + + function drawLineChart(elementId, data) { + + // data manipulation first + data.forEach(function (data) { + data.timeStamp = new Date(data.timeStamp); + }); + + // TODO code duplication check how you can avoid that + var containerEl = document.getElementById(elementId), + width = containerEl.clientWidth, + height = width * 0.4, + margin = { + top: 30, + right: 10, + left: 10 + }, + + detailWidth = 98, + detailHeight = 55, + detailMargin = 10, + + container = d3.select(containerEl), + svg = container.select('svg') + .attr('width', width) + .attr('height', height + margin.top), + + x = d3.time.scale().range([0, width - detailWidth]), + xAxis = d3.svg.axis().scale(x) + .ticks(8) + .tickSize(-height), + xAxisTicks = d3.svg.axis().scale(x) + .ticks(16) + .tickSize(-height) + .tickFormat(''), + y = d3.scale.linear().range([height, 0]), + yAxisTicks = d3.svg.axis().scale(y) + .ticks(12) + .tickSize(width) + .tickFormat('') + .orient('right'), + + area = d3.svg.area() + .interpolate('linear') + .x(function (d) { + return x(d.timeStamp) + detailWidth / 2; + }) + .y0(height) + .y1(function (d) { + return y(eval(drawchart)); + }), + + line = d3.svg.line() + .interpolate('linear') + .x(function (d) { + return x(d.timeStamp) + detailWidth / 2; + }) + .y(function (d) { + return y(eval(drawchart)); + }), + + startData = data.map(function (datum) { + return { + timeStamp: datum.timeStamp, + value: 0 + }; + }), + + circleContainer; + + // Compute the minimum and maximum date, and the maximum price. + x.domain([data[0].timeStamp, data[data.length - 1].timeStamp]); + // hacky hacky hacky :( + y.domain([0, d3.max(data, function (d) { + return eval(drawchart); + }) + 100]); + + svg.append('g') + .attr('class', 'lineChart--xAxisTicks') + .attr('transform', 'translate(' + detailWidth / 2 + ',' + height + ')') + .call(xAxisTicks); + + svg.append('g') + .attr('class', 'lineChart--xAxis') + .attr('transform', 'translate(' + detailWidth / 2 + ',' + ( height + 7 ) + ')') + .call(xAxis); + + svg.append('g') + .attr('class', 'lineChart--yAxisTicks') + .call(yAxisTicks); + + // Add the line path. + svg.append('path') + .data(startData) + .attr('class', 'lineChart--areaLine') + .attr('d', line) + .transition() + .duration(DURATION) + .delay(DURATION / 2) + .attrTween('d', tween(data, line)) + .each('end', function () { + drawCircles(data); + }); + + // Add the area path. + svg.append('path') + .data(startData) + .attr('class', 'lineChart--area') + .attr('d', area) + .transition() + .duration(DURATION) + .attrTween('d', tween(data, area)); + + // Helper functions!!! + function drawCircle(datum, index) { + circleContainer.datum(datum) + .append('circle') + .attr('class', 'lineChart--circle') + .attr('r', 0) + .attr( + 'cx', + function (d) { + return x(d.timeStamp) + detailWidth / 2; + } + ) + .attr( + 'cy', + function (d) { + return y(eval(drawchart)); + } + ) + .on('mouseenter', function (d) { + d3.select(this) + .attr( + 'class', + 'lineChart--circle lineChart--circle__highlighted' + ) + .attr('r', 2.5); + + d.active = true; + + showCircleDetail(d); + }) + .on('mouseout', function (d) { + d3.select(this) + .attr( + 'class', + 'lineChart--circle' + ) + .attr('r', 2.5); + + if (d.active) { + hideCircleDetails(); + + d.active = false; + } + }) + .on('click touch', function (d) { + if (d.active) { + showCircleDetail(d) + } else { + hideCircleDetails(); + } + }) + .transition() + .delay(DURATION / 10 * index) + .attr('r', 2.5); + } + + function drawCircles(data) { + circleContainer = svg.append('g'); + + data.forEach(function (datum, index) { + drawCircle(datum, index); + }); + } + + function hideCircleDetails() { + circleContainer.selectAll('.lineChart--bubble') + .remove(); + } + + function showCircleDetail(data) { + var details = circleContainer.append('g') + .attr('class', 'lineChart--bubble') + .attr( + 'transform', + function () { + var result = 'translate('; + + result += x(data.timeStamp); + result += ', '; + result += y(eval(dataChart)) - detailHeight - detailMargin; + result += ')'; + + return result; + } + ); + + details.append('path') + .attr('d', 'm-39.44921,-1c-3.16445,0 -5.72969,1.3422 -5.72969,2.999l0,44.6691c0,1.6562 2.56211,2.999 5.73146,2.999l79.09031,0c8.72469,3.7228 0.11021,-0.0614 8.76815,3.8017c8.44014,-3.7725 0.00888,-0.0325 8.59819,-3.8017l79.25048,0c3.17049,0 5.74033,-1.3422 5.74033,-2.999l0,-44.6691c0,-1.6563 -2.57506,-2.999 -5.72989,-2.999l-175.71924,0l0,0l0,0l0,0l0,0l-0.0001,0zm0,0') + .attr('width', detailWidth) + .attr('height', detailHeight); + + var text = details.append('text') + .attr('class', 'lineChart--bubble--text'); + + var date = new Date(data.timeStamp); + + var text = details.append('text') + .attr('class', 'lineChart--bubble--text'); + text.append('tspan') + .attr('class', 'lineChart--bubble--label') + .attr('x', detailWidth / 2) + .attr('y', detailHeight / 3) + .attr('text-anchor', 'middle') + .text(timeConverter(date)); + + text.append('tspan') + .attr('class', 'lineChart--bubble--value') + .attr('x', detailWidth / 2) + .attr('y', detailHeight / 4 * 3) + .attr('text-anchor', 'middle') + .text(eval(dataChart)); + } + + } + + var data = dataset; + drawLineChart(elementId, data); + } + + //time converter funtion returns the time in human readble manner + function timeConverter(timestamp) { + + var string = String(timestamp); + var numb = string.indexOf("("); + var timeUTC = string.substring(0, numb); + + return timeUTC; + } + + function tween(b, callback) { + return function (a) { + var i = d3.interpolateArray(a, b); + + return function (t) { + return callback(i(t)); + }; + }; + b = string.indexOf("("); + var timeUTC = string.substring(0, numb); + + return timeUTC; + } + + function tween(b, callback) { + return function (a) { + var i = d3.interpolateArray(a, b); + + return function (t) { + return callback(i(t)); + }; + }; + } + diff --git a/components/org.apache.stratos.manager.console/console/themes/theme0/js/jquery.contextMenu/jquery.contextMenu.js b/components/org.apache.stratos.manager.console/console/themes/theme0/js/jquery.contextMenu/jquery.contextMenu.js old mode 100755 new mode 100644 diff --git a/components/org.apache.stratos.manager.console/console/themes/theme0/js/jquery.contextMenu/jquery.ui.position.js b/components/org.apache.stratos.manager.console/console/themes/theme0/js/jquery.contextMenu/jquery.ui.position.js old mode 100755 new mode 100644 diff --git a/components/org.apache.stratos.manager.console/console/themes/theme0/partials/applications_topology.hbs b/components/org.apache.stratos.manager.console/console/themes/theme0/partials/applications_topology.hbs index 72300bc581..53b0f74fc1 100644 --- a/components/org.apache.stratos.manager.console/console/themes/theme0/partials/applications_topology.hbs +++ b/components/org.apache.stratos.manager.console/console/themes/theme0/partials/applications_topology.hbs @@ -88,6 +88,7 @@