diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
index 34c9a84..5590f95 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
@@ -8,10 +8,81 @@
</tr>
<tr>
<td>Server Time</td>
- <td>{{serverInfo.serverTime}} (<a data-ng-click="serverInfoUpdate()">update</a>)</td>
+ <td>{{serverInfo.serverTime}} (<a style="cursor: pointer" data-ng-click="serverInfoUpdate()">update</a>)</td>
+ </tr>
+ <tr>
+ <td>Server Uptime</td>
+ <td>{{serverInfo.serverUptime}}</td>
+ </tr>
+ <tr>
+ <td>Current Working Directory</td>
+ <td>{{serverInfo.systemInfo.userDir}}</td>
+ </tr>
+ <tr>
+ <td>Java Version</td>
+ <td>{{serverInfo.systemInfo.javaVersion}}</td>
+ </tr>
+ <tr>
+ <td>Java Vendor</td>
+ <td>{{serverInfo.systemInfo.javaVendor}}</td>
+ </tr>
+ <tr>
+ <td>Java Runtime</td>
+ <td>{{serverInfo.systemInfo.javaRuntime}}</td>
+ </tr>
+ <tr>
+ <td>Java VM</td>
+ <td>{{serverInfo.systemInfo.javaVm}}</td>
+ </tr>
+ <tr>
+ <td>Java VM Version</td>
+ <td>{{serverInfo.systemInfo.javaVmVersion}}</td>
+ </tr>
+ <tr>
+ <td>Java Home</td>
+ <td>{{serverInfo.systemInfo.javaHome}}</td>
+ </tr>
+ <tr>
+ <td>User Name</td>
+ <td>{{serverInfo.systemInfo.userName}}</td>
+ </tr>
+ <tr>
+ <td>User Timezone</td>
+ <td>{{serverInfo.systemInfo.userTimezone}}</td>
+ </tr>
+ <tr>
+ <td>User Locale</td>
+ <td>{{serverInfo.systemInfo.userLocale}}</td>
+ </tr>
+ <tr>
+ <td>System Encoding</td>
+ <td>{{serverInfo.systemInfo.fileEncoding}}</td>
+ </tr>
+ <tr>
+ <td>Operating System</td>
+ <td>{{serverInfo.systemInfo.osName}} {{serverInfo.systemInfo.osVersion}}</td>
+ </tr>
+ <tr>
+ <td>OS Architecture</td>
+ <td>{{serverInfo.systemInfo.osArchitecture}}</td>
</tr>
</table>
-
+
+ <h3>Java VM Memory Statistics</h3>
+ <table class="table table-striped table-bordered">
+ <tr>
+ <td>Total Memory</td>
+ <td>{{serverInfo.memoryInfo.totalFormated}}</td>
+ </tr>
+ <tr>
+ <td>Free Memory</td>
+ <td>{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)</td>
+ </tr>
+ <tr>
+ <td>Used Memory</td>
+ <td>{{serverInfo.memoryInfo.usedFormated}}</td>
+ </tr>
+ </table>
<fieldset>
<legend collapsed>Providers</legend>
diff --git a/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java b/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java
index cbb3da2..8266550 100755
--- a/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java
+++ b/model/api/src/main/java/org/keycloak/models/KeycloakSessionFactory.java
@@ -18,6 +18,8 @@ public interface KeycloakSessionFactory extends ProviderEventManager {
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id);
List<ProviderFactory> getProviderFactories(Class<? extends Provider> clazz);
+
+ long getServerStartupTimestamp();
void close();
}
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
index e312aa0..c5be21b 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
@@ -28,6 +28,8 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
private Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoriesMap = new HashMap<Class<? extends Provider>, Map<String, ProviderFactory>>();
protected CopyOnWriteArrayList<ProviderEventListener> listeners = new CopyOnWriteArrayList<ProviderEventListener>();
+ protected long serverStartupTimestamp;
+
@Override
public void register(ProviderEventListener listener) {
listeners.add(listener);
@@ -46,6 +48,8 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
}
public void init() {
+ serverStartupTimestamp = System.currentTimeMillis();
+
ProviderManager pm = new ProviderManager(getClass().getClassLoader(), Config.scope().getArray("providers"));
for (Spi spi : ServiceLoader.load(Spi.class, getClass().getClassLoader())) {
@@ -148,4 +152,12 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
return factory.getClass().getPackage().getName().startsWith("org.keycloak");
}
+ /**
+ * @return timestamp of Keycloak server startup
+ */
+ @Override
+ public long getServerStartupTimestamp() {
+ return serverStartupTimestamp;
+ }
+
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
index 4f1c225..c600b92 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
@@ -1,5 +1,18 @@
package org.keycloak.services.resources.admin;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.core.Context;
+
import org.keycloak.Version;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
@@ -24,17 +37,6 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
import org.keycloak.social.SocialIdentityProvider;
-import javax.ws.rs.GET;
-import javax.ws.rs.core.Context;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.ServiceLoader;
-import java.util.Set;
-
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@@ -55,6 +57,7 @@ public class ServerInfoAdminResource {
ServerInfoRepresentation info = new ServerInfoRepresentation();
info.version = Version.VERSION;
info.serverTime = new Date().toString();
+ info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp();
setSocialProviders(info);
setIdentityProviders(info);
setThemes(info);
@@ -187,12 +190,115 @@ public class ServerInfoAdminResource {
info.clientImporters.add(data);
}
}
+
+ public static class MemoryInfo{
+
+ public long getTotal(){
+ return Runtime.getRuntime().maxMemory();
+ }
+
+ public String getTotalFormated(){
+ return formatMemory(getTotal());
+ }
+
+ public long getFree(){
+ return getTotal() - getUsed();
+ }
+
+ public String getFreeFormated(){
+ return formatMemory(getFree());
+ }
+
+ public long getUsed(){
+ return Runtime.getRuntime().totalMemory();
+ }
+
+ public String getUsedFormated(){
+ return formatMemory(getUsed());
+ }
+
+ public long getFreePercentage(){
+ return getFree()*100/getTotal();
+ }
+
+ private String formatMemory(long bytes){
+ if(bytes > 1024L*1024L){
+ return bytes/(1024L *1024L) + " MB";
+ } else if(bytes > 1024L){
+ return bytes/(1024L) + " kB";
+ } else {
+ return bytes + " B";
+ }
+ }
+
+ }
+ public static class SystemInfo {
+ public String getJavaVersion(){
+ return System.getProperty("java.version");
+ }
+
+ public String getJavaVendor(){
+ return System.getProperty("java.vendor");
+ }
+
+ public String getJavaVm(){
+ return System.getProperty("java.vm.name");
+ }
+
+ public String getJavaVmVersion(){
+ return System.getProperty("java.vm.version");
+ }
+
+ public String getJavaRuntime(){
+ return System.getProperty("java.runtime.name");
+ }
+
+ public String getJavaHome(){
+ return System.getProperty("java.home");
+ }
+
+ public String getOsName(){
+ return System.getProperty("os.name");
+ }
+
+ public String getOsArchitecture(){
+ return System.getProperty("os.arch");
+ }
+
+ public String getOsVersion(){
+ return System.getProperty("os.version");
+ }
+
+ public String getFileEncoding(){
+ return System.getProperty("file.encoding");
+ }
+
+ public String getUserName(){
+ return System.getProperty("user.name");
+ }
+
+ public String getUserDir(){
+ return System.getProperty("user.dir");
+ }
+
+ public String getUserTimezone(){
+ return System.getProperty("user.timezone");
+ }
+
+ public String getUserLocale(){
+ return (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString());
+ }
+
+ }
+
public static class ServerInfoRepresentation {
private String version;
private String serverTime;
+
+ private long serverStartupTime;
private Map<String, List<String>> themes;
@@ -211,10 +317,55 @@ public class ServerInfoAdminResource {
public ServerInfoRepresentation() {
}
+
+ public SystemInfo getSystemInfo(){
+ return new SystemInfo();
+ }
+
+ public MemoryInfo getMemoryInfo(){
+ return new MemoryInfo();
+ }
public String getServerTime() {
return serverTime;
}
+
+ /**
+ * @return server startup time formatted
+ */
+ public String getServerStartupTime() {
+ return (new Date(serverStartupTime)).toString();
+ }
+
+ /**
+ * @return server uptime in millis
+ */
+ public long getServerUptimeMillis(){
+ return System.currentTimeMillis() - serverStartupTime;
+ }
+
+ /**
+ * @return server uptime formatted like "0 days, 10 hours, 24 minutes, 55 seconds"
+ */
+ public String getServerUptime(){
+ long diffInSeconds = getServerUptimeMillis()/1000;
+ long diff[] = new long[] { 0, 0, 0, 0 };
+ /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
+ /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
+ /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
+ /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24));
+
+ return String.format(
+ "%d day%s, %d hour%s, %d minute%s, %d second%s",
+ diff[0],
+ diff[0] != 1 ? "s" : "",
+ diff[1],
+ diff[1] != 1 ? "s" : "",
+ diff[2],
+ diff[2] != 1 ? "s" : "",
+ diff[3],
+ diff[3] != 1 ? "s" : "");
+ }
public String getVersion() {
return version;