001: /*
002: * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005: package com.sun.portal.desktop.context;
006:
007: import com.sun.portal.desktop.dp.DPRoot;
008: import com.sun.portal.desktop.dp.xml.XMLDPRoot;
009: import com.sun.portal.community.mc.ConfigTable;
010: import com.sun.portal.community.mc.CMCUser;
011: import com.sun.portal.community.mc.CMCException;
012:
013: import java.util.Map;
014: import java.util.HashMap;
015: import java.util.Set;
016: import java.util.List;
017: import java.util.ArrayList;
018: import java.util.Iterator;
019: import java.util.Collections;
020: import java.util.TreeSet;
021: import java.io.InputStream;
022: import java.io.ByteArrayInputStream;
023:
024: public class DPCacheManager {
025: // Constants for dpScanInterval
026: public static final int DP_SCAN_INTERVAL_NEVER = -1;
027: public static final int DP_SCAN_INTERVAL_ALWAYS = 0;
028:
029: // Map of (uid, DPRoot). Stores parsed User-DP. User-DP is also said to be Customized-DP.
030: // User-DP is DP document found at user's LDAP DN.
031: private static Map dpRootsUser = Collections
032: .synchronizedMap(new HashMap());
033:
034: // Map of (uid, Boolean). Stores whether user has customized-DP.
035: private static Map dpRootsUserCustomized = Collections
036: .synchronizedMap(new HashMap());
037:
038: // Map of (uid, Long). Stores when was the last time User-DP was read.
039: private static Map lastReadTimesDPUserDocuments = Collections
040: .synchronizedMap(new HashMap());
041:
042: public static DPRoot getUserDPRoot(String uid) {
043: return (DPRoot) dpRootsUser.get(uid);
044: }
045:
046: public static void putUserDPRoot(String uid, DPRoot dpRoot) {
047: dpRootsUser.put(uid, dpRoot);
048: dpRootsUserCustomized.put(uid, Boolean.TRUE);
049: lastReadTimesDPUserDocuments.put(uid, new Long(System
050: .currentTimeMillis()));
051: }
052:
053: public static void removeUserDPRoot(String uid) {
054: dpRootsUser.remove(uid);
055: dpRootsUserCustomized.remove(uid);
056: lastReadTimesDPUserDocuments.remove(uid);
057: }
058:
059: public static void setUserDocumentLastRead(String uid) {
060: lastReadTimesDPUserDocuments.put(uid, new Long(System
061: .currentTimeMillis()));
062: }
063:
064: public static long getUserDocumentLastRead(String uid) {
065: Long lastRead = (Long) lastReadTimesDPUserDocuments.get(uid);
066: if (lastRead != null) {
067: return lastRead.longValue();
068: } else {
069: return -1;
070: }
071: }
072:
073: public static void setCustomized(String uid, boolean state) {
074: dpRootsUserCustomized.put(uid, state ? Boolean.TRUE
075: : Boolean.FALSE);
076: }
077:
078: public static boolean hasCustomized(String uid) {
079: Boolean customized = (Boolean) dpRootsUserCustomized.get(uid);
080: if (customized != null) {
081: return customized.booleanValue();
082: } else {
083: return false;
084: }
085: }
086:
087: // Map of (ConfigKey, DPRoot). Stores parsed Shared-DPs. Shared-DPs are non-User-DPs or non-Customized-DPs.
088: private static Map dpRootsShared = Collections
089: .synchronizedMap(new HashMap());
090:
091: // ConfigTable of (ConfigKey, Long). Stores last read times for Shared-DPs.
092: private static ConfigTable lastReadTimesDPSharedDocuments = new ConfigTable(
093: Collections.synchronizedMap(new HashMap()));
094:
095: // Map of (ConfigKey, Long). Stores last scan times for Shared-DPs.
096: private static Map lastScanTimesDPSharedDocuments = Collections
097: .synchronizedMap(new HashMap());
098:
099: // Map of (uniqueKey, DPRoot). Stores merged DP of Shared-DPs. This is useful when user hasn't customized DP, and
100: // such Shared-DPs are un-modified since last read.
101: private static Map dpRootsDummyUser = Collections
102: .synchronizedMap(new HashMap());
103:
104: // Map of (uniqueKey, Long). Stores last update time for Shared-DP dpRoots.
105: // Helps determine if cached dpRootsDummyUser can be used for this request.
106: private static Map lastUpdateTimesDPRootsDummyUser = Collections
107: .synchronizedMap(new HashMap());
108:
109: private static String getDummyDPRootKey(Set membership) {
110: return membership.toString();
111: }
112:
113: private static DPRoot getDummyUserDPRoot(String uniqueKey) {
114: return (DPRoot) dpRootsDummyUser.get(uniqueKey);
115: }
116:
117: private static void putDummyUserDPRoot(String uniqueKey,
118: DPRoot dpRoot) {
119: dpRootsDummyUser.put(uniqueKey, dpRoot);
120: lastUpdateTimesDPRootsDummyUser.put(uniqueKey, new Long(System
121: .currentTimeMillis()));
122: }
123:
124: private static void removeDummyUserDPRoot(String uniqueKey) {
125: lastUpdateTimesDPRootsDummyUser.remove(uniqueKey);
126: dpRootsDummyUser.remove(uniqueKey);
127: }
128:
129: private static DPRoot getSharedDPRoot(
130: ConfigTable.ConfigKey configKey) {
131: return (DPRoot) dpRootsShared.get(configKey);
132: }
133:
134: private static void putSharedDPRoot(
135: ConfigTable.ConfigKey configKey, DPRoot dpRoot) {
136: dpRootsShared.put(configKey, dpRoot);
137: }
138:
139: private static List getMergers(Set configKeys) {
140: List mergers = new ArrayList();
141:
142: Iterator iterator = configKeys.iterator();
143: while (iterator.hasNext()) {
144: ConfigTable.ConfigKey configKey = (ConfigTable.ConfigKey) iterator
145: .next();
146:
147: DPRoot dpr = getSharedDPRoot(configKey);
148: if (dpr != null) {
149: mergers.add(dpr);
150: }
151: }
152:
153: return mergers;
154: }
155:
156: private static void updateDummyUserDPRoots(DPContext dpc,
157: Set setMembership) {
158: Set copySetMembership = new TreeSet();
159: copySetMembership.addAll(setMembership); // Work on copy of setMembership
160:
161: ConfigTable.ConfigKey[] memberships = (ConfigTable.ConfigKey[]) copySetMembership
162: .toArray(new ConfigTable.ConfigKey[copySetMembership
163: .size()]);
164: int i = memberships.length - 1;
165: while (!copySetMembership.isEmpty()) {
166: DPRoot dpRootDummyUser = new XMLDPRoot(dpc);
167: List mergers = getMergers(copySetMembership);
168: dpRootDummyUser.addMergers(mergers);
169: String uniqueKey = getDummyDPRootKey(copySetMembership);
170: putDummyUserDPRoot(uniqueKey, dpRootDummyUser);
171: copySetMembership.remove(memberships[i--]);
172: }
173: }
174:
175: private static void updateSharedDPRoots(DPContext dpc,
176: ConfigTable configTable, Set membership) {
177: Set configKeys = configTable.getConfigKeys();
178: Iterator iterator = configKeys.iterator();
179:
180: while (iterator.hasNext()) {
181: ConfigTable.ConfigKey configKey = (ConfigTable.ConfigKey) iterator
182: .next();
183: byte[] dp = (byte[]) configTable.get(configKey);
184: InputStream is = new ByteArrayInputStream(dp);
185: DPRoot dprMerger = new XMLDPRoot(dpc, is);
186: putSharedDPRoot(configKey, dprMerger);
187: }
188:
189: updateDummyUserDPRoots(dpc, membership);
190: }
191:
192: private static Set getFetchOrScanMembership(
193: Set effectiveMembership, int dpScanInterval) {
194: if (dpScanInterval == DP_SCAN_INTERVAL_ALWAYS) {
195: // All shared-DPs or membership DPs should be checked for update.
196: return effectiveMembership;
197: }
198:
199: Set result = new TreeSet();
200: if (dpScanInterval == DP_SCAN_INTERVAL_NEVER) {
201: // Shared-DPs that have not been fetched earlier have to be read anyway.
202:
203: Iterator iterator = effectiveMembership.iterator();
204: while (iterator.hasNext()) {
205: ConfigTable.ConfigKey configKey = (ConfigTable.ConfigKey) iterator
206: .next();
207: if (lastScanTimesDPSharedDocuments.get(configKey) == null) {
208: result.add(configKey);
209: }
210: }
211: } else {
212: // Shared-DPs whose last scan happened more than dpScanInterval seconds have to be scanned for update.
213: // Shared-DPs that have not been fetched earlier have to be read anyway.
214:
215: long currentTime = System.currentTimeMillis();
216: Iterator iterator = effectiveMembership.iterator();
217: while (iterator.hasNext()) {
218: ConfigTable.ConfigKey configKey = (ConfigTable.ConfigKey) iterator
219: .next();
220: Long lastScanTime = (Long) lastScanTimesDPSharedDocuments
221: .get(configKey);
222: if (lastScanTime == null) {
223: result.add(configKey);
224: } else if ((currentTime - lastScanTime.longValue()) > dpScanInterval * 1000) {
225: result.add(configKey);
226: }
227: }
228: }
229:
230: return (result.size() == 0) ? null : result;
231: }
232:
233: private static void updateSharedDPDocumentsScanTimes(
234: Set scanMembership, int dpScanInterval) {
235: if (scanMembership == null) {
236: return;
237: }
238:
239: if (dpScanInterval == DP_SCAN_INTERVAL_ALWAYS) {
240: // If we're scanning DPDocuments always, no need to maintain the
241: // lastScanTimesDPSharedDocuments map.
242: return;
243: }
244:
245: Long currentTime = new Long(System.currentTimeMillis());
246: Iterator iterator = scanMembership.iterator();
247: while (iterator.hasNext()) {
248: ConfigTable.ConfigKey configKey = (ConfigTable.ConfigKey) iterator
249: .next();
250: lastScanTimesDPSharedDocuments.put(configKey, currentTime);
251: }
252: }
253:
254: private static boolean checkDPRootDummyUserForUpdate(
255: int dpScanInterval, String uniqueKey,
256: Set effectiveMembership) {
257: if (dpScanInterval == DP_SCAN_INTERVAL_NEVER) {
258: return false;
259: }
260:
261: boolean modified = false;
262: Long lastDPRootDummyUserUpdateTime = (Long) lastUpdateTimesDPRootsDummyUser
263: .get(uniqueKey);
264: if (lastDPRootDummyUserUpdateTime == null) {
265: return modified;
266: }
267:
268: if (effectiveMembership != null) {
269: // We've to check update times for every Shared-DP that is part
270: // of effectiveMembership with lastDPRootDummyUserUpdateTime
271: Iterator iterator = effectiveMembership.iterator();
272: while (iterator.hasNext()) {
273: ConfigTable.ConfigKey configKey = (ConfigTable.ConfigKey) iterator
274: .next();
275: Long lastReadTimeDPSharedDocument = (Long) lastReadTimesDPSharedDocuments
276: .get(configKey);
277: if ((lastReadTimeDPSharedDocument != null)
278: && (lastReadTimeDPSharedDocument.longValue() > lastDPRootDummyUserUpdateTime
279: .longValue())) {
280: modified = true;
281: break;
282: }
283: }
284: }
285:
286: return modified;
287: }
288:
289: public static boolean sharedDPRootsModified(CMCUser cu,
290: Set effectiveMembership, DPContext dpc, int dpScanInterval) {
291: boolean modified = false;
292: ConfigTable configTable = null;
293:
294: String uniqueKey = getDummyDPRootKey(effectiveMembership);
295: Set fetchOrScanMembership = getFetchOrScanMembership(
296: effectiveMembership, dpScanInterval);
297: if (fetchOrScanMembership != null) {
298: try {
299: configTable = cu.getDPDocuments(
300: lastReadTimesDPSharedDocuments,
301: fetchOrScanMembership);
302:
303: // Even if DP is not set for any of the membership in data source,
304: // we update scan time for all membership so that next call to
305: // cu.getDPDocuments(...) gets avoided.
306: updateSharedDPDocumentsScanTimes(effectiveMembership,
307: dpScanInterval);
308:
309: if (configTable.size() > 0) {
310: removeDummyUserDPRoot(uniqueKey);
311: updateSharedDPRoots(dpc, configTable,
312: effectiveMembership);
313: modified = true;
314: }
315: } catch (CMCException e) {
316: throw new ContextError(
317: "DPCacheManager.sharedDPRootsModified()", e);
318: }
319: }
320:
321: if (!modified) {
322: // Check if any of the Shared-DP has been updated in cache for all
323: // Shared-DPs that form user's membership
324: modified = checkDPRootDummyUserForUpdate(dpScanInterval,
325: uniqueKey, effectiveMembership);
326: if (modified) {
327: removeDummyUserDPRoot(uniqueKey);
328: }
329: }
330:
331: return modified;
332: }
333:
334: private static void addMergers(DPRoot dpRoot, Set membership) {
335: List mergers = getMergers(membership);
336: dpRoot.addMergers(mergers);
337: }
338:
339: public static DPRoot getDPRoot(Set effectiveMembership,
340: DPContext dpc, DPUserContext dpuc, boolean personalize) {
341: DPRoot result = null;
342:
343: // Check if dummyUserDPRoot can be returned quickly
344: if (!personalize) {
345: String uniqueKey = getDummyDPRootKey(effectiveMembership);
346: DPRoot dpRootDummyUser = getDummyUserDPRoot(uniqueKey);
347: if (dpRootDummyUser != null) {
348: result = dpRootDummyUser;
349: }
350: }
351:
352: // Either dummyUserDPRoot is not set, or we're really working with user DP
353: if (result == null) {
354: byte[] userDoc = dpuc.getDPUserDocument();
355: if (userDoc == null || userDoc.length == 0) {
356: result = new XMLDPRoot(dpc);
357: } else {
358: ByteArrayInputStream s = new ByteArrayInputStream(
359: userDoc);
360: result = new XMLDPRoot(dpc, s);
361: }
362:
363: addMergers(result, effectiveMembership);
364:
365: if (!personalize) {
366: // Set dummyUserDPRoot in cache for quick reference
367: String uniqueKey = getDummyDPRootKey(effectiveMembership);
368: putDummyUserDPRoot(uniqueKey, result);
369: }
370: }
371:
372: return result;
373: }
374: }
|