001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: Content.java 3634 2007-01-08 21:42:24Z gbevin $
007: */
008: package com.uwyn.rife.cmf;
009:
010: import com.uwyn.rife.tools.ExceptionUtils;
011: import java.util.HashMap;
012: import java.util.Map;
013: import java.util.logging.Logger;
014:
015: /**
016: * Contains the information required to store new content data together with
017: * additional meta-data.
018: * <p>All content is determined by its mime type and the raw data that will be
019: * used to load the content. The type of the data is dependent on the mime
020: * type.
021: * <p>For example, images can be loaded from byte arrays and texts can be
022: * loaded from strings. If an unsupported data type is used or the format is
023: * incorrect, suitable exceptions will be thrown when the content is stored in
024: * the back-end.
025: *
026: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
027: * @version $Revision: 3634 $
028: * @since 1.0
029: */
030: public class Content implements Cloneable {
031: private MimeType mMimeType = null;
032: private Object mData = null;
033: private boolean mFragment = false;
034: private String mName = null;
035: private Map<String, String> mAttributes = null;
036: private Map<String, String> mProperties = null;
037: private Object mCachedLoadedData = null;
038:
039: /**
040: * Creates a new <code>Content</code> instance with the minimal required
041: * arguments.
042: *
043: * @param mimeType the mime type as which the content will be stored in
044: * the back-end, note that this doesn't necessarily has to correspond to
045: * the mime type of the provided data. Image formats can for example be
046: * automatically detected and converted to the target mime type by image
047: * loading and conversion libraries.
048: * @param data the data of the content, if this is <code>null</code>,
049: * empty content should be stored
050: * @since 1.0
051: */
052: public Content(MimeType mimeType, Object data) {
053: if (null == mimeType)
054: throw new IllegalArgumentException("mimeType can't be null");
055:
056: mMimeType = mimeType;
057: mData = data;
058: }
059:
060: /**
061: * Retrieves the mime type of the content.
062: *
063: * @return the mime type of the content
064: * @since 1.0
065: */
066: public MimeType getMimeType() {
067: return mMimeType;
068: }
069:
070: /**
071: * Retrieves the data of the content.
072: *
073: * @return the data of the content
074: * @since 1.0
075: */
076: public Object getData() {
077: return mData;
078: }
079:
080: /**
081: * Sets the data of the content.
082: * @since 1.4
083: */
084: public void setData(Object data) {
085: mData = data;
086: }
087:
088: /**
089: * Sets whether the content data is a fragment. A fragment means that it's
090: * not a complete document or a file, but rather a small part that is
091: * intended to be used within a larger document. For example a HTML
092: * snippet. This information is for example important when validating the
093: * data.
094: *
095: * @param fragment <code>true</code> if the content is a fragment; or
096: * <p><code>false</code> otherwise
097: * @return the current <code>Content</code> instance
098: * @see #setFragment(boolean)
099: * @see #isFragment()
100: * @since 1.0
101: */
102: public Content fragment(boolean fragment) {
103: setFragment(fragment);
104:
105: return this ;
106: }
107:
108: /**
109: * Sets whether the content data is a fragment.
110: *
111: * @param fragment <code>true</code> if the content is a fragment; or
112: * <p><code>false</code> otherwise
113: * @see #fragment(boolean)
114: * @see #isFragment()
115: * @since 1.0
116: */
117: public void setFragment(boolean fragment) {
118: mFragment = fragment;
119: }
120:
121: /**
122: * Indicates whether the content data is a fragment.
123: *
124: * @return <code>true</code> if the content is a fragment; or
125: * <p><code>false</code> otherwise
126: * @see #fragment(boolean)
127: * @see #setFragment(boolean)
128: * @since 1.0
129: */
130: public boolean isFragment() {
131: return mFragment;
132: }
133:
134: /**
135: * Sets the name of the content.
136: *
137: * @param name the name
138: * @return the current <code>Content</code> instance
139: * @see #setName(String)
140: * @see #getName()
141: * @see #hasName()
142: * @since 1.0
143: */
144: public Content name(String name) {
145: setName(name);
146:
147: return this ;
148: }
149:
150: /**
151: * Sets the name of the content.
152: *
153: * @param name the name
154: * @see #name(String)
155: * @see #getName()
156: * @see #hasName()
157: * @since 1.0
158: */
159: public void setName(String name) {
160: mName = name;
161: }
162:
163: /**
164: * Retrieves the name of the content.
165: *
166: * @return <code>null</code> if the content has no name; or
167: * <p>the name of the content
168: * @see #name(String)
169: * @see #setName(String)
170: * @see #hasName()
171: * @since 1.0
172: */
173: public String getName() {
174: return mName;
175: }
176:
177: /**
178: * Indicates whether the content data has a name.
179: *
180: * @return <code>true</code> if the content has a name; or
181: * <p><code>false</code> otherwise
182: * @see #name(String)
183: * @see #setName(String)
184: * @see #getName()
185: * @since 1.0
186: */
187: public boolean hasName() {
188: return mName != null;
189: }
190:
191: /**
192: * Replaces the map of named content attributes.
193: * <p>Note that attributes provide information about how to load, convert
194: * and transform content into its stored data form. If you want to provide
195: * meta information about the content, you should provide it through
196: * properties instead.
197: *
198: * @param attributes the map of named content attributes
199: * @return the current <code>Content</code> instance
200: * @see #setAttributes(Map)
201: * @see #getAttributes()
202: * @see #hasAttributes()
203: * @since 1.0
204: */
205: public Content attributes(Map<String, String> attributes) {
206: setAttributes(attributes);
207:
208: return this ;
209: }
210:
211: /**
212: * Sets a named content attribute that will be converted internally to a
213: * <code>String</code> value.
214: *
215: * @param name the name of the attribute
216: * @param value the value of the attribute
217: * @return the current <code>Content</code> instance
218: * @see #getAttribute(String)
219: * @see #hasAttribute(String)
220: * @since 1.0
221: */
222: public Content attribute(String name, boolean value) {
223: return attribute(name, String.valueOf(value));
224: }
225:
226: /**
227: * Sets a named content attribute that will be converted internally to a
228: * <code>String</code> value.
229: *
230: * @param name the name of the attribute
231: * @param value the value of the attribute
232: * @return the current <code>Content</code> instance
233: * @see #getAttribute(String)
234: * @see #hasAttribute(String)
235: * @since 1.0
236: */
237: public Content attribute(String name, char value) {
238: return attribute(name, String.valueOf(value));
239: }
240:
241: /**
242: * Sets a named content attribute that will be converted internally to a
243: * <code>String</code> value.
244: *
245: * @param name the name of the attribute
246: * @param value the value of the attribute
247: * @return the current <code>Content</code> instance
248: * @see #getAttribute(String)
249: * @see #hasAttribute(String)
250: * @since 1.0
251: */
252: public Content attribute(String name, byte value) {
253: return attribute(name, String.valueOf(value));
254: }
255:
256: /**
257: * Sets a named content attribute that will be converted internally to a
258: * <code>String</code> value.
259: *
260: * @param name the name of the attribute
261: * @param value the value of the attribute
262: * @return the current <code>Content</code> instance
263: * @see #getAttribute(String)
264: * @see #hasAttribute(String)
265: * @since 1.0
266: */
267: public Content attribute(String name, short value) {
268: return attribute(name, String.valueOf(value));
269: }
270:
271: /**
272: * Sets a named content attribute that will be converted internally to a
273: * <code>String</code> value.
274: *
275: * @param name the name of the attribute
276: * @param value the value of the attribute
277: * @return the current <code>Content</code> instance
278: * @see #getAttribute(String)
279: * @see #hasAttribute(String)
280: * @since 1.0
281: */
282: public Content attribute(String name, int value) {
283: return attribute(name, String.valueOf(value));
284: }
285:
286: /**
287: * Sets a named content attribute that will be converted internally to a
288: * <code>String</code> value.
289: *
290: * @param name the name of the attribute
291: * @param value the value of the attribute
292: * @return the current <code>Content</code> instance
293: * @see #getAttribute(String)
294: * @see #hasAttribute(String)
295: * @since 1.0
296: */
297: public Content attribute(String name, long value) {
298: return attribute(name, String.valueOf(value));
299: }
300:
301: /**
302: * Sets a named content attribute that will be converted internally to a
303: * <code>String</code> value.
304: *
305: * @param name the name of the attribute
306: * @param value the value of the attribute
307: * @return the current <code>Content</code> instance
308: * @see #getAttribute(String)
309: * @see #hasAttribute(String)
310: * @since 1.0
311: */
312: public Content attribute(String name, float value) {
313: return attribute(name, String.valueOf(value));
314: }
315:
316: /**
317: * Sets a named content attribute that will be converted internally to a
318: * <code>String</code> value.
319: *
320: * @param name the name of the attribute
321: * @param value the value of the attribute
322: * @return the current <code>Content</code> instance
323: * @see #getAttribute(String)
324: * @see #hasAttribute(String)
325: * @since 1.0
326: */
327: public Content attribute(String name, double value) {
328: return attribute(name, String.valueOf(value));
329: }
330:
331: /**
332: * Sets a named content attribute.
333: *
334: * @param name the name of the attribute
335: * @param value the value of the attribute
336: * @return the current <code>Content</code> instance
337: * @see #getAttribute(String)
338: * @see #hasAttribute(String)
339: * @since 1.0
340: */
341: public Content attribute(String name, String value) {
342: if (null == mAttributes) {
343: mAttributes = new HashMap<String, String>();
344: }
345:
346: mAttributes.put(name, value);
347:
348: return this ;
349: }
350:
351: /**
352: * Replaces the map of named content attributes.
353: *
354: * @param attributes the map of named content attributes
355: * @see #attributes(Map)
356: * @see #getAttributes()
357: * @see #hasAttributes()
358: * @since 1.0
359: */
360: public void setAttributes(Map<String, String> attributes) {
361: if (null == attributes) {
362: mAttributes = null;
363: return;
364: }
365:
366: mAttributes = new HashMap<String, String>(attributes);
367: }
368:
369: /**
370: * Retrieves the map of named content attributes.
371: *
372: * @return the map of named content attributes; or
373: * <p><code>null</code> if no attributes are present
374: * @see #attributes(Map)
375: * @see #setAttributes(Map)
376: * @see #hasAttributes()
377: * @since 1.0
378: */
379: public Map<String, String> getAttributes() {
380: return mAttributes;
381: }
382:
383: /**
384: * Indicates whether named content attributes are present.
385: *
386: * @return <code>true</code> if named content attributes are present; or
387: * <p><code>false</code> otherwise
388: * @see #attributes(Map)
389: * @see #setAttributes(Map)
390: * @see #getAttributes()
391: * @since 1.0
392: */
393: public boolean hasAttributes() {
394: return mAttributes != null && mAttributes.size() > 0;
395: }
396:
397: /**
398: * Indicates whether a specific named content attribute is present.
399: *
400: * @param name the name of the attribute
401: * @return <code>true</code> if the name content attribute is present; or
402: * <p><code>false</code> otherwise
403: * @see #getAttribute(String)
404: * @since 1.0
405: */
406: public boolean hasAttribute(String name) {
407: if (null == mAttributes) {
408: return false;
409: }
410:
411: return mAttributes.containsKey(name);
412: }
413:
414: /**
415: * Retrieves the value of a named content attribute.
416: *
417: * @param name the name of the attribute
418: * @return the value of the named content attribute; or
419: * <p><code>null</code> if no such attribute could be found
420: * @see #hasAttribute(String)
421: * @since 1.0
422: */
423: public String getAttribute(String name) {
424: if (null == mAttributes) {
425: return null;
426: }
427:
428: return mAttributes.get(name);
429: }
430:
431: /**
432: * Replaces the content properties.
433: * <p>This is also internally used by content formatters to provide
434: * additional information about the content that's stored after formatting
435: * and transformation. Note that this is not the same as content
436: * attributes, who provide infomration about how to format and transform
437: * the provided data before storage. The content properties describe the
438: * result as it's stored in the back-end.
439: *
440: * @param properties the content properties
441: * @return the current <code>Content</code> instance
442: * @see #setProperties(Map)
443: * @see #hasProperties()
444: * @see #getProperties()
445: * @since 1.0
446: */
447: public Content properties(Map<String, String> properties) {
448: setProperties(properties);
449:
450: return this ;
451: }
452:
453: /**
454: * Sets a named content property that will be converted internally to a
455: * <code>String</code> value.
456: *
457: * @param name the name of the property
458: * @param value the value of the property
459: * @return the current <code>Content</code> instance
460: * @see #getProperty(String)
461: * @see #hasProperty(String)
462: * @since 1.0
463: */
464: public Content property(String name, boolean value) {
465: return property(name, String.valueOf(value));
466: }
467:
468: /**
469: * Sets a named content property that will be converted internally to a
470: * <code>String</code> value.
471: *
472: * @param name the name of the property
473: * @param value the value of the property
474: * @return the current <code>Content</code> instance
475: * @see #getProperty(String)
476: * @see #hasProperty(String)
477: * @since 1.0
478: */
479: public Content property(String name, char value) {
480: return property(name, String.valueOf(value));
481: }
482:
483: /**
484: * Sets a named content property that will be converted internally to a
485: * <code>String</code> value.
486: *
487: * @param name the name of the property
488: * @param value the value of the property
489: * @return the current <code>Content</code> instance
490: * @see #getProperty(String)
491: * @see #hasProperty(String)
492: * @since 1.0
493: */
494: public Content property(String name, byte value) {
495: return property(name, String.valueOf(value));
496: }
497:
498: /**
499: * Sets a named content property that will be converted internally to a
500: * <code>String</code> value.
501: *
502: * @param name the name of the property
503: * @param value the value of the property
504: * @return the current <code>Content</code> instance
505: * @see #getProperty(String)
506: * @see #hasProperty(String)
507: * @since 1.0
508: */
509: public Content property(String name, short value) {
510: return property(name, String.valueOf(value));
511: }
512:
513: /**
514: * Sets a named content property that will be converted internally to a
515: * <code>String</code> value.
516: *
517: * @param name the name of the property
518: * @param value the value of the property
519: * @return the current <code>Content</code> instance
520: * @see #getProperty(String)
521: * @see #hasProperty(String)
522: * @since 1.0
523: */
524: public Content property(String name, int value) {
525: return property(name, String.valueOf(value));
526: }
527:
528: /**
529: * Sets a named content property that will be converted internally to a
530: * <code>String</code> value.
531: *
532: * @param name the name of the property
533: * @param value the value of the property
534: * @return the current <code>Content</code> instance
535: * @see #getProperty(String)
536: * @see #hasProperty(String)
537: * @since 1.0
538: */
539: public Content property(String name, long value) {
540: return property(name, String.valueOf(value));
541: }
542:
543: /**
544: * Sets a named content property that will be converted internally to a
545: * <code>String</code> value.
546: *
547: * @param name the name of the property
548: * @param value the value of the property
549: * @return the current <code>Content</code> instance
550: * @see #getProperty(String)
551: * @see #hasProperty(String)
552: * @since 1.0
553: */
554: public Content property(String name, float value) {
555: return property(name, String.valueOf(value));
556: }
557:
558: /**
559: * Sets a named content property that will be converted internally to a
560: * <code>String</code> value.
561: *
562: * @param name the name of the property
563: * @param value the value of the property
564: * @return the current <code>Content</code> instance
565: * @see #getProperty(String)
566: * @see #hasProperty(String)
567: * @since 1.0
568: */
569: public Content property(String name, double value) {
570: return property(name, String.valueOf(value));
571: }
572:
573: /**
574: * Sets a named content property.
575: *
576: * @param name the name of the property
577: * @param value the value of the property
578: * @return the current <code>Content</code> instance
579: * @see #getProperty(String)
580: * @see #hasProperty(String)
581: * @since 1.0
582: */
583: public Content property(String name, String value) {
584: if (null == mProperties) {
585: mProperties = new HashMap<String, String>();
586: }
587:
588: mProperties.put(name, value);
589:
590: return this ;
591: }
592:
593: /**
594: * Replaces the content properties.
595: *
596: * @param properties the content properties
597: * @see #properties(Map)
598: * @see #hasProperties()
599: * @see #getProperties()
600: * @since 1.0
601: */
602: public void setProperties(Map<String, String> properties) {
603: if (null == properties) {
604: mProperties = null;
605: return;
606: }
607:
608: mProperties = new HashMap<String, String>(properties);
609: }
610:
611: /**
612: * Indicates whether content properties are present
613: *
614: * @return <code>true</code> if properties are present; or
615: * <p><code>false</code> otherwise
616: * @see #properties(Map)
617: * @see #setProperties(Map)
618: * @see #getProperties()
619: * @since 1.0
620: */
621: public boolean hasProperties() {
622: return mProperties != null && mProperties.size() > 0;
623: }
624:
625: /**
626: * Indicates whether a specific named content property is present.
627: *
628: * @param name the name of the property
629: * @return <code>true</code> if the name content property is present; or
630: * <p><code>false</code> otherwise
631: * @see #getProperty(String)
632: * @since 1.0
633: */
634: public boolean hasProperty(String name) {
635: if (null == mProperties) {
636: return false;
637: }
638:
639: return mProperties.containsKey(name);
640: }
641:
642: /**
643: * Retrieves the value of a named content property.
644: *
645: * @param name the name of the property
646: * @return the value of the named content property; or
647: * <p><code>null</code> if no such property could be found
648: * @see #hasProperty(String)
649: * @since 1.0
650: */
651: public String getProperty(String name) {
652: if (null == mProperties) {
653: return null;
654: }
655:
656: return mProperties.get(name);
657: }
658:
659: /**
660: * Retrieves the content properties.
661: *
662: * @return the content properties; or
663: * <p><code>null</code> if no content properties are present
664: * @see #properties(Map)
665: * @see #setProperties(Map)
666: * @see #hasProperties()
667: * @since 1.0
668: */
669: public Map<String, String> getProperties() {
670: return mProperties;
671: }
672:
673: /**
674: * Sets the cached loaded data.
675: * <p>This is <b>internally</b> used by content loaders to prevent having
676: * to load and convert data to the specified mime type several times for
677: * the same content. It is for instance very resource intensive to detect
678: * an image format, validate the provided raw data and create a generic
679: * image instance for further processing. These operations are however
680: * required in several different locations in the content handling logic.
681: * Storing the result after the first successful loading and simply
682: * retrieving it later enhances the speed considerably.
683: *
684: * @param data the loaded data
685: * @return the current <code>Content</code> instance
686: * @see #setCachedLoadedData(Object)
687: * @see #hasCachedLoadedData()
688: * @see #getCachedLoadedData()
689: * @since 1.0
690: */
691: public Content cachedLoadedData(Object data) {
692: setCachedLoadedData(data);
693:
694: return this ;
695: }
696:
697: /**
698: * Sets the cached loaded data.
699: *
700: * @param data the loaded data
701: * @see #cachedLoadedData(Object)
702: * @see #hasCachedLoadedData()
703: * @see #getCachedLoadedData()
704: * @since 1.0
705: */
706: public void setCachedLoadedData(Object data) {
707: mCachedLoadedData = data;
708: }
709:
710: /**
711: * Indicates whether cached loaded content data is present.
712: *
713: * @return <code>true</code> if cached loaded content data is present; or
714: * <p><code>false</code> otherwise
715: * @see #cachedLoadedData(Object)
716: * @see #setCachedLoadedData(Object)
717: * @see #getCachedLoadedData()
718: * @since 1.0
719: */
720: public boolean hasCachedLoadedData() {
721: return null != mCachedLoadedData;
722:
723: }
724:
725: /**
726: * Retrieves the cached loaded content data.
727: *
728: * @return the cached loaded content data; or
729: * <p><code>null</code> if no loaded content data has been cached
730: * @see #cachedLoadedData(Object)
731: * @see #setCachedLoadedData(Object)
732: * @see #hasCachedLoadedData()
733: * @since 1.0
734: */
735: public Object getCachedLoadedData() {
736: return mCachedLoadedData;
737: }
738:
739: /**
740: * Simply clones the instance with the default clone method since we
741: * want to create a shallow copy
742: *
743: * @since 1.0
744: */
745: public Content clone() {
746: try {
747: return (Content) super .clone();
748: } catch (CloneNotSupportedException e) {
749: // this should never happen
750: Logger.getLogger("com.uwyn.rife.cmf").severe(
751: ExceptionUtils.getExceptionStackTrace(e));
752: return null;
753: }
754: }
755: }
|