001: /* Copyright 2005 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.layout.dlm;
007:
008: import java.util.ArrayList;
009: import java.util.Collections;
010: import java.util.Enumeration;
011: import java.util.HashSet;
012: import java.util.Hashtable;
013: import java.util.List;
014: import java.util.Set;
015:
016: import org.apache.commons.logging.Log;
017: import org.apache.commons.logging.LogFactory;
018: import org.jasig.portal.StructureStylesheetUserPreferences;
019: import org.jasig.portal.ThemeStylesheetUserPreferences;
020:
021: /**
022: * Distributed layout Extension to user preferences object for stylesheets
023: * performing structure or theme transformation. This extension adds support
024: * for user preferences set by layout owneres in incorporated elements.
025: * @author Mark Boyd <a href="mailto:">mboyd@campuspipeline.com</a>
026: * @version $Revision: 36684 $ $Date: 2006-08-24 00:56:17 -0700 (Thu, 24 Aug 2006) $
027: * @since uPortal 2.5
028: */
029:
030: public class DistributedUserPreferences extends
031: StructureStylesheetUserPreferences {
032: public static final String RCS_ID = "@(#) $Header$";
033: private static Log LOG = LogFactory
034: .getLog(DistributedUserPreferences.class);
035:
036: protected Hashtable incorporatedChannelAttributeValues;
037: protected Hashtable incorporatedFolderAttributeValues;
038:
039: /**
040: * Creates a new DistributedUserPreferences object with empty tables.
041: *
042: */
043: public DistributedUserPreferences() {
044: super ();
045: this .incorporatedChannelAttributeValues = new Hashtable();
046: this .incorporatedFolderAttributeValues = new Hashtable();
047: }
048:
049: /**
050: * Creates a DistributedUserPreferences with values for super classes
051: * derived from those of the passed in StructureStylesheetUserPreferences
052: * object.
053: *
054: * @param ssup
055: */
056: public DistributedUserPreferences(
057: StructureStylesheetUserPreferences ssup) {
058: super (ssup);
059: this .incorporatedChannelAttributeValues = new Hashtable();
060: this .incorporatedFolderAttributeValues = new Hashtable();
061: }
062:
063: /**
064: * If instantiated with a theme stylesheet preferences then this object
065: * should only be used in place of a theme stylesheet user prefs since
066: * structure stylesheet oriented variables will not be initialized.
067: */
068: public DistributedUserPreferences(
069: ThemeStylesheetUserPreferences tsup) {
070: super (tsup);
071: this .incorporatedChannelAttributeValues = new Hashtable();
072: }
073:
074: /**
075: * Creates a new DistributedUserPreferences object populated with all values
076: * from the passed-in instance.
077: *
078: * @param dup
079: */
080: public DistributedUserPreferences(DistributedUserPreferences dup) {
081: super ((StructureStylesheetUserPreferences) dup);
082: if (dup.incorporatedChannelAttributeValues != null)
083: this .incorporatedChannelAttributeValues = new Hashtable(
084: dup.incorporatedChannelAttributeValues);
085: if (dup.incorporatedFolderAttributeValues != null)
086: this .incorporatedFolderAttributeValues = new Hashtable(
087: dup.incorporatedFolderAttributeValues);
088: }
089:
090: /**
091: * Provides a copy of this object with all fields instantiated to reflect
092: * the values of this object. This allows subclasses to override to add
093: * correct copying behavior for their added fields.
094: *
095: * @return a copy of this object
096: */
097: public Object newInstance() {
098: return new DistributedUserPreferences(this );
099: }
100:
101: //////////// extensions for structure super class
102:
103: public Enumeration getFolders() {
104: Enumeration userOwned = folderAttributeValues.keys();
105: Enumeration incorporated = incorporatedFolderAttributeValues
106: .keys();
107: Set attribs = new HashSet();
108: while (userOwned.hasMoreElements()) {
109: attribs.add(userOwned.nextElement());
110: }
111: while (incorporated.hasMoreElements()) {
112: attribs.add(incorporated.nextElement());
113: }
114: return Collections.enumeration(attribs);
115: }
116:
117: public boolean hasFolder(String folderId) {
118: return folderAttributeValues.containsKey(folderId)
119: || incorporatedFolderAttributeValues
120: .containsKey(folderId);
121: }
122:
123: /**
124: * Returns the default value for the specified attribute for the specified
125: * folder. Defaults for an attribute may be unique to a folder since an
126: * incorporated value becomes the default value for a fragment user.
127: */
128: public String getDefaultFolderAttributeValue(String folderId,
129: String attributeName) {
130: Integer attributeNumber = (Integer) folderAttributeNumbers
131: .get(attributeName);
132:
133: if (attributeNumber == null) {
134: LOG
135: .error("Attempting to obtain a non-existing attribute \""
136: + attributeName + "\".");
137: return null;
138: }
139: String value = null;
140: List l = (List) incorporatedFolderAttributeValues.get(folderId);
141: // no incorporated value so use default
142: if (l == null) {
143: return (String) defaultFolderAttributeValues
144: .get(attributeNumber.intValue());
145: }
146: // inc'd list found, is it long enough?
147: if (attributeNumber.intValue() < l.size()) {
148: value = (String) l.get(attributeNumber.intValue());
149: }
150: // if not long enough, use default
151: if (value == null) {
152: try {
153: value = (String) defaultFolderAttributeValues
154: .get(attributeNumber.intValue());
155: } catch (IndexOutOfBoundsException e) {
156: LOG
157: .error("Internal Error - attribute name is "
158: + "registered, but no default value is provided.");
159: return null;
160: }
161: }
162: return value;
163: }
164:
165: public String getFolderAttributeValue(String folderId,
166: String attributeName) {
167: Integer attributeNumber = (Integer) folderAttributeNumbers
168: .get(attributeName);
169:
170: if (attributeNumber == null) {
171: LOG
172: .error("Attempting to obtain a non-existing attribute \""
173: + attributeName + "\".");
174: return null;
175: }
176: String value = null;
177: List l = (List) folderAttributeValues.get(folderId);
178: if (l == null) {
179: // user attribute changes not found, any incorporated?
180: l = (List) incorporatedFolderAttributeValues.get(folderId);
181: // non incorporated, use default
182: if (l == null) {
183: return (String) defaultFolderAttributeValues
184: .get(attributeNumber.intValue());
185: }
186: // inc'd list found, is it long enough?
187: if (attributeNumber.intValue() < l.size()) {
188: value = (String) l.get(attributeNumber.intValue());
189: }
190: // if not long enough, use default
191: if (value == null) {
192: try {
193: value = (String) defaultFolderAttributeValues
194: .get(attributeNumber.intValue());
195: } catch (IndexOutOfBoundsException e) {
196: LOG
197: .error("Internal Error - attribute name is "
198: + "registered, but no default value is provided.");
199: return null;
200: }
201: }
202: } else // user attribute changes list found for this folder
203: {
204: // is list long enough for my attribute?
205: if (attributeNumber.intValue() < l.size()) {
206: value = (String) l.get(attributeNumber.intValue());
207: }
208: // if not then delegate to inc'd change if it exists
209: if (value == null) {
210: l = (List) incorporatedFolderAttributeValues
211: .get(folderId);
212: if (l == null) {
213: // no changes recorded in inc'd values, use default
214: try {
215: value = (String) defaultFolderAttributeValues
216: .get(attributeNumber.intValue());
217: } catch (IndexOutOfBoundsException e) {
218: // no default specified, should never occur.
219: LOG
220: .error("Internal Error - attribute name is "
221: + "registered, but no default value is provided.");
222: return null;
223: }
224: } else // inc'd list found, is it long enough?
225: {
226: if (attributeNumber.intValue() < l.size()) {
227: value = (String) l.get(attributeNumber
228: .intValue());
229: }
230: // if not long enough then use default
231: if (value == null) {
232: try {
233: value = (String) defaultFolderAttributeValues
234: .get(attributeNumber.intValue());
235: } catch (IndexOutOfBoundsException e) {
236: LOG
237: .error("Internal Error - attribute name is "
238: + "registered, but no default value is provided.");
239: return null;
240: }
241: }
242: }
243: }
244: }
245: return value;
246: }
247:
248: /**
249: * Sets the value of an attribute to the value that it had on the folder in
250: * the fragment from which it was incorporated. User overrides, if allowed,
251: * are not set here. The setFolderAttributeValue() method is where user
252: * overrides are set and maintained distinctly from the original values had
253: * in the originating fragment.
254: *
255: * @param folderSubscribeId
256: * @param attributeName
257: * @param attributeValue
258: */
259: public void setIncorporatedFolderAttributeValue(
260: String folderSubscribeId, String attributeName,
261: String attributeValue) {
262: Integer attributeNumber = (Integer) folderAttributeNumbers
263: .get(attributeName);
264:
265: if (attributeNumber == null) {
266: LOG
267: .error("Attempting to set a non-existing folder attribute \""
268: + attributeName + "\".");
269: return;
270: }
271: List l = (List) incorporatedFolderAttributeValues
272: .get(folderSubscribeId);
273: if (l == null)
274: l = this .createIncorporatedFolder(folderSubscribeId);
275: try {
276: l.set(attributeNumber.intValue(), attributeValue);
277: } catch (IndexOutOfBoundsException e) {
278: // bring up the array to the right size
279: for (int i = l.size(); i < attributeNumber.intValue(); i++) {
280: l.add((String) null);
281: }
282: l.add(attributeValue);
283: }
284: }
285:
286: public void removeFolder(String folderID) {
287: if (folderAttributeValues.remove(folderID) == null
288: && incorporatedFolderAttributeValues.remove(folderID) == null) {
289: LOG.error("Attempting to remove an non-existing folder "
290: + "(folderID=\"" + folderID + "\") ");
291: }
292: }
293:
294: public void removeChannel(String channelSubscribeId) {
295: if (channelAttributeValues.remove(channelSubscribeId) == null
296: && incorporatedChannelAttributeValues
297: .remove(channelSubscribeId) == null)
298: LOG.error("Attempting to remove an non-existing channel "
299: + "(channelSubscribeId=\"" + channelSubscribeId
300: + "\").");
301: }
302:
303: public void removeDefinedFolderAttributeValue(String folderID,
304: String attributeName) {
305: Integer attributeNumber = (Integer) folderAttributeNumbers
306: .get(attributeName);
307:
308: // if that attribute isn't defined then we are done
309: if (attributeNumber == null)
310: return;
311:
312: List l = (List) folderAttributeValues.get(folderID);
313:
314: // if no atts found for folder then it doesn't have to be removed
315: if (l == null)
316: return;
317: try {
318: l.remove(attributeNumber.intValue());
319: } catch (Exception e) {
320: // if index out of bounds then the value aint' there
321: }
322: }
323:
324: private ArrayList createIncorporatedFolder(String folderID) {
325: ArrayList l = new ArrayList(defaultFolderAttributeValues.size());
326: incorporatedFolderAttributeValues.put(folderID, l);
327: return l;
328: }
329:
330: /**
331: * Used when loading fragment layouts and converting them to their
332: * "fragmentized" version suitable for incorporating into other user's
333: * layouts. One aspect of fragmentization is converting the user and layout
334: * node IDs to globally unique and consistent IDs. This method is used to
335: * replace the folder's user and layout specific ID with its globally
336: * unique value.
337: *
338: * @param oldFolderId
339: * @param newFolderId
340: */
341: public void changeFolderId(String oldFolderId, String newFolderId) {
342: List l = (List) folderAttributeValues.remove(oldFolderId);
343: if (l != null)
344: folderAttributeValues.put(newFolderId, l);
345: }
346:
347: ////////// extensions to theme stylesheet super class for channels
348:
349: public Enumeration getChannels() {
350: Enumeration userOwned = channelAttributeValues.keys();
351: Enumeration incorporated = incorporatedChannelAttributeValues
352: .keys();
353: Set attribs = new HashSet();
354: while (userOwned.hasMoreElements()) {
355: attribs.add(userOwned.nextElement());
356: }
357: while (incorporated.hasMoreElements()) {
358: attribs.add(incorporated.nextElement());
359: }
360: return Collections.enumeration(attribs);
361: }
362:
363: public boolean hasChannel(String chanId) {
364: return channelAttributeValues.containsKey(chanId)
365: || incorporatedChannelAttributeValues
366: .containsKey(chanId);
367: }
368:
369: /**
370: * Returns the default value for the specified attribute for the specified
371: * channel. Defaults for an attribute may be unique to a channel since an
372: * incorporated value becomes the default value for a fragment user.
373: */
374: public String getDefaultChannelAttributeValue(
375: String channelSubscribeId, String attributeName) {
376: Integer attributeNumber = (Integer) channelAttributeNumbers
377: .get(attributeName);
378:
379: if (attributeNumber == null) {
380: LOG
381: .error("Attempting to obtain a non-existing attribute \""
382: + attributeName + "\".");
383: return null;
384: }
385: String value = null;
386: List l = (List) incorporatedChannelAttributeValues
387: .get(channelSubscribeId);
388: // no incorporated value so use default
389: if (l == null) {
390: return (String) defaultChannelAttributeValues
391: .get(attributeNumber.intValue());
392: }
393: // inc'd list found, is it long enough?
394: if (attributeNumber.intValue() < l.size()) {
395: value = (String) l.get(attributeNumber.intValue());
396: }
397: // if not long enough, use default
398: if (value == null) {
399: try {
400: value = (String) defaultChannelAttributeValues
401: .get(attributeNumber.intValue());
402: } catch (IndexOutOfBoundsException e) {
403: LOG
404: .error("Internal Error - attribute name is "
405: + "registered, but no default value is provided.");
406: return null;
407: }
408: }
409: return value;
410: }
411:
412: public String getChannelAttributeValue(String channelSubscribeId,
413: String attributeName) {
414: Integer attributeNumber = (Integer) channelAttributeNumbers
415: .get(attributeName);
416:
417: if (attributeNumber == null) {
418: LOG
419: .error("Attempting to obtain a non-existing attribute \""
420: + attributeName + "\".");
421: return null;
422: }
423: String value = null;
424: List l = (List) channelAttributeValues.get(channelSubscribeId);
425: if (l == null) {
426: // user attribute changes not found, any incorporated?
427: l = (List) incorporatedChannelAttributeValues
428: .get(channelSubscribeId);
429: // non incorporated, use default
430: if (l == null) {
431: return (String) defaultChannelAttributeValues
432: .get(attributeNumber.intValue());
433: }
434: // inc'd list found, is it long enough?
435: if (attributeNumber.intValue() < l.size()) {
436: value = (String) l.get(attributeNumber.intValue());
437: }
438: // if not long enough, use default
439: if (value == null) {
440: try {
441: value = (String) defaultChannelAttributeValues
442: .get(attributeNumber.intValue());
443: } catch (IndexOutOfBoundsException e) {
444: LOG
445: .error("Internal Error - attribute name is "
446: + "registered, but no default value is provided.");
447: return null;
448: }
449: }
450: } else // user attribute changes list found for this channel
451: {
452: // is list long enough for my attribute?
453: if (attributeNumber.intValue() < l.size()) {
454: value = (String) l.get(attributeNumber.intValue());
455: }
456: // if not then delegate to inc'd change if it exists
457: if (value == null) {
458: l = (List) incorporatedChannelAttributeValues
459: .get(channelSubscribeId);
460: if (l == null) {
461: // no changes recorded in inc'd values, use default
462: try {
463: value = (String) defaultChannelAttributeValues
464: .get(attributeNumber.intValue());
465: } catch (IndexOutOfBoundsException e) {
466: // no default specified, should never occur.
467: LOG
468: .error("Internal Error - attribute name is "
469: + "registered, but no default value is provided.");
470: return null;
471: }
472: } else // inc'd list found, is it long enough?
473: {
474: if (attributeNumber.intValue() < l.size()) {
475: value = (String) l.get(attributeNumber
476: .intValue());
477: }
478: // if not long enough then use default
479: if (value == null) {
480: try {
481: value = (String) defaultChannelAttributeValues
482: .get(attributeNumber.intValue());
483: } catch (IndexOutOfBoundsException e) {
484: LOG
485: .error("Internal Error - attribute name is "
486: + "registered, but no default value is provided.");
487: return null;
488: }
489: }
490: }
491: }
492: }
493: return value;
494: }
495:
496: /**
497: * Sets the value of an attribute to the value that it had on the channel in
498: * the fragment from which it was incorporated. User overrides, if allowed,
499: * are not set here. The setChannelAttributeValue() method is where user
500: * overrides are set and maintained distinctly from the original values had
501: * in the originating fragment.
502: *
503: * @param channelSubscribeId
504: * @param attributeName
505: * @param attributeValue
506: */
507: public void setIncorporatedChannelAttributeValue(
508: String channelSubscribeId, String attributeName,
509: String attributeValue) {
510: Integer attributeNumber = (Integer) channelAttributeNumbers
511: .get(attributeName);
512:
513: if (attributeNumber == null) {
514: LOG
515: .error("Attempting to set a non-existing channel attribute \""
516: + attributeName + "\".");
517: return;
518: }
519: List l = (List) incorporatedChannelAttributeValues
520: .get(channelSubscribeId);
521: if (l == null)
522: l = this .createIncorporatedChannel(channelSubscribeId);
523: try {
524: l.set(attributeNumber.intValue(), attributeValue);
525: } catch (IndexOutOfBoundsException e) {
526: // bring up the array to the right size
527: for (int i = l.size(); i < attributeNumber.intValue(); i++) {
528: l.add((String) null);
529: }
530: l.add(attributeValue);
531: }
532: }
533:
534: public void removeDefinedChannelAttributeValue(String channelID,
535: String attributeName) {
536: Integer attributeNumber = (Integer) channelAttributeNumbers
537: .get(attributeName);
538:
539: // if that attribute isn't defined then we are done
540: if (attributeNumber == null)
541: return;
542:
543: List l = (List) channelAttributeValues.get(channelID);
544:
545: // if no atts found for channel then it doesn't have to be removed
546: if (l == null)
547: return;
548: try {
549: l.remove(attributeNumber.intValue());
550: } catch (Exception e) {
551: // if index out of bounds then the value aint' there
552: }
553: return;
554: }
555:
556: private ArrayList createIncorporatedChannel(
557: String channelSubscribeId) {
558: ArrayList l = new ArrayList(defaultChannelAttributeValues
559: .size());
560: incorporatedChannelAttributeValues.put(channelSubscribeId, l);
561: return l;
562: }
563:
564: /**
565: * Used when loading fragment layouts and converting them to their
566: * "fragmentized" version suitable for incorporating into other user's
567: * layouts. One aspect of fragmentization is converting the user and layout
568: * node IDs to globally unique and consistent IDs. This method is used to
569: * replace the channel's user and layout specific ID with its globally
570: * unique value.
571: *
572: * @param oldChannelId
573: * @param newChannelId
574: */
575: public void changeChannelId(String oldChannelId, String newChannelId) {
576: List l = (List) channelAttributeValues.remove(oldChannelId);
577: if (l != null)
578: channelAttributeValues.put(newChannelId, l);
579: }
580: }
|