keycloak-memoizeit
Changes
connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java 48(+12 -36)
connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java 4(+2 -2)
connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java 43(+10 -33)
connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java 4(+2 -2)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html 118(+53 -65)
services/pom.xml 15(+0 -15)
services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java 254(+3 -251)
Details
diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
index aac1cde..a79c82b 100755
--- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
+++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
@@ -6,20 +6,19 @@ import org.keycloak.Config;
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.provider.ProviderOperationalInfo;
import javax.naming.InitialContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.sql.DataSource;
-
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
/**
@@ -33,7 +32,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
private Config.Scope config;
- private DatabaseInfo databaseInfo;
+ private Map<String,String> operationalInfo;
@Override
public JpaConnectionProvider create(KeycloakSession session) {
@@ -127,7 +126,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
connection = getConnection();
try{
- prepareDatabaseInfo(connection);
+ prepareOperationalInfo(connection);
if (databaseSchema != null) {
logger.trace("Updating database");
@@ -180,16 +179,16 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
}
}
- protected void prepareDatabaseInfo(Connection connection) {
+ protected void prepareOperationalInfo(Connection connection) {
try {
- databaseInfo = new DatabaseInfo();
+ operationalInfo = new LinkedHashMap<>();
DatabaseMetaData md = connection.getMetaData();
- databaseInfo.databaseDriver = md.getDriverName() + " " + md.getDriverVersion();
- databaseInfo.databaseProduct = md.getDatabaseProductName() + " " + md.getDatabaseProductVersion();
- databaseInfo.databaseUser = md.getUserName();
- databaseInfo.jdbcUrl = md.getURL();
+ operationalInfo.put("databaseUrl",md.getURL());
+ operationalInfo.put("databaseUser", md.getUserName());
+ operationalInfo.put("databaseProduct", md.getDatabaseProductName() + " " + md.getDatabaseProductVersion());
+ operationalInfo.put("databaseDriver", md.getDriverName() + " " + md.getDriverVersion());
} catch (SQLException e) {
- logger.warn("Unable to get database info due " + e.getMessage());
+ logger.warn("Unable to prepare operational info due database exception: " + e.getMessage());
}
}
@@ -209,31 +208,8 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
}
@Override
- public DatabaseInfo getOperationalInfo() {
- return databaseInfo;
- }
-
- public static class DatabaseInfo implements ProviderOperationalInfo {
- protected String jdbcUrl;
- protected String databaseUser;
- protected String databaseProduct;
- protected String databaseDriver;
-
- public String getJdbcUrl() {
- return jdbcUrl;
- }
-
- public String getDatabaseDriver() {
- return databaseDriver;
- }
-
- public String getDatabaseUser() {
- return databaseUser;
- }
-
- public String getDatabaseProduct() {
- return databaseProduct;
- }
+ public Map<String,String> getOperationalInfo() {
+ return operationalInfo;
}
}
diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java
index ab2b119..288e403 100644
--- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java
+++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionProviderFactory.java
@@ -1,10 +1,10 @@
package org.keycloak.connections.jpa;
-import org.keycloak.provider.MonitorableProviderFactory;
+import org.keycloak.provider.ServerInfoAwareProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public interface JpaConnectionProviderFactory extends MonitorableProviderFactory<JpaConnectionProvider> {
+public interface JpaConnectionProviderFactory extends ServerInfoAwareProviderFactory<JpaConnectionProvider> {
}
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
index 2df4b85..8da15b6 100755
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
@@ -14,13 +14,13 @@ import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocati
import org.keycloak.connections.mongo.updater.MongoUpdaterProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.provider.ProviderOperationalInfo;
import javax.net.ssl.SSLSocketFactory;
-
import java.lang.reflect.Method;
import java.net.UnknownHostException;
import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -61,7 +61,7 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
private DB db;
protected Config.Scope config;
- private MongoDbInfo mongoDbInfo;
+ private Map<String,String> operationalInfo;
@Override
public MongoConnectionProvider create(KeycloakSession session) {
@@ -165,11 +165,11 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
client = new MongoClient(new ServerAddress(host, port), clientOptions);
}
- mongoDbInfo = new MongoDbInfo();
- mongoDbInfo.driverVersion = client.getVersion();
- mongoDbInfo.address = client.getAddress().toString();
- mongoDbInfo.database = dbName;
- mongoDbInfo.user = user;
+ operationalInfo = new LinkedHashMap<>();
+ operationalInfo.put("mongoServerAddress", client.getAddress().toString());
+ operationalInfo.put("mongoDatabaseName", dbName);
+ operationalInfo.put("mongoUser", user);
+ operationalInfo.put("mongoDriverVersion", client.getVersion());
logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName);
return client;
@@ -219,31 +219,8 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
}
@Override
- public ProviderOperationalInfo getOperationalInfo() {
- return mongoDbInfo;
+ public Map<String,String> getOperationalInfo() {
+ return operationalInfo;
}
- public static class MongoDbInfo implements ProviderOperationalInfo {
-
- public String address;
- public String database;
- public String driverVersion;
- public String user;
-
- public String getAddress() {
- return address;
- }
-
- public String getDatabase() {
- return database;
- }
-
- public String getDriverVersion() {
- return driverVersion;
- }
-
- public String getUser() {
- return user;
- }
- }
}
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java
index 3b3a00e..bce5fe4 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionProviderFactory.java
@@ -1,9 +1,9 @@
package org.keycloak.connections.mongo;
-import org.keycloak.provider.MonitorableProviderFactory;
+import org.keycloak.provider.ServerInfoAwareProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public interface MongoConnectionProviderFactory extends MonitorableProviderFactory<MongoConnectionProvider> {
+public interface MongoConnectionProviderFactory extends ServerInfoAwareProviderFactory<MongoConnectionProvider> {
}
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
index 8fb7c36..4f02ce6 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -1133,7 +1133,13 @@ module.config([ '$routeProvider', function($routeProvider) {
controller : 'AuthenticationConfigCreateCtrl'
})
.when('/server-info', {
- templateUrl : resourceUrl + '/partials/server-info.html'
+ templateUrl : resourceUrl + '/partials/server-info.html',
+ resolve : {
+ serverInfoPage : function(ServerInfoPageLoader) {
+ return ServerInfoPageLoader();
+ }
+ },
+ controller : 'ServerInfoPageCtrl'
})
.when('/logout', {
templateUrl : resourceUrl + '/partials/home.html',
@@ -1867,4 +1873,4 @@ module.directive( 'kcOpen', function ( $location ) {
});
});
};
-});
\ No newline at end of file
+});
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index 85ad18b..5c5e023 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -125,6 +125,13 @@ module.controller('RealmTabCtrl', function(Dialog, $scope, Current, Realm, Notif
};
});
+module.controller('ServerInfoPageCtrl', function($scope, ServerInfoPage) {
+ $scope.serverInfoPage = ServerInfoPage.get();
+ $scope.serverInfoPageUpdate = function() {
+ $scope.serverInfoPage = ServerInfoPage.get();
+ };
+});
+
module.controller('RealmListCtrl', function($scope, Realm, Current) {
$scope.realms = Realm.query();
Current.realms = $scope.realms;
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js
index 37a9566..2e65b3c 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js
@@ -39,6 +39,10 @@ module.factory('ServerInfoLoader', function(Loader, ServerInfo, $q) {
return Loader.get(ServerInfo);
});
+module.factory('ServerInfoPageLoader', function(Loader, ServerInfoPage, $q) {
+ return Loader.get(ServerInfoPage);
+});
+
module.factory('RealmLoader', function(Loader, Realm, $route, $q) {
return Loader.get(Realm, function() {
return {
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
index 3763ba9..b5d8c33 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -219,6 +219,9 @@ module.factory('ServerInfo', function($resource) {
return $resource(authUrl + '/admin/serverinfo');
});
+module.factory('ServerInfoPage', function($resource) {
+ return $resource(authUrl + '/admin/serverinfopage');
+});
module.factory('ClientProtocolMapper', function($resource) {
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 f4e4c6d..0dfac4c 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
@@ -4,15 +4,15 @@
<table class="table table-striped table-bordered">
<tr>
<td width="20%">Keycloak Version</td>
- <td>{{serverInfo.version}}</td>
+ <td>{{serverInfoPage.version}}</td>
</tr>
<tr>
<td>Server Time</td>
- <td>{{serverInfo.serverTime}} (<a style="cursor: pointer" data-ng-click="serverInfoUpdate()">update</a>)</td>
+ <td>{{serverInfoPage.serverTime}} (<a style="cursor: pointer" data-ng-click="serverInfoPageUpdate()">update</a>)</td>
</tr>
<tr>
<td>Server Uptime</td>
- <td>{{serverInfo.serverUptime}}</td>
+ <td>{{serverInfoPage.serverUptime}}</td>
</tr>
</table>
@@ -22,15 +22,15 @@
<table class="table table-striped table-bordered" style="margin-top: 0px;">
<tr>
<td width="20%">Total Memory</td>
- <td>{{serverInfo.memoryInfo.totalFormated}}</td>
+ <td>{{serverInfoPage.memoryInfo.totalFormated}}</td>
</tr>
<tr>
<td>Free Memory</td>
- <td>{{serverInfo.memoryInfo.freeFormated}} ({{serverInfo.memoryInfo.freePercentage}}%)</td>
+ <td>{{serverInfoPage.memoryInfo.freeFormated}} ({{serverInfoPage.memoryInfo.freePercentage}}%)</td>
</tr>
<tr>
<td>Used Memory</td>
- <td>{{serverInfo.memoryInfo.usedFormated}}</td>
+ <td>{{serverInfoPage.memoryInfo.usedFormated}}</td>
</tr>
</table>
</div>
@@ -42,109 +42,73 @@
<table class="table table-striped table-bordered" style="margin-top: 0px;">
<tr>
<td width="20%">Current Working Directory</td>
- <td>{{serverInfo.systemInfo.userDir}}</td>
+ <td>{{serverInfoPage.systemInfo.userDir}}</td>
</tr>
<tr>
<td>Java Version</td>
- <td>{{serverInfo.systemInfo.javaVersion}}</td>
+ <td>{{serverInfoPage.systemInfo.javaVersion}}</td>
</tr>
<tr>
<td>Java Vendor</td>
- <td>{{serverInfo.systemInfo.javaVendor}}</td>
+ <td>{{serverInfoPage.systemInfo.javaVendor}}</td>
</tr>
<tr>
<td>Java Runtime</td>
- <td>{{serverInfo.systemInfo.javaRuntime}}</td>
+ <td>{{serverInfoPage.systemInfo.javaRuntime}}</td>
</tr>
<tr>
<td>Java VM</td>
- <td>{{serverInfo.systemInfo.javaVm}}</td>
+ <td>{{serverInfoPage.systemInfo.javaVm}}</td>
</tr>
<tr>
<td>Java VM Version</td>
- <td>{{serverInfo.systemInfo.javaVmVersion}}</td>
+ <td>{{serverInfoPage.systemInfo.javaVmVersion}}</td>
</tr>
<tr>
<td>Java Home</td>
- <td>{{serverInfo.systemInfo.javaHome}}</td>
+ <td>{{serverInfoPage.systemInfo.javaHome}}</td>
</tr>
<tr>
<td>User Name</td>
- <td>{{serverInfo.systemInfo.userName}}</td>
+ <td>{{serverInfoPage.systemInfo.userName}}</td>
</tr>
<tr>
<td>User Timezone</td>
- <td>{{serverInfo.systemInfo.userTimezone}}</td>
+ <td>{{serverInfoPage.systemInfo.userTimezone}}</td>
</tr>
<tr>
<td>User Locale</td>
- <td>{{serverInfo.systemInfo.userLocale}}</td>
+ <td>{{serverInfoPage.systemInfo.userLocale}}</td>
</tr>
<tr>
<td>System Encoding</td>
- <td>{{serverInfo.systemInfo.fileEncoding}}</td>
+ <td>{{serverInfoPage.systemInfo.fileEncoding}}</td>
</tr>
<tr>
<td>Operating System</td>
- <td>{{serverInfo.systemInfo.osName}} {{serverInfo.systemInfo.osVersion}}</td>
+ <td>{{serverInfoPage.systemInfo.osName}} {{serverInfoPage.systemInfo.osVersion}}</td>
</tr>
<tr>
<td>OS Architecture</td>
- <td>{{serverInfo.systemInfo.osArchitecture}}</td>
+ <td>{{serverInfoPage.systemInfo.osArchitecture}}</td>
</tr>
</table>
</div>
</fieldset>
- <fieldset ng-show="serverInfo.jpaInfo">
+ <fieldset ng-show="serverInfoPage.jpaInfo">
<legend collapsed>Database Info</legend>
<div class="form-group">
<table class="table table-striped table-bordered" style="margin-top: 0px;">
- <tr>
- <td width="20%">Database URL</td>
- <td>{{serverInfo.jpaInfo.jdbcUrl}}</td>
- </tr>
- <tr>
- <td>Database User</td>
- <td>{{serverInfo.jpaInfo.databaseUser}}</td>
- </tr>
- <tr>
- <td>Database Type</td>
- <td>{{serverInfo.jpaInfo.databaseProduct}}</td>
- </tr>
- <tr>
- <td>Database Driver</td>
- <td>{{serverInfo.jpaInfo.databaseDriver}}</td>
+ <tr ng-repeat="(key, value) in serverInfoPage.jpaInfo">
+ <td width="20%">{{key}}</td>
+ <td>{{value}}</td>
</tr>
</table>
</div>
</fieldset>
- <fieldset ng-show="serverInfo.mongoDbInfo">
- <legend collapsed>Mongo DB Info</legend>
- <div class="form-group">
- <table class="table table-striped table-bordered" style="margin-top: 0px;">
- <tr width="20%">
- <td>Address</td>
- <td>{{serverInfo.mongoDbInfo.address}}</td>
- </tr>
- <tr>
- <td>Database</td>
- <td>{{serverInfo.mongoDbInfo.database}}</td>
- </tr>
- <tr>
- <td>User</td>
- <td>{{serverInfo.mongoDbInfo.user}}</td>
- </tr>
- <tr>
- <td>Driver Version</td>
- <td>{{serverInfo.mongoDbInfo.driverVersion}}</td>
- </tr>
- </table>
- </div>
- </fieldset>
-
<fieldset>
<legend collapsed>Providers</legend>
@@ -160,11 +124,23 @@
</tr>
</thead>
<tbody>
- <tr data-ng-repeat="spi in (serverInfo.providers | filter:{internal:false} | orderBy:'name')">
+ <tr data-ng-repeat="spi in (serverInfoPage.providers | filter:{internal:false} | orderBy:'name')">
<td>{{spi.name}}</td>
<td>
- <div data-ng-repeat="provider in (spi.implementations | orderBy:'toString()')">
- {{provider}}
+ <div data-ng-repeat="provider in (spi.implementations | orderBy:'name')">
+ {{provider.name}}
+ <span ng-show="provider.operationalInfo">
+ <button type="button" class="btn btn-default btn-xs" ng-click="collapseRep = !collapseRep">
+ <span class="glyphicon glyphicon-plus" data-ng-show="!collapseRep"></span>
+ <span class="glyphicon glyphicon-minus" data-ng-show="collapseRep"></span>
+ </button>
+ <table ng-show="collapseRep" class="table table-striped table-bordered" style="margin-top: 0px;">
+ <tr ng-repeat="(key, value) in provider.operationalInfo">
+ <td width="20%">{{key}}</td>
+ <td>{{value}}</td>
+ </tr>
+ </table>
+ </span>
</div>
</td>
</tr>
@@ -184,11 +160,23 @@
</tr>
</thead>
<tbody>
- <tr data-ng-repeat="spi in (serverInfo.providers | filter:{internal:true} | orderBy:'name')">
+ <tr data-ng-repeat="spi in (serverInfoPage.providers | filter:{internal:true} | orderBy:'name')">
<td>{{spi.name}}</td>
<td>
- <div data-ng-repeat="provider in (spi.implementations | orderBy:'toString()')">
- {{provider}}
+ <div data-ng-repeat="provider in (spi.implementations | orderBy:'name')">
+ {{provider.name}}
+ <span ng-show="provider.operationalInfo">
+ <button type="button" class="btn btn-default btn-xs" ng-click="collapseRep = !collapseRep">
+ <span class="glyphicon glyphicon-plus" data-ng-show="!collapseRep"></span>
+ <span class="glyphicon glyphicon-minus" data-ng-show="collapseRep"></span>
+ </button>
+ <table ng-show="collapseRep" class="table table-striped table-bordered" style="margin-top: 0px;">
+ <tr ng-repeat="(key, value) in provider.operationalInfo">
+ <td width="20%">{{key}}</td>
+ <td>{{value}}</td>
+ </tr>
+ </table>
+ </span>
</div>
</td>
</tr>
services/pom.xml 15(+0 -15)
diff --git a/services/pom.xml b/services/pom.xml
index 16fef06..da71e9a 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -41,21 +41,6 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-connections-jpa</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-entitymanager</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-connections-mongo</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.keycloak</groupId>
<artifactId>keycloak-forms-common-freemarker</artifactId>
<scope>provided</scope>
</dependency>
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
index e1d1fa3..6b3ca3e 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java
@@ -218,6 +218,32 @@ public class AdminRoot {
return adminResource;
}
+ /**
+ * Operational information about the server for "Server Info" page
+ *
+ * @param headers
+ * @return
+ */
+ @Path("serverinfopage")
+ public ServerInfoPageAdminResource getServerInfoPage(@Context final HttpHeaders headers) {
+ handlePreflightRequest();
+
+ AdminAuth auth = authenticateRealmAdminRequest(headers);
+ if (!isAdmin(auth)) {
+ throw new ForbiddenException();
+ }
+
+ if (auth != null) {
+ logger.debug("authenticated admin access for: " + auth.getUser().getUsername());
+ }
+
+ Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response);
+
+ ServerInfoPageAdminResource adminResource = new ServerInfoPageAdminResource();
+ ResteasyProviderFactory.getInstance().injectProperties(adminResource);
+ return adminResource;
+ }
+
protected boolean isAdmin(AdminAuth auth) {
RealmManager realmManager = new RealmManager(session);
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 3b69304..4f1c225 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,11 +1,8 @@
package org.keycloak.services.resources.admin;
-import org.jboss.logging.Logger;
import org.keycloak.Version;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
-import org.keycloak.connections.jpa.JpaConnectionProvider;
-import org.keycloak.connections.mongo.MongoConnectionProvider;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventType;
import org.keycloak.events.admin.OperationType;
@@ -19,10 +16,8 @@ import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.LoginProtocolFactory;
import org.keycloak.protocol.ProtocolMapper;
-import org.keycloak.provider.MonitorableProviderFactory;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.ProviderOperationalInfo;
import org.keycloak.provider.Spi;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
@@ -31,13 +26,11 @@ import org.keycloak.social.SocialIdentityProvider;
import javax.ws.rs.GET;
import javax.ws.rs.core.Context;
-import java.io.Serializable;
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;
@@ -46,8 +39,6 @@ import java.util.Set;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ServerInfoAdminResource {
-
- private static final Logger logger = Logger.getLogger(ServerInfoAdminResource.class);
private static final Map<String, List<String>> ENUMS = createEnumsMap(EventType.class, OperationType.class);
@@ -64,9 +55,6 @@ public class ServerInfoAdminResource {
ServerInfoRepresentation info = new ServerInfoRepresentation();
info.version = Version.VERSION;
info.serverTime = new Date().toString();
- info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp();
- info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime());
- info.systemInfo = (new SystemInfo()).init();
setSocialProviders(info);
setIdentityProviders(info);
setThemes(info);
@@ -77,21 +65,6 @@ public class ServerInfoAdminResource {
setProtocolMapperTypes(info);
setBuiltinProtocolMappers(info);
info.setEnums(ENUMS);
-
- ProviderFactory<JpaConnectionProvider> jpf = session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
- if(jpf!=null && jpf instanceof MonitorableProviderFactory){
- info.jpaInfo = ((MonitorableProviderFactory<?>)jpf).getOperationalInfo();
- } else {
- logger.debug("JPA provider not found or is not monitorable");
- }
-
- ProviderFactory<MongoConnectionProvider> mpf = session.getKeycloakSessionFactory().getProviderFactory(MongoConnectionProvider.class);
- if(mpf!=null && mpf instanceof MonitorableProviderFactory){
- info.mongoDbInfo = ((MonitorableProviderFactory<?>)mpf).getOperationalInfo();
- } else {
- logger.debug("Mongo provider not found or is not monitorable");
- }
-
return info;
}
@@ -214,170 +187,12 @@ public class ServerInfoAdminResource {
info.clientImporters.add(data);
}
}
-
- public static class MemoryInfo implements Serializable {
-
- protected long total;
- protected long used;
-
- public MemoryInfo(){
- }
-
- /**
- * Fill object fwith info.
- * @param runtime used to get memory info from.
- * @return itself for chaining
- */
- public MemoryInfo init(Runtime runtime){
- total = runtime.maxMemory();
- used = runtime.totalMemory() - runtime.freeMemory();
- return this;
- }
-
- public long getTotal(){
- return total;
- }
-
- public String getTotalFormated(){
- return formatMemory(getTotal());
- }
-
- public long getFree(){
- return getTotal() - getUsed();
- }
-
- public String getFreeFormated(){
- return formatMemory(getFree());
- }
-
- public long getUsed(){
- return used;
- }
-
- 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 implements Serializable {
-
- protected String javaVersion;
- protected String javaVendor;
- protected String javaVm;
- protected String javaVmVersion;
- protected String javaRuntime;
- protected String javaHome;
- protected String osName;
- protected String osArchitecture;
- protected String osVersion;
- protected String fileEncoding;
- protected String userName;
- protected String userDir;
- protected String userTimezone;
- protected String userLocale;
-
- public SystemInfo() {
- }
-
- /**
- * Fill object with info about current system loaded from {@link System} properties.
- * @return object itself for chaining
- */
- protected SystemInfo init(){
- javaVersion = System.getProperty("java.version");
- javaVendor = System.getProperty("java.vendor");
- javaVm = System.getProperty("java.vm.name");
- javaVmVersion = System.getProperty("java.vm.version");
- javaRuntime = System.getProperty("java.runtime.name");
- javaHome = System.getProperty("java.home");
- osName = System.getProperty("os.name");
- osArchitecture = System.getProperty("os.arch");
- osVersion = System.getProperty("os.version");
- fileEncoding = System.getProperty("file.encoding");
- userName = System.getProperty("user.name");
- userDir = System.getProperty("user.dir");
- userTimezone = System.getProperty("user.timezone");
- userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString());
- return this;
- }
-
- public String getJavaVersion(){
- return javaVersion;
- }
-
- public String getJavaVendor(){
- return javaVendor;
- }
-
- public String getJavaVm(){
- return javaVm;
- }
-
- public String getJavaVmVersion(){
- return javaVmVersion;
- }
- public String getJavaRuntime(){
- return javaRuntime;
- }
-
- public String getJavaHome(){
- return javaHome;
- }
-
- public String getOsName(){
- return osName;
- }
-
- public String getOsArchitecture(){
- return osArchitecture;
- }
-
- public String getOsVersion(){
- return osVersion;
- }
-
- public String getFileEncoding(){
- return fileEncoding;
- }
-
- public String getUserName(){
- return userName;
- }
-
- public String getUserDir(){
- return userDir;
- }
-
- public String getUserTimezone(){
- return userTimezone;
- }
-
- public String getUserLocale(){
- return userLocale;
- }
- }
-
- public static class ServerInfoRepresentation implements Serializable {
+ public static class ServerInfoRepresentation {
private String version;
+
private String serverTime;
- private long serverStartupTime;
private Map<String, List<String>> themes;
@@ -393,76 +208,13 @@ public class ServerInfoAdminResource {
private Map<String, List<ProtocolMapperRepresentation>> builtinProtocolMappers;
private Map<String, List<String>> enums;
-
- private MemoryInfo memoryInfo;
- private SystemInfo systemInfo;
-
- private ProviderOperationalInfo jpaInfo;
- private ProviderOperationalInfo mongoDbInfo;
public ServerInfoRepresentation() {
}
-
- public SystemInfo getSystemInfo(){
- return systemInfo;
- }
-
- public MemoryInfo getMemoryInfo(){
- return memoryInfo;
- }
-
- public ProviderOperationalInfo getJpaInfo() {
- return jpaInfo;
- }
-
- public ProviderOperationalInfo getMongoDbInfo() {
- return mongoDbInfo;
- }
public String getServerTime() {
return serverTime;
}
-
- public long getServerStartupTime() {
- return serverStartupTime;
- }
-
- /**
- * @return server startup time formatted
- */
- public String getServerStartupTimeFormatted() {
- 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;
@@ -517,7 +269,7 @@ public class ServerInfoAdminResource {
}
}
- public static class SpiInfoRepresentation implements Serializable {
+ public static class SpiInfoRepresentation {
private String name;
private boolean internal;
private Set<String> implementations;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java
new file mode 100644
index 0000000..c6a7208
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoPageAdminResource.java
@@ -0,0 +1,375 @@
+package org.keycloak.services.resources.admin;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashSet;
+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.jboss.logging.Logger;
+import org.keycloak.Version;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.provider.ServerInfoAwareProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * REST endpoint which return info for "Server Info" page.
+ *
+ * @author Vlastimil Elias (velias at redhat dot com)
+ */
+public class ServerInfoPageAdminResource {
+
+ private static final Logger logger = Logger.getLogger(ServerInfoPageAdminResource.class);
+
+ @Context
+ private KeycloakSession session;
+
+ /**
+ * Returns a list of providers and other operational info about the page.
+ *
+ * @return
+ */
+ @GET
+ public ServerInfoRepresentation getInfo() {
+ ServerInfoRepresentation info = new ServerInfoRepresentation();
+ info.version = Version.VERSION;
+ info.serverTime = new Date().toString();
+ info.serverStartupTime = session.getKeycloakSessionFactory().getServerStartupTimestamp();
+ info.memoryInfo = (new MemoryInfo()).init(Runtime.getRuntime());
+ info.systemInfo = (new SystemInfo()).init();
+ setProviders(info);
+ return info;
+ }
+
+ private void setProviders(ServerInfoRepresentation info) {
+ List<SpiInfoRepresentation> providers = new LinkedList<>();
+ for (Spi spi : ServiceLoader.load(Spi.class)) {
+ SpiInfoRepresentation spiRep = new SpiInfoRepresentation();
+ spiRep.setName(spi.getName());
+ spiRep.setInternal(spi.isInternal());
+ spiRep.setSystemInfo(ServerInfoAwareProviderFactory.class.isAssignableFrom(spi.getProviderFactoryClass()));
+ Set<String> s = session.listProviderIds(spi.getProviderClass());
+ Set<SpiImplementationRepresentation> srs = new HashSet<>();
+
+ if(s!=null){
+ for(String name: s){
+ SpiImplementationRepresentation sr = new SpiImplementationRepresentation(name);
+ if(spiRep.isSystemInfo()){
+ sr.setOperationalInfo(((ServerInfoAwareProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(spi.getProviderClass(), name)).getOperationalInfo());
+ }
+ srs.add(sr);
+ }
+ }
+ spiRep.setImplementations(srs);
+ providers.add(spiRep);
+ }
+ info.providers = providers;
+ }
+
+
+ public static class MemoryInfo implements Serializable {
+
+ protected long total;
+ protected long used;
+
+ public MemoryInfo(){
+ }
+
+ /**
+ * Fill object fwith info.
+ * @param runtime used to get memory info from.
+ * @return itself for chaining
+ */
+ public MemoryInfo init(Runtime runtime){
+ total = runtime.maxMemory();
+ used = runtime.totalMemory() - runtime.freeMemory();
+ return this;
+ }
+
+ public long getTotal(){
+ return total;
+ }
+
+ public String getTotalFormated(){
+ return formatMemory(getTotal());
+ }
+
+ public long getFree(){
+ return getTotal() - getUsed();
+ }
+
+ public String getFreeFormated(){
+ return formatMemory(getFree());
+ }
+
+ public long getUsed(){
+ return used;
+ }
+
+ 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 implements Serializable {
+
+ protected String javaVersion;
+ protected String javaVendor;
+ protected String javaVm;
+ protected String javaVmVersion;
+ protected String javaRuntime;
+ protected String javaHome;
+ protected String osName;
+ protected String osArchitecture;
+ protected String osVersion;
+ protected String fileEncoding;
+ protected String userName;
+ protected String userDir;
+ protected String userTimezone;
+ protected String userLocale;
+
+ public SystemInfo() {
+ }
+
+ /**
+ * Fill object with info about current system loaded from {@link System} properties.
+ * @return object itself for chaining
+ */
+ protected SystemInfo init(){
+ javaVersion = System.getProperty("java.version");
+ javaVendor = System.getProperty("java.vendor");
+ javaVm = System.getProperty("java.vm.name");
+ javaVmVersion = System.getProperty("java.vm.version");
+ javaRuntime = System.getProperty("java.runtime.name");
+ javaHome = System.getProperty("java.home");
+ osName = System.getProperty("os.name");
+ osArchitecture = System.getProperty("os.arch");
+ osVersion = System.getProperty("os.version");
+ fileEncoding = System.getProperty("file.encoding");
+ userName = System.getProperty("user.name");
+ userDir = System.getProperty("user.dir");
+ userTimezone = System.getProperty("user.timezone");
+ userLocale = (new Locale(System.getProperty("user.country"),System.getProperty("user.language")).toString());
+ return this;
+ }
+
+ public String getJavaVersion(){
+ return javaVersion;
+ }
+
+ public String getJavaVendor(){
+ return javaVendor;
+ }
+
+ public String getJavaVm(){
+ return javaVm;
+ }
+
+ public String getJavaVmVersion(){
+ return javaVmVersion;
+ }
+
+ public String getJavaRuntime(){
+ return javaRuntime;
+ }
+
+ public String getJavaHome(){
+ return javaHome;
+ }
+
+ public String getOsName(){
+ return osName;
+ }
+
+ public String getOsArchitecture(){
+ return osArchitecture;
+ }
+
+ public String getOsVersion(){
+ return osVersion;
+ }
+
+ public String getFileEncoding(){
+ return fileEncoding;
+ }
+
+ public String getUserName(){
+ return userName;
+ }
+
+ public String getUserDir(){
+ return userDir;
+ }
+
+ public String getUserTimezone(){
+ return userTimezone;
+ }
+
+ public String getUserLocale(){
+ return userLocale;
+ }
+ }
+
+ public static class ServerInfoRepresentation implements Serializable {
+
+ private String version;
+ private String serverTime;
+ private long serverStartupTime;
+
+
+ private List<SpiInfoRepresentation> providers;
+
+ private MemoryInfo memoryInfo;
+ private SystemInfo systemInfo;
+
+ public ServerInfoRepresentation() {
+ }
+
+ public SystemInfo getSystemInfo(){
+ return systemInfo;
+ }
+
+ public MemoryInfo getMemoryInfo(){
+ return memoryInfo;
+ }
+
+ public String getServerTime() {
+ return serverTime;
+ }
+
+ public long getServerStartupTime() {
+ return serverStartupTime;
+ }
+
+ /**
+ * @return server startup time formatted
+ */
+ public String getServerStartupTimeFormatted() {
+ 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;
+ }
+
+
+ public List<SpiInfoRepresentation> getProviders() {
+ return providers;
+ }
+ }
+
+ public static class SpiInfoRepresentation implements Serializable {
+ private String name;
+ private boolean internal;
+ private boolean systemInfo;
+ private Set<SpiImplementationRepresentation> implementations;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isInternal() {
+ return internal;
+ }
+
+ public void setInternal(boolean internal) {
+ this.internal = internal;
+ }
+
+ public Set<SpiImplementationRepresentation> getImplementations() {
+ return implementations;
+ }
+
+ public boolean isSystemInfo() {
+ return systemInfo;
+ }
+
+ public void setSystemInfo(boolean systemInfo) {
+ this.systemInfo = systemInfo;
+ }
+
+ public void setImplementations(Set<SpiImplementationRepresentation> implementations) {
+ this.implementations = implementations;
+ }
+ }
+
+ public static class SpiImplementationRepresentation implements Serializable {
+
+ private String name;
+ private Map<String, String> operationalInfo;
+
+ public SpiImplementationRepresentation(String name) {
+ super();
+ this.name = name;
+ }
+
+ public Map<String, String> getOperationalInfo() {
+ return operationalInfo;
+ }
+
+ public void setOperationalInfo(Map<String, String> operationalInfo) {
+ this.operationalInfo = operationalInfo;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
index 2cca19a..33ead31 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
@@ -317,13 +317,41 @@ public class AdminAPITest {
Assert.assertNotNull(response);
Assert.assertEquals(Version.VERSION, response.get("version"));
Assert.assertNotNull(response.get("serverTime"));
+ Assert.assertNotNull(response.get("providers"));
+ Assert.assertNotNull(response.get("themes"));
+ Assert.assertNotNull(response.get("enums"));
+
+ // System.out.println(response);
+
+ }
+
+ @Test
+ public void testServerInfoPage() {
+
+ String token = createToken();
+ final String authHeader = "Bearer " + token;
+ ClientRequestFilter authFilter = new ClientRequestFilter() {
+ @Override
+ public void filter(ClientRequestContext requestContext) throws IOException {
+ requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
+ }
+ };
+ Client client = ClientBuilder.newBuilder().register(authFilter).build();
+ UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
+ WebTarget target = client.target(AdminRoot.adminBaseUrl(authBase).path("serverinfopage"));
+
+ Map<?, ?> response = target.request().accept("application/json").get(Map.class);
+
+ Assert.assertNotNull(response);
+ Assert.assertEquals(Version.VERSION, response.get("version"));
+ Assert.assertNotNull(response.get("serverTime"));
+ Assert.assertNotNull(response.get("providers"));
Assert.assertNotNull(response.get("serverStartupTime"));
Assert.assertNotNull(response.get("memoryInfo"));
- Assert.assertNotNull(response.get("jpaInfo"));
- Assert.assertNull(response.get("mongoDbInfo"));
+ Assert.assertNotNull(response.get("systemInfo"));
- System.out.println(response);
+ // System.out.println(response);
}