001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/entity/tags/sakai_2-4-1/entity-util/util/src/java/org/sakaiproject/util/BaseResourceProperties.java $
003: * $Id: BaseResourceProperties.java 17599 2006-10-30 17:27:33Z ggolden@umich.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.util;
021:
022: import java.util.Enumeration;
023: import java.util.Hashtable;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Properties;
027: import java.util.Stack;
028: import java.util.Vector;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.sakaiproject.content.cover.ContentTypeImageService;
033: import org.sakaiproject.entity.api.EntityPropertyNotDefinedException;
034: import org.sakaiproject.entity.api.EntityPropertyTypeException;
035: import org.sakaiproject.entity.api.ResourceProperties;
036: import org.sakaiproject.exception.EmptyException;
037: import org.sakaiproject.exception.TypeException;
038: import org.sakaiproject.time.api.Time;
039: import org.sakaiproject.time.cover.TimeService;
040: import org.sakaiproject.user.api.User;
041: import org.sakaiproject.user.cover.UserDirectoryService;
042: import org.w3c.dom.Document;
043: import org.w3c.dom.Element;
044: import org.w3c.dom.Node;
045: import org.w3c.dom.NodeList;
046:
047: /**
048: * <p>
049: * BaseResourceProperties is the base class for ResourceProperties implementations.
050: * </p>
051: */
052: public class BaseResourceProperties implements ResourceProperties {
053: /** Our logger. */
054: private static Log M_log = LogFactory
055: .getLog(BaseResourceProperties.class);
056:
057: /** A fixed class serian number. */
058: private static final long serialVersionUID = 1L;
059:
060: /** The hashtable of properties. */
061: protected Hashtable m_props = null;
062:
063: /** If the full properties have not yet been read. */
064: protected transient boolean m_lazy = false;
065:
066: /**
067: * Construct.
068: */
069: public BaseResourceProperties() {
070: m_props = new Hashtable();
071: }
072:
073: /**
074: * Construct from XML.
075: *
076: * @param el
077: * The XML DOM element.
078: */
079: public BaseResourceProperties(Element el) {
080: this ();
081:
082: // the children (property)
083: NodeList children = el.getChildNodes();
084: final int length = children.getLength();
085: for (int i = 0; i < length; i++) {
086: Node child = children.item(i);
087: if (child.getNodeType() != Node.ELEMENT_NODE)
088: continue;
089: Element element = (Element) child;
090:
091: // look for property
092: if (element.getTagName().equals("property")) {
093: String name = element.getAttribute("name");
094: String enc = StringUtil.trimToNull(element
095: .getAttribute("enc"));
096: String value = null;
097: if ("BASE64".equalsIgnoreCase(enc)) {
098: value = Xml.decodeAttribute(element, "value");
099: } else {
100: value = element.getAttribute("value");
101: }
102:
103: // deal with multiple valued lists
104: if ("list".equals(element.getAttribute("list"))) {
105: // accumulate multiple values in a list
106: Object current = m_props.get(name);
107:
108: // if we don't have a value yet, make a list to hold this one
109: if (current == null) {
110: List values = new Vector();
111: m_props.put(name, values);
112: values.add(value);
113: }
114:
115: // if we do and it's a list, add this one
116: else if (current instanceof List) {
117: ((List) current).add(value);
118: }
119:
120: // if it's not a list, it's wrong!
121: else {
122: M_log
123: .warn("construct(el): value set not a list: "
124: + name);
125: }
126: } else {
127: m_props.put(name, value);
128: }
129: }
130: }
131: }
132:
133: /**
134: * Serialize the resource into XML, adding an element to the doc under the top of the stack element.
135: *
136: * @param doc
137: * The DOM doc to contain the XML (or null for a string return).
138: * @param stack
139: * The DOM elements, the top of which is the containing element of the new "resource" element.
140: * @return The newly added element.
141: */
142: public Element toXml(Document doc, Stack stack) {
143: Element properties = doc.createElement("properties");
144: ((Element) stack.peek()).appendChild(properties);
145: Enumeration props = m_props.keys();
146: while (props.hasMoreElements()) {
147: String name = (String) props.nextElement();
148: Object value = m_props.get(name);
149: if (value instanceof String) {
150: Element propElement = doc.createElement("property");
151: properties.appendChild(propElement);
152: propElement.setAttribute("name", name);
153:
154: // encode to allow special characters in the value
155: Xml.encodeAttribute(propElement, "value",
156: (String) value);
157: propElement.setAttribute("enc", "BASE64");
158: } else if (value instanceof List) {
159: for (Iterator iValues = ((List) value).iterator(); iValues
160: .hasNext();) {
161: Object val = iValues.next();
162: if (val instanceof String) {
163: Element propElement = doc
164: .createElement("property");
165: properties.appendChild(propElement);
166: propElement.setAttribute("name", name);
167: Xml.encodeAttribute(propElement, "value",
168: (String) val);
169: propElement.setAttribute("enc", "BASE64");
170: propElement.setAttribute("list", "list");
171: } else {
172: M_log.warn(".toXml: in list not string: "
173: + name);
174: }
175: }
176: } else {
177: M_log
178: .warn(".toXml: not a string, not a value: "
179: + name);
180: }
181: }
182:
183: return properties;
184: }
185:
186: public boolean isLazy() {
187: return m_lazy;
188: }
189:
190: /**
191: * Access an iterator on the names of the defined properties (Strings).
192: *
193: * @return An iterator on the names of the defined properties (Strings) (may be empty).
194: */
195: public Iterator getPropertyNames() {
196: if (m_props.size() == 0) {
197: return new EmptyIterator();
198: }
199:
200: return new EnumerationIterator(m_props.keys());
201: }
202:
203: /**
204: * Access a named property as a string (won't find multi-valued ones.)
205: *
206: * @param name
207: * The property name.
208: * @return the property value, or null if not found.
209: */
210: public String getProperty(String name) {
211: Object value = m_props.get(name);
212: if (value instanceof String)
213: return (String) value;
214:
215: return null;
216: }
217:
218: /**
219: * {@inheritDoc}
220: */
221: public Object get(String name) {
222: return m_props.get(name);
223: }
224:
225: /**
226: * Access a named property as a List of (String), good for single or multi-valued properties.
227: *
228: * @param name
229: * The property name.
230: * @return the property value, or null if not found.
231: */
232: public List getPropertyList(String name) {
233: Object value = m_props.get(name);
234: if (value == null)
235: return null;
236:
237: if (value instanceof String) {
238: List rv = new Vector();
239: rv.add(value);
240: return rv;
241: }
242:
243: else if (value instanceof List) {
244: List rv = new Vector();
245: rv.addAll((List) value);
246: return rv;
247: }
248:
249: return null;
250: }
251:
252: /**
253: * Check if a named property is a live one (auto updated).
254: *
255: * @param name
256: * The property name.
257: * @return True if the property is a live one, false if not.
258: */
259: public boolean isLiveProperty(String name) {
260: if ((name.equals(PROP_CREATOR))
261: || (name.equals(PROP_MODIFIED_BY))
262: || (name.equals(PROP_CREATION_DATE))
263: || (name.equals(PROP_CONTENT_LENGTH))
264: || (name.equals(PROP_CONTENT_TYPE))
265: || (name.equals(PROP_MODIFIED_DATE))
266: || (name.equals(PROP_IS_COLLECTION))) {
267: return true;
268: }
269:
270: return false;
271: }
272:
273: /**
274: * Access a named property as a properly formatted string.
275: *
276: * @param name
277: * The property name.
278: * @return the property value, or an empty string if not found.
279: */
280: public String getPropertyFormatted(String name) {
281: Object value = m_props.get(name);
282:
283: // if missing, return blank
284: if (value == null)
285: return "";
286:
287: if (value instanceof String) {
288: try {
289: // check all known properties...
290:
291: // User
292: if ((name.equals(PROP_CREATOR))
293: || (name.equals(PROP_MODIFIED_BY))
294: || name.equals(PROP_TO)) {
295: return getUserProperty(name).getDisplayName(); // %%% no user?
296: }
297:
298: // Time
299: else if ((name.equals(PROP_CREATION_DATE))
300: || (name.equals(PROP_MODIFIED_DATE))) {
301: return getTimeProperty(name).toStringLocalFull();
302: }
303:
304: // content length- in kb
305: else if (name.equals(PROP_CONTENT_LENGTH)) {
306: long len = getLongProperty(name);
307: String[] byteString = { "KB", "KB", "MB", "GB" };
308: int count = 0;
309: long newLen = 0;
310: long lenBytesExtra = len;
311:
312: while (len > 1024) {
313: newLen = len / 1024;
314: lenBytesExtra = len - (newLen * 1024);
315: len = newLen;
316: count++;
317: }
318:
319: if ((lenBytesExtra >= 512)
320: || ((lenBytesExtra > 0) && (newLen == 0))) {
321: newLen++;
322: }
323:
324: return Long.toString(newLen) + " "
325: + byteString[count];
326: }
327:
328: // content type
329: else if (name.equals(PROP_CONTENT_TYPE)) {
330: return ContentTypeImageService
331: .getContentTypeDisplayName((String) value);
332: }
333: } catch (EntityPropertyNotDefinedException e) {
334: return "";
335: } catch (EntityPropertyTypeException e) {
336: }
337:
338: // all else failed, so just return the value
339: return (String) value;
340: }
341:
342: else if (value instanceof List) {
343: StringBuffer buf = new StringBuffer();
344: for (Iterator i = ((List) value).iterator(); i.hasNext();) {
345: String val = (String) i.next();
346: buf.append(val);
347: if (i.hasNext()) {
348: buf.append(", ");
349: }
350: }
351: return buf.toString();
352: }
353:
354: else {
355: M_log
356: .warn("getPropertyFormatted: value not string, not list: "
357: + name);
358: return "";
359: }
360: }
361:
362: /**
363: * Access a named property as a boolean.
364: *
365: * @param name
366: * The property name.
367: * @return the property value.
368: * @exception EmptyException
369: * if not found.
370: * @exception TypeException
371: * if the property is found but not a boolean.
372: */
373: public boolean getBooleanProperty(String name)
374: throws EntityPropertyNotDefinedException,
375: EntityPropertyTypeException {
376: String p = getProperty(name);
377: if (p == null)
378: throw new EntityPropertyNotDefinedException();
379: try {
380: return Boolean.valueOf(p).booleanValue();
381: } catch (Exception any) {
382: throw new EntityPropertyTypeException(name);
383: }
384:
385: }
386:
387: /**
388: * Access a named property as a long.
389: *
390: * @param name
391: * The property name.
392: * @return the property value.
393: * @exception EmptyException
394: * if not found.
395: * @exception TypeException
396: * if the property is found but not a long.
397: */
398: public long getLongProperty(String name)
399: throws EntityPropertyNotDefinedException,
400: EntityPropertyTypeException {
401: String p = getProperty(name);
402: if (p == null)
403: throw new EntityPropertyNotDefinedException();
404: try {
405: return Long.parseLong(p);
406: } catch (Exception any) {
407: throw new EntityPropertyTypeException(name);
408: }
409: }
410:
411: /**
412: * Access a named property as a Time.
413: *
414: * @param name
415: * The property name.
416: * @return the property value
417: * @exception EmptyException
418: * if not found.
419: * @exception TypeException
420: * if the property is found but not a Time.
421: */
422: public Time getTimeProperty(String name)
423: throws EntityPropertyNotDefinedException,
424: EntityPropertyTypeException {
425: String p = getProperty(name);
426: if (p == null)
427: throw new EntityPropertyNotDefinedException();
428: try {
429: return TimeService.newTimeGmt(p);
430: } catch (Exception any) {
431: throw new EntityPropertyTypeException(name);
432: }
433:
434: } // getTimeProperty
435:
436: /**
437: * Access a named property as a User.
438: *
439: * @param name
440: * The property name.
441: * @return the property value
442: * @exception EmptyException
443: * if not found.
444: * @exception TypeException
445: * if the property is found but not a User.
446: */
447: public User getUserProperty(String name)
448: throws EntityPropertyNotDefinedException,
449: EntityPropertyTypeException {
450: String p = getProperty(name);
451: if (p == null)
452: throw new EntityPropertyNotDefinedException();
453: try {
454: return UserDirectoryService.getUser(p);
455: } catch (Exception any) {
456: throw new EntityPropertyTypeException(name);
457: }
458: }
459:
460: /**
461: * Get the static String of PROP_CREATOR
462: *
463: * @return The static String of PROP_CREATOR
464: */
465: public String getNamePropCreator() {
466: return PROP_CREATOR;
467: }
468:
469: /**
470: * Get the static String of PROP_MODIFIED_BY
471: *
472: * @return The static String of PROP_MODIFIED_BY
473: */
474: public String getNamePropModifiedBy() {
475: return PROP_MODIFIED_BY;
476: }
477:
478: /**
479: * Get the static String of PROP_CREATION_DATE
480: *
481: * @return The static String of PROP_CREATION_DATE
482: */
483: public String getNamePropCreationDate() {
484: return PROP_CREATION_DATE;
485: }
486:
487: /**
488: * Get the static String of PROP_DISPLAY_NAME
489: *
490: * @return The static String of PROP_DISPLAY_NAME
491: */
492: public String getNamePropDisplayName() {
493: return PROP_DISPLAY_NAME;
494: }
495:
496: /**
497: * Get the static String of PROP_COPYRIGHT_CHOICE
498: *
499: * @return The static String of PROP_COPYRIGHT_CHOICE
500: */
501: public String getNamePropCopyrightChoice() {
502: return PROP_COPYRIGHT_CHOICE;
503: }
504:
505: /**
506: * Get the static String of PROP_COPYRIGHT_ALERT
507: *
508: * @return The static String of PROP_COPYRIGHT_ALERT
509: */
510: public String getNamePropCopyrightAlert() {
511: return PROP_COPYRIGHT_ALERT;
512: }
513:
514: /**
515: * Get the static String of PROP_COPYRIGHT
516: *
517: * @return The static String of PROP_COPYRIGHT
518: */
519: public String getNamePropCopyright() {
520: return PROP_COPYRIGHT;
521: }
522:
523: /**
524: * Get the static String of PROP_CONTENT_LENGTH
525: *
526: * @return The static String of PROP_CONTENT_LENGTH
527: */
528: public String getNamePropContentLength() {
529: return PROP_CONTENT_LENGTH;
530: }
531:
532: /**
533: * Get the static String of PROP_CONTENT_TYPE
534: *
535: * @return The static String of PROP_CONTENT_TYPE
536: */
537: public String getNamePropContentType() {
538: return PROP_CONTENT_TYPE;
539: }
540:
541: /**
542: * Get the static String of PROP_MODIFIED_DATE
543: *
544: * @return The static String of PROP_MODIFIED_DATE
545: */
546: public String getNamePropModifiedDate() {
547: return PROP_MODIFIED_DATE;
548: }
549:
550: /**
551: * Get the static String of PROP_IS_COLLECTION
552: *
553: * @return The static String of PROP_IS_COLLECTION
554: */
555: public String getNamePropIsCollection() {
556: return PROP_IS_COLLECTION;
557: }
558:
559: /**
560: * Get the static String of PROP_COLLECTION_BODY_QUOTA
561: *
562: * @return The static String of PROP_COLLECTION_BODY_QUOTA
563: */
564: public String getNamePropCollectionBodyQuota() {
565: return PROP_COLLECTION_BODY_QUOTA;
566: }
567:
568: /**
569: * Get the static String of PROP_CHAT_ROOM
570: *
571: * @return The static String of PROP_CHAT_ROOM
572: */
573: public String getNamePropChatRoom() {
574: return PROP_CHAT_ROOM;
575: }
576:
577: /**
578: * Get the static String of PROP_TO
579: *
580: * @return The static String of PROP_TO
581: */
582: public String getNamePropTo() {
583: return PROP_TO;
584: }
585:
586: /**
587: * Get the static String of PROP_DESCRIPTION
588: *
589: * @return The static String of PROP_DESCRIPTION
590: */
591: public String getNamePropDescription() {
592: return PROP_DESCRIPTION;
593: }
594:
595: /**
596: * Get the static String of PROP_CALENDAR_TYPE
597: *
598: * @return The static String of PROP_CALENDAR_TYPE
599: */
600: public String getNamePropCalendarType() {
601: return PROP_CALENDAR_TYPE;
602: }
603:
604: /**
605: * Get the static String of PROP_CALENDAR_LOCATION
606: *
607: * @return The static String of PROP_CALENDAR_LOCATION
608: */
609: public String getNamePropCalendarLocation() {
610: return PROP_CALENDAR_LOCATION;
611: }
612:
613: /**
614: * Get the static String of PROP_REPLY_STYLE
615: *
616: * @return The static String of PROP_REPLY_STYLE
617: */
618: public String getNamePropReplyStyle() {
619: return PROP_REPLY_STYLE;
620: }
621:
622: /**
623: * Get the static String of NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE
624: *
625: * @return The static String of NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE
626: */
627: public String getNamePropNewAssignmentCheckAddDueDate() {
628: return NEW_ASSIGNMENT_CHECK_ADD_DUE_DATE;
629: }
630:
631: /**
632: * Get the static String of NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE
633: *
634: * @return The static String of NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE
635: */
636: public String getNamePropNewAssignmentCheckAutoAnnounce() {
637: return NEW_ASSIGNMENT_CHECK_AUTO_ANNOUNCE;
638: }
639:
640: /**
641: * Get the static String of PROP_SUBMISSION_PREVIOUS_GRADES
642: *
643: * @return The static String of PROP_SUBMISSION_PREVIOUS_GRADES
644: */
645: public String getNamePropSubmissionPreviousGrades() {
646: return PROP_SUBMISSION_PREVIOUS_GRADES;
647: }
648:
649: /**
650: * Get the static String of PROP_SUBMISSION_SCALED_PREVIOUS_GRADES
651: *
652: * @return The static String of PROP_SUBMISSION_SCALED_PREVIOUS_GRADES
653: */
654: public String getNamePropSubmissionScaledPreviousGrades() {
655: return PROP_SUBMISSION_SCALED_PREVIOUS_GRADES;
656: }
657:
658: /**
659: * Get the static String of PROP_SUBMISSION_PREVIOUS_FEEDBACK_TEXT
660: *
661: * @return The static String of PROP_SUBMISSION_PREVIOUS_FEEDBACK_TEXT
662: */
663: public String getNamePropSubmissionPreviousFeedbackText() {
664: return PROP_SUBMISSION_PREVIOUS_FEEDBACK_TEXT;
665: }
666:
667: /**
668: * Get the static String of PROP_SUBMISSION_PREVIOUS_FEEDBACK_COMMENT
669: *
670: * @return The static String of PROP_SUBMISSION_PREVIOUS_FEEDBACK_COMMENT
671: */
672: public String getNamePropSubmissionPreviousFeedbackComment() {
673: return PROP_SUBMISSION_PREVIOUS_FEEDBACK_COMMENT;
674: }
675:
676: /**
677: * Get the static String of PROP_ASSIGNMENT_DELETED
678: *
679: * @return The static String of PROP_ASSIGNMENT_DELETED
680: */
681: public String getNamePropAssignmentDeleted() {
682: return PROP_ASSIGNMENT_DELETED;
683: }
684:
685: /**
686: * Get the static String of TYPE_URL
687: *
688: * @return The static String of TYPE_URL
689: */
690: public String getTypeUrl() {
691: return TYPE_URL;
692: }
693:
694: /**
695: * Get the static String of PROP_STRUCTOBJ_TYPE
696: *
697: * @return The static String of PROP_STRUCTOBJ_TYPE
698: */
699: public String getNamePropStructObjType() {
700: return PROP_STRUCTOBJ_TYPE;
701: }
702:
703: /**
704: * {@inheritDoc}
705: */
706: public void setLazy(boolean lazy) {
707: m_lazy = lazy;
708: }
709:
710: /**
711: * Add a single valued property.
712: *
713: * @param name
714: * The property name.
715: * @param value
716: * The property value.
717: */
718: public void addProperty(String name, String value) {
719: // protect against a null put
720: if (value == null)
721: value = "";
722:
723: m_props.put(name, value);
724: }
725:
726: /**
727: * Add a value to a multi-valued property.
728: *
729: * @param name
730: * The property name.
731: * @param value
732: * The property value.
733: */
734: public void addPropertyToList(String name, String value) {
735: // protect against a null put
736: if (value == null)
737: value = "";
738:
739: // accumulate multiple values in a list
740: Object current = m_props.get(name);
741:
742: // if we don't have a value yet, make a list to hold this one
743: if (current == null) {
744: List values = new Vector();
745: m_props.put(name, values);
746: values.add(value);
747: }
748:
749: // if we do and it's a list, add this one
750: else if (current instanceof List) {
751: ((List) current).add(value);
752: }
753:
754: // if it's not a list, it's wrong!
755: else {
756: M_log.warn("addPropertyToList() value set not a list: "
757: + name);
758: }
759: }
760:
761: /**
762: * Add all the properties from the other ResourceProperties object.
763: *
764: * @param other
765: * The ResourceProperties to add.
766: */
767: public void addAll(ResourceProperties other) {
768: for (Iterator iNames = other.getPropertyNames(); iNames
769: .hasNext();) {
770: String name = (String) iNames.next();
771:
772: // use the general accessor for String or List return
773: Object value = other.get(name);
774:
775: if (value != null) {
776: // Strings are immutable so can be placed directly in
777: if (value instanceof String) {
778: m_props.put(name, value);
779: }
780:
781: // deep copy the list
782: else if (value instanceof List) {
783: List list = new Vector();
784: list.addAll((List) value);
785: m_props.put(name, list);
786: }
787: }
788: }
789: }
790:
791: /**
792: * Add all the properties from the Properties object.
793: *
794: * @param props
795: * The Properties to add.
796: */
797: public void addAll(Properties props) {
798: // if there's a list, it must be deep copied
799: for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
800: String name = (String) e.nextElement();
801: Object value = props.get(name);
802: if (value instanceof List) {
803: List list = new Vector();
804: list.addAll((List) value);
805: m_props.put(name, list);
806: } else {
807: m_props.put(name, value);
808: }
809: }
810: }
811:
812: /**
813: * Remove all properties.
814: */
815: public void clear() {
816: m_props.clear();
817: }
818:
819: /**
820: * Remove a property.
821: *
822: * @param name
823: * The property name.
824: */
825: public void removeProperty(String name) {
826: m_props.remove(name);
827: }
828:
829: /**
830: * Take all values from this object.
831: *
832: * @param user
833: * The ResourceProperties object to take values from.
834: */
835: public void set(ResourceProperties props) {
836: clear();
837: addAll(props);
838: }
839: }
|