diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/model/status/FacterData.java b/jans-config-api/common/src/main/java/io/jans/configapi/model/status/FacterData.java
new file mode 100644
index 00000000000..08efa23e844
--- /dev/null
+++ b/jans-config-api/common/src/main/java/io/jans/configapi/model/status/FacterData.java
@@ -0,0 +1,110 @@
+package io.jans.configapi.model.status;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({ "memoryfree", "swapfree", "hostname", "ipaddress", "uptime", "free_disk_space", "load_average" })
+public class FacterData {
+
+ @JsonProperty("memoryfree")
+ private String memoryfree;
+
+ @JsonProperty("swapfree")
+ private String swapfree;
+
+ @JsonProperty("hostname")
+ private String hostname;
+
+ @JsonProperty("ipaddress")
+ private String ipaddress;
+
+ @JsonProperty("uptime")
+ private String uptime;
+
+ @JsonProperty("free_disk_space")
+ private String freeDiskSpace;
+
+ @JsonProperty("load_average")
+ private String loadAverage;
+
+
+ @JsonProperty("memoryfree")
+ public String getMemoryfree() {
+ return memoryfree;
+ }
+
+ @JsonProperty("memoryfree")
+ public void setMemoryfree(String memoryfree) {
+ this.memoryfree = memoryfree;
+ }
+
+ @JsonProperty("swapfree")
+ public String getSwapfree() {
+ return swapfree;
+ }
+
+ @JsonProperty("swapfree")
+ public void setSwapfree(String swapfree) {
+ this.swapfree = swapfree;
+ }
+
+ @JsonProperty("hostname")
+ public String getHostname() {
+ return hostname;
+ }
+
+ @JsonProperty("hostname")
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ @JsonProperty("ipaddress")
+ public String getIpaddress() {
+ return ipaddress;
+ }
+
+ @JsonProperty("ipaddress")
+ public void setIpaddress(String ipaddress) {
+ this.ipaddress = ipaddress;
+ }
+
+ @JsonProperty("uptime")
+ public String getUptime() {
+ return uptime;
+ }
+
+ @JsonProperty("uptime")
+ public void setUptime(String uptime) {
+ this.uptime = uptime;
+ }
+
+ @JsonProperty("free_disk_space")
+ public String getFreeDiskSpace() {
+ return freeDiskSpace;
+ }
+
+ @JsonProperty("free_disk_space")
+ public void setFreeDiskSpace(String freeDiskSpace) {
+ this.freeDiskSpace = freeDiskSpace;
+ }
+
+ @JsonProperty("load_average")
+ public String getLoadAverage() {
+ return loadAverage;
+ }
+
+ @JsonProperty("load_average")
+ public void setLoadAverage(String loadAverage) {
+ this.loadAverage = loadAverage;
+ }
+
+ @Override
+ public String toString() {
+ return "FacterData [memoryfree=" + memoryfree + ", swapfree=" + swapfree + ", hostname=" + hostname
+ + ", ipaddress=" + ipaddress + ", uptime=" + uptime + ", freeDiskSpace=" + freeDiskSpace
+ + ", loadAverage=" + loadAverage + "]";
+ }
+
+}
diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/model/status/StatsData.java b/jans-config-api/common/src/main/java/io/jans/configapi/model/status/StatsData.java
new file mode 100644
index 00000000000..4f490ecd3a1
--- /dev/null
+++ b/jans-config-api/common/src/main/java/io/jans/configapi/model/status/StatsData.java
@@ -0,0 +1,51 @@
+package io.jans.configapi.model.status;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+import java.util.Date;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({ "dbType", "lastUpdate", "facterData", })
+public class StatsData {
+
+ @JsonProperty("dbType")
+ private String dbType;
+
+ @JsonProperty("lastUpdate")
+ private Date lastUpdate;
+
+ @JsonProperty("facterData")
+ private FacterData facterData;
+
+ public String getDbType() {
+ return dbType;
+ }
+
+ public void setDbType(String dbType) {
+ this.dbType = dbType;
+ }
+
+ public Date getLastUpdate() {
+ return lastUpdate;
+ }
+
+ public void setLastUpdate(Date lastUpdate) {
+ this.lastUpdate = lastUpdate;
+ }
+
+ public FacterData getFacterData() {
+ return facterData;
+ }
+
+ public void setFacterData(FacterData facterData) {
+ this.facterData = facterData;
+ }
+
+ @Override
+ public String toString() {
+ return "StatsData [dbType=" + dbType + ", lastUpdate=" + lastUpdate + ", facterData=" + facterData + "]";
+ }
+
+}
diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java
index 12ed4df02f4..4750279214e 100644
--- a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java
+++ b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java
@@ -72,6 +72,7 @@ private ApiConstants() {}
public static final String STATISTICS = "/stat";
public static final String USER = "/user";
public static final String ORG = "/org";
+ public static final String SERVER_STAT = "/server-stat";
public static final String LIMIT = "limit";
public static final String START_INDEX = "startIndex";
diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml
index fc03609f072..979f43deeb4 100644
--- a/jans-config-api/docs/jans-config-api-swagger.yaml
+++ b/jans-config-api/docs/jans-config-api-swagger.yaml
@@ -33,6 +33,7 @@ tags:
- name: OAuth - Scopes
- name: Statistics - User
- name: Health - Check
+ - name: Server Stats
- name: SCIM - User Management
- name: SCIM - Config Management
- name: Organization Configuration
@@ -2378,6 +2379,23 @@ paths:
$ref: '#/components/schemas/HealthStatusItem'
'500':
description: Internal Server Error
+
+ /jans-config-api/api/v1/health/server-stat:
+ get:
+ summary: Returns application server status.
+ description: Returns application server status.
+ operationId: get-server-stat
+ tags:
+ - Server Stats
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/StatsData'
+ '500':
+ description: Internal Server Error
/jans-config-api/scim/user:
get:
@@ -2807,7 +2825,7 @@ paths:
$ref: '#/components/schemas/ErrorResponse'
security:
- oauth2: [https://jans.io/oauth/config/scim/users.read https://jans.io/scim/users.read]
-
+
/jans-config-api/scim/config:
get:
summary: Retrieves SCIM App configuration.
@@ -2860,7 +2878,7 @@ paths:
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
-
+
/jans-config-api/api/v1/org:
get:
summary: Retrieves organization configuration.
@@ -2913,7 +2931,7 @@ paths:
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/InternalServerError'
-
+
/jans-config-api/api/v1/jans-auth-server/health:
get:
summary: Returns auth server health status.
@@ -6598,7 +6616,7 @@ components:
useLocalCache:
type: boolean
description: Boolean value specifying whether to enable local in-memory cache.
-
+
Organization:
type: object
properties:
@@ -6640,5 +6658,46 @@ components:
jsFaviconPath:
type: string
description: Path to organization favicon image
+
+
+ FacterData:
+ type: object
+ properties:
+ memoryfree:
+ type: string
+ description: Server free memory
+ swapfree:
+ type: string
+ description: Server swap free
+ hostname:
+ type: string
+ description: Server hostname
+ ipaddress:
+ type: string
+ description: Server ipaddress
+ uptime:
+ type: string
+ description: Server uptime
+ free_disk_space:
+ type: string
+ description: Server free disk space
+ load_average:
+ type: string
+ description: Server average load time
+
+
+ StatsData:
+ type: object
+ properties:
+ dbType:
+ type: string
+ description: Jans Server DB type
+ lastUpdate:
+ type: string
+ description: Stats update time
+ facterData:
+ type: object
+ $ref: '#/components/schemas/FacterData'
+ description: Underlying Server stats
-
+
diff --git a/jans-config-api/profiles/local/test.properties b/jans-config-api/profiles/local/test.properties
index 3109daa325e..7f7fff14b15 100644
--- a/jans-config-api/profiles/local/test.properties
+++ b/jans-config-api/profiles/local/test.properties
@@ -39,11 +39,11 @@ test.scopes=https://jans.io/oauth/config/acrs.readonly https://jans.io/oauth/con
#test.issuer=https:// pujavs.jans.server3
# jans.server1
-token.endpoint=https://jans.server1/jans-auth/restv1/token
-token.grant.type=client_credentials
-test.client.id=1800.ba5c72a0-733c-44e9-82fb-9c710e4e7408
-test.client.secret=EcBbZAVoH8gr
-test.issuer=https://jans.server1
+#token.endpoint=https://jans.server1/jans-auth/restv1/token
+#token.grant.type=client_credentials
+#test.client.id=1800.df97feac-c94e-468d-9e22-48946da45403
+#test.client.secret=OL13IYRG0IjV
+#test.issuer=https://jans.server1
# jans.server2
#token.endpoint=https://jans.server2/jans-auth/restv1/token
@@ -59,3 +59,11 @@ test.issuer=https://jans.server1
#test.client.secret=aDiH4IuuGddZ
#test.issuer=https://jans.server3
+# jans.server4
+token.endpoint=https://jans.server4/jans-auth/restv1/token
+token.grant.type=client_credentials
+test.client.id=1800.7e78990f-fdae-40e9-9433-4fe20645851d
+test.client.secret=GfUrIapPM71X
+test.issuer=https://jans.server4
+
+
diff --git a/jans-config-api/server/pom.xml b/jans-config-api/server/pom.xml
index cac37a65a17..0211df5ec7d 100644
--- a/jans-config-api/server/pom.xml
+++ b/jans-config-api/server/pom.xml
@@ -201,6 +201,12 @@
${jetty.version}
+
+
+ org.gluufederation
+ jython-standalone
+
+
diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java b/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java
index b718e709869..a5c2d72497e 100644
--- a/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java
+++ b/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java
@@ -10,6 +10,8 @@
import io.jans.configapi.security.api.ApiProtectionService;
import io.jans.configapi.security.service.AuthorizationService;
import io.jans.configapi.security.service.OpenIdAuthorizationService;
+import io.jans.configapi.service.status.StatusCheckerTimer;
+import io.jans.configapi.service.logger.LoggerService;
import io.jans.exception.ConfigurationException;
import io.jans.exception.OxIntializationException;
import io.jans.orm.PersistenceEntryManager;
@@ -62,14 +64,20 @@ public class AppInitializer {
@Inject
private Instance authorizationServiceInstance;
-
-
+
+ @Inject
+ StatusCheckerTimer statusCheckerTimer;
+
+ @Inject
+ private LoggerService loggerService;
+
@Inject
private QuartzSchedulerManager quartzSchedulerManager;
public void onStart(@Observes @Initialized(ApplicationScoped.class) Object init) {
log.info("========================== Initializing - App =======================================");
log.info("============= STARTING API APPLICATION ========================");
+ log.info("init:{}",init);
System.setProperty(ResteasyContextParameters.RESTEASY_PATCH_FILTER_DISABLED, "true");
this.configurationFactory.create();
persistenceEntryManagerInstance.get();
@@ -77,7 +85,13 @@ public void onStart(@Observes @Initialized(ApplicationScoped.class) Object init)
// Start timer
initSchedulerService();
+
+ // Stats timer
+ statusCheckerTimer.initTimer();
+ // Schedule timer tasks
+ loggerService.initTimer();
+
ResteasyProviderFactory instance = ResteasyProviderFactory.getInstance();
RegisterBuiltin.register(instance);
instance.registerProvider(ResteasyJackson2Provider.class);
@@ -89,6 +103,7 @@ public void onStart(@Observes @Initialized(ApplicationScoped.class) Object init)
public void destroy(@Observes @BeforeDestroyed(ApplicationScoped.class) ServletContext init) {
log.info("================================================================");
log.info("=========== API APPLICATION STOPPED ==========================");
+ log.info("init:{}",init);
log.info("================================================================");
}
@@ -128,6 +143,7 @@ private AuthorizationService createAuthorizationService() {
configurationFactory.getApiClientId());
return authorizationServiceInstance.select(OpenIdAuthorizationService.class).get();
} catch (Exception ex) {
+ log.error("Failed to create AuthorizationService instance", ex);
throw new ConfigurationException("Failed to create AuthorizationService instance", ex);
}
}
@@ -136,8 +152,8 @@ public void recreatePersistanceEntryManager(@Observes @LdapConfigurationReload S
closePersistenceEntryManager();
PersistenceEntryManager ldapEntryManager = persistenceEntryManagerInstance.get();
persistenceEntryManagerInstance.destroy(ldapEntryManager);
- log.debug("Recreated instance {} with operation service: {}", ldapEntryManager,
- ldapEntryManager.getOperationService());
+ log.debug("Recreated instance {} with operation service: {} - event:{}", ldapEntryManager,
+ ldapEntryManager.getOperationService(), event);
}
private void closePersistenceEntryManager() {
@@ -153,6 +169,7 @@ private void closePersistenceEntryManager() {
}
protected void initSchedulerService() {
+ log.debug(" \n\n initSchedulerService - Entry \n\n");
quartzSchedulerManager.start();
String disableScheduler = System.getProperties().getProperty("gluu.disable.scheduler");
diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/health/ApiHealthCheck.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/health/ApiHealthCheck.java
index c89a683b30c..c9ff46d3468 100644
--- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/health/ApiHealthCheck.java
+++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/health/ApiHealthCheck.java
@@ -6,6 +6,7 @@
package io.jans.configapi.rest.health;
+import io.jans.configapi.model.status.StatsData;
import io.jans.configapi.rest.resource.auth.BaseResource;
import io.jans.configapi.service.auth.ConfigurationService;
import io.jans.configapi.util.ApiConstants;
@@ -17,29 +18,32 @@
import org.json.JSONObject;
import org.json.JSONArray;
+
import org.slf4j.Logger;
@Path(ApiConstants.HEALTH)
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class ApiHealthCheck extends BaseResource {
-
+
@Inject
- Logger log;
+ Logger logger;
+ private static final String STATUS = "status";
+
@Inject
ConfigurationService configurationService;
@GET
- public Response getHealthResponse() throws Exception {
- log.debug("ApiHealthCheck::getHealthResponse() - Entry");
+ public Response getHealthResponse() {
+ logger.debug("Api Health Check - Entry");
JSONObject jsonObject = new JSONObject();
- jsonObject.put("status", "UP");
+ jsonObject.put(STATUS, "UP");
// liveness
JSONObject dataJsonObject = new JSONObject();
dataJsonObject.put("name", "jans-config-api liveness");
- dataJsonObject.put("status", "UP");
+ dataJsonObject.put(STATUS, "UP");
JSONArray jsonArray = new JSONArray();
jsonArray.put(0, dataJsonObject);
@@ -48,50 +52,60 @@ public Response getHealthResponse() throws Exception {
dataJsonObject.put("name", "jans-config-api readiness");
try {
checkDatabaseConnection();
- dataJsonObject.put("status", "UP");
+ dataJsonObject.put(STATUS, "UP");
} catch (Exception e) {
- log.error(e.getMessage(), e);
- dataJsonObject.put("status", "DOWN");
+ logger.error(e.getMessage(), e);
+ dataJsonObject.put(STATUS, "DOWN");
dataJsonObject.put("error", "e.getMessage()");
- log.debug("\n\n\n ApiHealthCheck::getHealthResponse() - Error Response = " + jsonObject + "\n\n");
+ logger.debug("Api Health Check - Error - jsonObject:{}",jsonObject);
}
jsonArray.put(1, dataJsonObject);
jsonObject.put("checks", jsonArray);
- log.debug("\n\n\n ApiHealthCheck::getHealthResponse() - jsonObject = " + jsonObject + "\n\n");
+ logger.debug("ApiHealthCheck::getHealthResponse() - jsonObject:{}",jsonObject);
return Response.ok(jsonObject.toString()).build();
}
@GET
@Path(ApiConstants.LIVE)
public Response getLivenessResponse() {
- log.debug("ApiHealthCheck::getLivenessResponse() - Entry");
+ logger.debug("ApiHealthCheck::getLivenessResponse() - Entry");
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "jans-config-api liveness");
- jsonObject.put("status", "UP");
- log.debug("\n\n\n ApiHealthCheck::getLivenessResponse() - jsonObject = " + jsonObject + "\n\n");
+ jsonObject.put(STATUS, "UP");
+ logger.debug("ApiHealthCheck::getLivenessResponse() - jsonObject:{}",jsonObject);
return Response.ok(jsonObject.toString()).build();
}
@GET
@Path(ApiConstants.READY)
public Response getReadinessResponse() {
- log.debug("ApiHealthCheck::getReadinessResponse() - Entry");
+ logger.debug("ApiHealthCheck::getReadinessResponse() - Entry");
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "jans-config-api readiness");
try {
checkDatabaseConnection();
- jsonObject.put("status", "UP");
- log.debug("\n\n\n ApiHealthCheck::getReadinessResponse() - Success Response = " + jsonObject + "\n\n");
+ jsonObject.put(STATUS, "UP");
+ logger.debug("Api Health Readiness - Success - jsonObject:{}",jsonObject);
return Response.ok(jsonObject.toString()).build();
} catch (Exception e) {
- log.error(e.getMessage(), e);
+ logger.error(e.getMessage(), e);
jsonObject.put("error", "e.getMessage()");
- log.debug("\n\n\n ApiHealthCheck::getReadinessResponse() - Error Response = " + jsonObject + "\n\n");
+ logger.debug("Api Health Readiness - Error - jsonObject:{}",jsonObject);
return Response.ok(jsonObject.toString()).build();
}
}
+ @GET
+ @Path(ApiConstants.SERVER_STAT)
+ public Response getServerStat() {
+ logger.debug("Server Stat - Entry");
+ StatsData statsData = configurationService.getStatsData();
+ logger.debug("Server Stat - statsData:{}",statsData);
+ return Response.ok(statsData).build();
+
+ }
+
private void checkDatabaseConnection() {
configurationService.findConf();
}
diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java
index 06c3cbe8fae..e0adeef7026 100644
--- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java
+++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ConfigurationService.java
@@ -11,6 +11,7 @@
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.persistence.model.configuration.GluuConfiguration;
import io.jans.configapi.configuration.ConfigurationFactory;
+import io.jans.configapi.model.status.StatsData;
import io.jans.orm.PersistenceEntryManager;
import io.jans.util.StringHelper;
@@ -30,6 +31,8 @@ public class ConfigurationService {
@Inject
ConfigurationFactory configurationFactory;
+
+ private StatsData statsData;
public Conf findConf() {
final String dn = configurationFactory.getConfigurationDn();
@@ -61,4 +64,13 @@ public GluuConfiguration findGluuConfiguration() {
public String getPersistenceType() {
return configurationFactory.getBaseConfiguration().getString("persistence.type");
}
+
+ public StatsData getStatsData() {
+ return statsData;
+ }
+
+ public void setStatsData(StatsData statsData) {
+ this.statsData = statsData;
+ }
+
}
diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/cdi/event/StatusCheckerTimerEvent.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/cdi/event/StatusCheckerTimerEvent.java
new file mode 100644
index 00000000000..400e51a0f85
--- /dev/null
+++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/cdi/event/StatusCheckerTimerEvent.java
@@ -0,0 +1,14 @@
+/*
+ * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
+ *
+ * Copyright (c) 2020, Janssen Project
+ */
+
+package io.jans.configapi.service.cdi.event;
+
+public class StatusCheckerTimerEvent {
+
+ public StatusCheckerTimerEvent() {}
+
+
+}
diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/logger/LoggerService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/logger/LoggerService.java
new file mode 100644
index 00000000000..66b9320a27c
--- /dev/null
+++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/logger/LoggerService.java
@@ -0,0 +1,35 @@
+package io.jans.configapi.service.logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import io.jans.configapi.model.configuration.ApiAppConfiguration;
+
+@ApplicationScoped
+public class LoggerService extends io.jans.service.logger.LoggerService {
+
+ @Inject
+ private ApiAppConfiguration appConfiguration;
+
+ @Override
+ public boolean isDisableJdkLogger() {
+ return (appConfiguration.getDisableJdkLogger() != null) && appConfiguration.getDisableJdkLogger();
+ }
+
+ @Override
+ public String getLoggingLevel() {
+ return appConfiguration.getLoggingLevel();
+ }
+
+ @Override
+ public String getExternalLoggerConfiguration() {
+ return appConfiguration.getExternalLoggerConfiguration();
+ }
+
+ @Override
+ public String getLoggingLayout() {
+ return appConfiguration.getLoggingLayout();
+ }
+
+}
+
diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/status/StatusCheckerTimer.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/status/StatusCheckerTimer.java
new file mode 100644
index 00000000000..02b9d70fe21
--- /dev/null
+++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/status/StatusCheckerTimer.java
@@ -0,0 +1,160 @@
+/*
+ * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
+ *
+ * Copyright (c) 2020, Janssen Project
+ */
+
+package io.jans.configapi.service.status;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Event;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.exec.CommandLine;
+import io.jans.configapi.model.status.StatsData;
+import io.jans.configapi.model.status.FacterData;
+import io.jans.util.process.ProcessHelper;
+
+import io.jans.configapi.configuration.ConfigurationFactory;
+import io.jans.configapi.service.auth.ConfigurationService;
+import io.jans.configapi.service.cdi.event.StatusCheckerTimerEvent;
+import io.jans.service.cdi.async.Asynchronous;
+import io.jans.service.cdi.event.BaseConfigurationReload;
+import io.jans.service.cdi.event.ConfigurationEvent;
+import io.jans.service.cdi.event.ConfigurationUpdate;
+import io.jans.service.cdi.event.LdapConfigurationReload;
+import io.jans.service.cdi.event.Scheduled;
+import io.jans.service.timer.event.TimerEvent;
+import io.jans.service.timer.schedule.TimerSchedule;
+import io.jans.util.StringHelper;
+import io.jans.util.properties.FileConfiguration;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import org.apache.commons.lang.StringUtils;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@ApplicationScoped
+@Named
+public class StatusCheckerTimer {
+
+ private static final int DEFAULT_INTERVAL = 5 * 60; // 1 minute
+ public static final String PROGRAM_FACTER = "facter";
+
+ @Inject
+ private Logger log;
+
+ @Inject
+ private Event timerEvent;
+
+ @Inject
+ private ConfigurationService configurationService;
+
+ @Inject
+ private ConfigurationFactory configurationFactory;
+
+ private AtomicBoolean isActive;
+
+ @PostConstruct
+ public void create() {
+ log.debug("Creating Status Cheker Timer");
+ }
+
+ public void initTimer() {
+ log.debug("Initializing Status Checker Timer");
+ this.isActive = new AtomicBoolean(false);
+
+ final int delay = 1 * 60;
+ final int interval = DEFAULT_INTERVAL;
+
+ timerEvent.fire(new TimerEvent(new TimerSchedule(delay, interval), new StatusCheckerTimerEvent(),
+ Scheduled.Literal.INSTANCE));
+ }
+
+ @Asynchronous
+ public void process(@Observes @Scheduled StatusCheckerTimerEvent statusCheckerTimerEvent) {
+ log.debug("Status Checker Timer Process");
+ if (this.isActive.get()) {
+ return;
+ }
+
+ if (!this.isActive.compareAndSet(false, true)) {
+ return;
+ }
+
+ try {
+ processInt();
+ } finally {
+ this.isActive.set(false);
+ }
+ }
+
+ /**
+ * Gather periodically site and server status
+ *
+ * @param when Date
+ * @param interval Interval
+ */
+ private void processInt() {
+ log.debug("Starting update of sever status");
+
+ StatsData statsData = new StatsData();
+ Date currentDateTime = new Date();
+ statsData.setLastUpdate(currentDateTime);
+ statsData.setFacterData(getFacterData());
+ statsData.setDbType(configurationService.getPersistenceType());
+
+ configurationService.setStatsData(statsData);
+ log.debug("Configuration status update finished");
+ }
+
+ private FacterData getFacterData() {
+ log.debug("Getting Server status");
+ FacterData facterData = new FacterData();
+ ObjectMapper mapper = new ObjectMapper();
+ if (!isLinux()) {
+ return facterData;
+ }
+ CommandLine commandLine = new CommandLine(PROGRAM_FACTER);
+ commandLine.addArgument("-j");
+ String resultOutput;
+ try (ByteArrayOutputStream bos = new ByteArrayOutputStream(4096);) {
+ boolean result = ProcessHelper.executeProgram(commandLine, false, 0, bos);
+ if (!result) {
+ return facterData;
+ }
+ resultOutput = new String(bos.toByteArray(), UTF_8);
+ facterData = mapper.readValue(resultOutput, FacterData.class);
+ } catch (UnsupportedEncodingException ex) {
+ log.error("Failed to parse program {} output", PROGRAM_FACTER, ex);
+ return facterData;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ log.debug("Server status - facterData:{}", facterData);
+ return facterData;
+ }
+
+ private boolean isLinux() {
+ String osName = System.getProperty("os.name");
+ return !StringHelper.isEmpty(osName) && osName.toLowerCase().contains("linux");
+ }
+}
diff --git a/jans-config-api/server/src/test/resources/feature/health/server-health.feature b/jans-config-api/server/src/test/resources/feature/health/server-health.feature
new file mode 100644
index 00000000000..4b7d44306a7
--- /dev/null
+++ b/jans-config-api/server/src/test/resources/feature/health/server-health.feature
@@ -0,0 +1,14 @@
+
+Feature: Verify Server stats
+
+Background:
+ * def mainUrl = healthUrl + "/server-stat"
+
+ Scenario: Verify Underlying server stats
+ Given url mainUrl
+ When method GET
+ Then status 200
+ And print response
+
+
+
\ No newline at end of file