001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.repository.commonimpl.user;
017:
018: import org.outerj.daisy.repository.user.User;
019: import org.outerj.daisy.repository.user.PublicUserInfo;
020: import org.outerj.daisy.repository.user.UserNotFoundException;
021: import org.outerj.daisy.repository.*;
022: import org.outerj.daisy.repository.commonimpl.AuthenticatedUser;
023:
024: import java.util.Map;
025: import java.util.HashMap;
026: import java.util.Collections;
027:
028: // Implementation note:
029: // The user cache can work in two modes depending on whether the cacheUser is
030: // in the Administrator role or not.
031: // If the cacheUser in in the Administrator role, the cache user can retrieve
032: // the full user objects. If the cacheUser is not in the Administrator role,
033: // the full user objects can still be retrieved by using the user that
034: // requested the user object. However, if a non-Admin user accesses the
035: // public user info, and the cache user is also a non-Admin user, then
036: // we cannot retrieve the full user object and therefore use a cache of
037: // only public user infos (for performance reasons, it is important that
038: // this info is cached).
039: // Supporting non-Administrator role cache users is interesting for the remote
040: // Java API implementation, which would otherwise only be usable with
041: // an Administrator user.
042: public class UserCache implements RepositoryListener {
043: private Map users = Collections.synchronizedMap(new HashMap());
044: private Map usersByLogin = Collections
045: .synchronizedMap(new HashMap());
046:
047: private Map usersPublicInfo = Collections
048: .synchronizedMap(new HashMap());
049: private Map usersPublicInfoByLogin = Collections
050: .synchronizedMap(new HashMap());
051:
052: private Map roles = Collections.synchronizedMap(new HashMap());
053: private Map rolesByName = Collections
054: .synchronizedMap(new HashMap());
055: private org.outerj.daisy.repository.commonimpl.AuthenticatedUser cacheUser;
056: private UserManagementStrategy userManagementStrategy;
057: private boolean adminMode;
058: private final static PublicUserInfo NONEXISTING_USER = new PublicUserInfoImpl(
059: -1, "Non-existing user", "A non-existing user");
060:
061: public UserCache(
062: UserManagementStrategy userManagementStrategy,
063: org.outerj.daisy.repository.commonimpl.AuthenticatedUser cacheUser) {
064: this .cacheUser = cacheUser;
065: this .userManagementStrategy = userManagementStrategy;
066: adminMode = cacheUser.isInAdministratorRole();
067: }
068:
069: public UserImpl getUser(long userId) throws RepositoryException {
070: return getUser(userId, cacheUser);
071: }
072:
073: public UserImpl getUser(long userId,
074: AuthenticatedUser requestingUser)
075: throws RepositoryException {
076: Long key = new Long(userId);
077: UserImpl user = (UserImpl) users.get(key);
078: if (user == null) {
079: user = userManagementStrategy.getUser(userId,
080: requestingUser);
081: user.makeReadOnly();
082: synchronized (this ) {
083: users.put(key, user);
084: usersByLogin.put(user.getLogin(), user);
085: }
086: }
087: return user;
088: }
089:
090: public UserImpl getUser(String login) throws RepositoryException {
091: return getUser(login, cacheUser);
092: }
093:
094: public UserImpl getUser(String login,
095: AuthenticatedUser requestingUser)
096: throws RepositoryException {
097: UserImpl user = (UserImpl) usersByLogin.get(login);
098: if (user == null) {
099: user = userManagementStrategy
100: .getUser(login, requestingUser);
101: user.makeReadOnly();
102: synchronized (this ) {
103: users.put(new Long(user.getId()), user);
104: usersByLogin.put(user.getLogin(), user);
105: }
106: }
107: return user;
108: }
109:
110: public PublicUserInfo getPublicUserInfo(long userId)
111: throws RepositoryException {
112: if (adminMode) {
113: return getUser(userId).getPublicUserInfo();
114: } else {
115: PublicUserInfo publicUserInfo = (PublicUserInfo) usersPublicInfo
116: .get(new Long(userId));
117: if (publicUserInfo == null) {
118: try {
119: publicUserInfo = userManagementStrategy
120: .getPublicUserInfo(userId, cacheUser);
121: } catch (UserNotFoundException e) {
122: publicUserInfo = NONEXISTING_USER;
123: }
124: synchronized (this ) {
125: usersPublicInfo.put(new Long(userId),
126: publicUserInfo);
127: usersPublicInfoByLogin.put(publicUserInfo
128: .getLogin(), publicUserInfo);
129: }
130: }
131: if (publicUserInfo == NONEXISTING_USER)
132: throw new UserNotFoundException(userId);
133: return publicUserInfo;
134: }
135: }
136:
137: public PublicUserInfo getPublicUserInfo(String login)
138: throws RepositoryException {
139: if (adminMode) {
140: return getUser(login).getPublicUserInfo();
141: } else {
142: PublicUserInfo publicUserInfo = (PublicUserInfo) usersPublicInfoByLogin
143: .get(login);
144: if (publicUserInfo == null) {
145: publicUserInfo = userManagementStrategy
146: .getPublicUserInfo(login, cacheUser);
147: synchronized (this ) {
148: usersPublicInfo.put(
149: new Long(publicUserInfo.getId()),
150: publicUserInfo);
151: usersPublicInfoByLogin.put(publicUserInfo
152: .getLogin(), publicUserInfo);
153: }
154: }
155: return publicUserInfo;
156: }
157: }
158:
159: public RoleImpl getRole(long roleId) throws RepositoryException {
160: Long key = new Long(roleId);
161: RoleImpl role = (RoleImpl) roles.get(key);
162: if (role == null) {
163: role = userManagementStrategy.getRole(roleId, cacheUser);
164: role.makeReadOnly();
165: synchronized (this ) {
166: roles.put(key, role);
167: rolesByName.put(role.getName(), role);
168: }
169: }
170: return role;
171: }
172:
173: public RoleImpl getRole(String roleName) throws RepositoryException {
174: RoleImpl role = (RoleImpl) rolesByName.get(roleName);
175: if (role == null) {
176: role = userManagementStrategy.getRole(roleName, cacheUser);
177: role.makeReadOnly();
178: synchronized (this ) {
179: roles.put(new Long(role.getId()), role);
180: rolesByName.put(roleName, role);
181: }
182: }
183: return role;
184: }
185:
186: public void repositoryEvent(RepositoryEventType eventType,
187: Object id, long updateCount) {
188: if (eventType == RepositoryEventType.USER_UPDATED
189: || eventType == RepositoryEventType.USER_DELETED) {
190: synchronized (this ) {
191: User user = (User) users.get(id);
192: if (user != null
193: && user.getUpdateCount() == updateCount)
194: return;
195: if (user != null) {
196: users.remove(id);
197: usersByLogin.remove(user.getLogin());
198: }
199:
200: PublicUserInfo publicUserInfo = (PublicUserInfo) usersPublicInfo
201: .get(id);
202: if (publicUserInfo != null) {
203: usersPublicInfo.remove(id);
204: usersPublicInfo.remove(publicUserInfo.getLogin());
205: }
206: }
207: } else if (eventType == RepositoryEventType.ROLE_UPDATED
208: || eventType == RepositoryEventType.ROLE_DELETED) {
209: synchronized (this ) {
210: RoleImpl role = (RoleImpl) roles.get(id);
211: if (role != null
212: && role.getUpdateCount() == updateCount)
213: return;
214:
215: // roles can belong to various users, just clear entire user cache
216: users.clear();
217: usersByLogin.clear();
218: if (role != null) {
219: roles.remove(new Long(role.getId()));
220: rolesByName.remove(role.getName());
221: }
222:
223: // note: public user info does not contain role information, so its cache can remain
224: }
225: }
226: // Note: upon role or user creation, we don't need to do anything.
227: }
228:
229: }
|