cache implement

This commit is contained in:
Bill Burke 2014-06-12 11:45:50 -04:00
parent 30b95e0a57
commit bb2ad656a3
5 changed files with 117 additions and 133 deletions

View file

@ -11,6 +11,8 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public interface KeycloakSession extends Provider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
KeycloakTransaction getTransaction();
RealmModel createRealm(String name);
@ -25,11 +27,9 @@ public interface KeycloakSession extends Provider {
List<UserModel> getUsers(RealmModel realm);
List<UserModel> searchForUser(String search, RealmModel realm);
List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm);
Set<RoleModel> getRealmRoleMappings(UserModel user, RealmModel realm);
Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm);
SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm);
AuthenticationLinkModel getAuthenticationLink(UserModel user, RealmModel realm);
RoleModel getRoleById(String id, RealmModel realm);

View file

@ -204,11 +204,6 @@ public class CacheKeycloakSession implements KeycloakSession {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<RoleModel> getRealmRoleMappings(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
@ -219,11 +214,6 @@ public class CacheKeycloakSession implements KeycloakSession {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public AuthenticationLinkModel getAuthenticationLink(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public RoleModel getRoleById(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.

View file

@ -3,8 +3,10 @@ package org.keycloak.models.jpa;
import org.keycloak.models.*;
import org.keycloak.models.jpa.entities.*;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.util.Time;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
@ -169,22 +171,59 @@ public class JpaKeycloakSession implements KeycloakSession {
@Override
public List<UserModel> getUsers(RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm", UserEntity.class);
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity);
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
return users;
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm and ( lower(u.loginName) like :search or lower(concat(u.firstName, ' ', u.lastName)) like :search or u.email like :search )", UserEntity.class);
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity);
query.setParameter("search", "%" + search.toLowerCase() + "%");
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
return users;
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
StringBuilder builder = new StringBuilder("select u from UserEntity u");
boolean first = true;
for (Map.Entry<String, String> entry : attributes.entrySet()) {
String attribute = null;
if (entry.getKey().equals(UserModel.LOGIN_NAME)) {
attribute = "lower(loginName)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
attribute = "lower(firstName)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
attribute = "lower(lastName)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
attribute = "lower(email)";
}
@Override
public Set<RoleModel> getRealmRoleMappings(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
if (attribute == null) continue;
if (first) {
first = false;
builder.append(" where realm = :realm");
} else {
builder.append(" and ");
}
builder.append(attribute).append(" like '%").append(entry.getValue().toLowerCase()).append("%'");
}
String q = builder.toString();
TypedQuery<UserEntity> query = em.createQuery(q, UserEntity.class);
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity);
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
return users;
}
private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
@ -216,14 +255,12 @@ public class JpaKeycloakSession implements KeycloakSession {
return (entity != null) ? new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()) : null;
}
@Override
public AuthenticationLinkModel getAuthenticationLink(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public RoleModel getRoleById(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
RoleEntity entity = em.find(RoleEntity.class, id);
if (entity == null) return null;
if (!realm.getId().equals(entity.getRealmId())) return null;
return new RoleAdapter(realm, em, entity);
}
@Override
@ -237,7 +274,11 @@ public class JpaKeycloakSession implements KeycloakSession {
@Override
public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
OAuthClientEntity client = em.find(OAuthClientEntity.class, id);
// Check if client belongs to this realm
if (client == null || !realm.getId().equals(client.getRealm().getId())) return null;
return new OAuthClientAdapter(realm, client, em);
}
@Override
@ -275,46 +316,82 @@ public class JpaKeycloakSession implements KeycloakSession {
@Override
public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) {
return null; //To change body of implemented methods use File | Settings | File Templates.
UserSessionEntity entity = new UserSessionEntity();
entity.setRealmId(realm.getId());
entity.setUserId(user.getId());
entity.setIpAddress(ipAddress);
int currentTime = Time.currentTime();
entity.setStarted(currentTime);
entity.setLastSessionRefresh(currentTime);
em.persist(entity);
return new UserSessionAdapter(em, realm, entity);
}
@Override
public UserSessionModel getUserSession(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
UserSessionEntity entity = em.find(UserSessionEntity.class, id);
return entity != null ? new UserSessionAdapter(em, realm, entity) : null;
}
@Override
public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
List<UserSessionModel> sessions = new LinkedList<UserSessionModel>();
for (UserSessionEntity e : em.createNamedQuery("getUserSessionByUser", UserSessionEntity.class)
.setParameter("userId", user.getId()).getResultList()) {
sessions.add(new UserSessionAdapter(em, realm, e));
}
return sessions;
}
@Override
public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
return null; //To change body of implemented methods use File | Settings | File Templates.
Set<UserSessionModel> list = new HashSet<UserSessionModel>();
TypedQuery<ClientUserSessionAssociationEntity> query = em.createNamedQuery("getClientUserSessionByClient", ClientUserSessionAssociationEntity.class);
String id = client.getId();
query.setParameter("clientId", id);
List<ClientUserSessionAssociationEntity> results = query.getResultList();
for (ClientUserSessionAssociationEntity entity : results) {
list.add(new UserSessionAdapter(em, realm, entity.getSession()));
}
return list;
}
@Override
public int getActiveUserSessions(RealmModel realm, ClientModel client) {
return 0; //To change body of implemented methods use File | Settings | File Templates.
Query query = em.createNamedQuery("getActiveClientSessions");
query.setParameter("clientId", client.getId());
Object count = query.getSingleResult();
return ((Number)count).intValue();
}
@Override
public void removeUserSession(UserSessionModel session) {
//To change body of implemented methods use File | Settings | File Templates.
em.remove(((UserSessionAdapter) session).getEntity());
}
@Override
public void removeUserSessions(RealmModel realm, UserModel user) {
//To change body of implemented methods use File | Settings | File Templates.
em.createNamedQuery("removeClientUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
em.createNamedQuery("removeUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
}
@Override
public void removeExpiredUserSessions(RealmModel realm) {
//To change body of implemented methods use File | Settings | File Templates.
TypedQuery<UserSessionEntity> query = em.createNamedQuery("getUserSessionExpired", UserSessionEntity.class)
.setParameter("maxTime", Time.currentTime() - realm.getSsoSessionMaxLifespan())
.setParameter("idleTime", Time.currentTime() - realm.getSsoSessionIdleTimeout());
List<UserSessionEntity> results = query.getResultList();
for (UserSessionEntity entity : results) {
em.remove(entity);
}
}
@Override
public void removeUserSessions(RealmModel realm) {
//To change body of implemented methods use File | Settings | File Templates.
em.createNamedQuery("removeClientUserSessionByRealm").setParameter("realmId", realm.getId()).executeUpdate();
em.createNamedQuery("removeRealmUserSessions").setParameter("realmId", realm.getId()).executeUpdate();
}
}

View file

@ -493,7 +493,8 @@ public class RealmAdapter implements RealmModel {
}
private void removeUser(UserEntity user) {
removeUserSessions(user);
em.createNamedQuery("removeClientUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
em.createNamedQuery("removeUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate();
em.createQuery("delete from " + SocialLinkEntity.class.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate();
@ -733,55 +734,17 @@ public class RealmAdapter implements RealmModel {
@Override
public List<UserModel> getUsers() {
TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm", UserEntity.class);
query.setParameter("realm", realm);
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(this, em, entity));
return users;
return session.getUsers(this);
}
@Override
public List<UserModel> searchForUser(String search) {
TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm and ( lower(u.loginName) like :search or lower(concat(u.firstName, ' ', u.lastName)) like :search or u.email like :search )", UserEntity.class);
query.setParameter("realm", realm);
query.setParameter("search", "%" + search.toLowerCase() + "%");
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(this, em, entity));
return users;
return session.searchForUser(search, this);
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes) {
StringBuilder builder = new StringBuilder("select u from UserEntity u");
boolean first = true;
for (Map.Entry<String, String> entry : attributes.entrySet()) {
String attribute = null;
if (entry.getKey().equals(UserModel.LOGIN_NAME)) {
attribute = "lower(loginName)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
attribute = "lower(firstName)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
attribute = "lower(lastName)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
attribute = "lower(email)";
}
if (attribute == null) continue;
if (first) {
first = false;
builder.append(" where ");
} else {
builder.append(" and ");
}
builder.append(attribute).append(" like '%").append(entry.getValue().toLowerCase()).append("%'");
}
String q = builder.toString();
TypedQuery<UserEntity> query = em.createQuery(q, UserEntity.class);
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(this, em, entity));
return users;
return session.searchForUserByAttributes(attributes, this);
}
@Override
@ -825,11 +788,7 @@ public class RealmAdapter implements RealmModel {
@Override
public OAuthClientModel getOAuthClientById(String id) {
OAuthClientEntity client = em.find(OAuthClientEntity.class, id);
// Check if client belongs to this realm
if (client == null || !this.realm.getId().equals(client.getRealm().getId())) return null;
return new OAuthClientAdapter(this, client, em);
return session.getOAuthClientById(id, this);
}
@ -991,11 +950,7 @@ public class RealmAdapter implements RealmModel {
@Override
public RoleModel getRoleById(String id) {
RoleEntity entity = null;
entity = em.find(RoleEntity.class, id);
if (entity == null) return null;
if (!getId().equals(entity.getRealmId())) return null;
return new RoleAdapter(this, em, entity);
return session.getRoleById(id, this);
}
@Override
@ -1143,66 +1098,38 @@ public class RealmAdapter implements RealmModel {
@Override
public UserSessionModel createUserSession(UserModel user, String ipAddress) {
UserSessionEntity entity = new UserSessionEntity();
entity.setRealmId(realm.getId());
entity.setUserId(user.getId());
entity.setIpAddress(ipAddress);
int currentTime = Time.currentTime();
entity.setStarted(currentTime);
entity.setLastSessionRefresh(currentTime);
em.persist(entity);
return new UserSessionAdapter(em, this, entity);
return session.createUserSession(this, user, ipAddress);
}
@Override
public UserSessionModel getUserSession(String id) {
UserSessionEntity entity = em.find(UserSessionEntity.class, id);
return entity != null ? new UserSessionAdapter(em, this, entity) : null;
return session.getUserSession(id, this);
}
@Override
public List<UserSessionModel> getUserSessions(UserModel user) {
List<UserSessionModel> sessions = new LinkedList<UserSessionModel>();
for (UserSessionEntity e : em.createNamedQuery("getUserSessionByUser", UserSessionEntity.class).setParameter("userId", user.getId()).getResultList()) {
sessions.add(new UserSessionAdapter(em, this, e));
}
return sessions;
return session.getUserSessions(user, this);
}
@Override
public void removeUserSession(UserSessionModel session) {
em.remove(((UserSessionAdapter) session).getEntity());
this.session.removeUserSession(session);
}
@Override
public void removeUserSessions() {
em.createNamedQuery("removeClientUserSessionByRealm").setParameter("realmId", realm.getId()).executeUpdate();
em.createNamedQuery("removeRealmUserSessions").setParameter("realmId", realm.getId()).executeUpdate();
session.removeUserSessions(this);
}
@Override
public void removeUserSessions(UserModel user) {
removeUserSessions(((UserAdapter) user).getUser());
}
private void removeUserSessions(UserEntity user) {
em.createNamedQuery("removeClientUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
em.createNamedQuery("removeUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
session.removeUserSessions(this, user);
}
@Override
public void removeExpiredUserSessions() {
TypedQuery<UserSessionEntity> query = em.createNamedQuery("getUserSessionExpired", UserSessionEntity.class)
.setParameter("maxTime", Time.currentTime() - getSsoSessionMaxLifespan())
.setParameter("idleTime", Time.currentTime() - getSsoSessionIdleTimeout());
List<UserSessionEntity> results = query.getResultList();
for (UserSessionEntity entity : results) {
em.remove(entity);
}
session.removeExpiredUserSessions(this);
}
}

View file

@ -172,11 +172,6 @@ public class MongoKeycloakSession implements KeycloakSession {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<RoleModel> getRealmRoleMappings(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
@ -187,11 +182,6 @@ public class MongoKeycloakSession implements KeycloakSession {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public AuthenticationLinkModel getAuthenticationLink(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public RoleModel getRoleById(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.