001    package jigcell.compare.data;
002    
003    import java.awt.datatransfer.DataFlavor;
004    import java.awt.datatransfer.UnsupportedFlavorException;
005    import java.io.IOException;
006    import java.io.InputStream;
007    import java.io.PipedReader;
008    import java.io.PipedWriter;
009    import java.io.Reader;
010    import java.text.NumberFormat;
011    import jigcell.compare.IDataElement;
012    import jigcell.compare.IEditableDataElement;
013    import jigcell.compare.impl.ComparatorDataFlavor;
014    import jigcell.compare.impl.Transferer;
015    
016    /**
017     * A helper implementation for data element classes.  Provides a default implementation for every method required by DataElement.  All of the
018     * access methods act as if this element is empty.
019     *
020     * <p>
021     * This code is licensed under the DARPA BioCOMP Open Source License.  See LICENSE for more details.
022     * </p>
023     *
024     * @author Nicholas Allen
025     */
026    
027    public class DataElement extends Transferer implements IDataElement {
028    
029       /**
030        * Size of long constant pool
031        */
032    
033       public final static int SIZE_LONGPOOL = 128;
034    
035       /**
036        * Long constant pool
037        */
038    
039       public final static Long LONGPOOL [];
040    
041       /**
042        * Pattern for boolean false
043        */
044    
045       public final static String PATTERN_FALSE = "false";
046    
047       /**
048        * Pattern for NaN
049        */
050    
051       public final static String PATTERN_NAN = "nan";
052    
053       /**
054        * Pattern for -Infinity
055        */
056    
057       public final static String PATTERN_NINFINITY = "-infinity";
058    
059       /**
060        * Alternate pattern for -Infinity
061        */
062    
063       public final static String PATTERN_NINFINITY2 = "-inf";
064    
065       /**
066        * Pattern for null
067        */
068    
069       public final static String PATTERN_NULL = "null";
070    
071       /**
072        * Pattern for +Infinity
073        */
074    
075       public final static String PATTERN_PINFINITY = "infinity";
076    
077       /**
078        * Alternate pattern for +Infinity
079        */
080    
081       public final static String PATTERN_PINFINITY2 = "inf";
082    
083       /**
084        * Pattern for boolean true
085        */
086    
087       public final static String PATTERN_TRUE = "true";
088    
089       /**
090        * Pattern for void
091        */
092    
093       public final static String PATTERN_VOID = "no value";
094    
095       /**
096        * Count of number of locking operations committed to
097        */
098    
099       protected transient int lockCount;
100    
101       static {
102          addFlavor (IDataElement.class, new ComparatorDataFlavor ("Data Element", IDataElement.class, ComparatorDataFlavor.FLAVOR_LOCALOBJECT));
103          addFlavor (IDataElement.class,
104             new ComparatorDataFlavor ("Data Element", InputStream.class, ComparatorDataFlavor.FLAVOR_XMLSERIALIZEDOBJECT));
105          addFlavor (IDataElement.class,
106             new ComparatorDataFlavor ("Data Element", IDataElement.class, ComparatorDataFlavor.FLAVOR_SERIALIZEDOBJECT));
107          addFlavor (IDataElement.class, new ComparatorDataFlavor ("Data Element", Reader.class, ComparatorDataFlavor.FLAVOR_TEXTPLAIN));
108          LONGPOOL = new Long [SIZE_LONGPOOL + 1];
109          for (int i = 0, l = LONGPOOL.length; i < l; i++)
110             LONGPOOL [i] = new Long (i - 1);
111       }
112    
113       /**
114        * Returns a constant out of the long constant pool or a new constant.
115        *
116        * @param value Value
117        */
118    
119       public static Long getLongObject (long value) {
120          return value >= -1 && value < SIZE_LONGPOOL ? LONGPOOL [(int) value + 1] : new Long (value);
121       }
122    
123       /**
124        * Whether a text string represents a special non-numeric value.
125        *
126        * @param text String to parse
127        */
128    
129       public static boolean isSpecialNonNumeric (String text) {
130          text = text.trim ().toLowerCase ();
131          return PATTERN_FALSE.equals (text) || PATTERN_TRUE.equals (text) || PATTERN_VOID.equals (text) || PATTERN_NAN.equals (text) ||
132             PATTERN_PINFINITY.equals (text) || PATTERN_PINFINITY2.equals (text) || PATTERN_NINFINITY.equals (text) ||
133             PATTERN_NINFINITY2.equals (text);
134       }
135    
136       /**
137        * Renders the DataElement as an ordered tuple.
138        *
139        * @param element DataElement
140        */
141    
142       public static String toString (IDataElement element) {
143          if (element == null)
144             return "No Value";
145          if (element.isScalar ()) {
146             IDataElement.Type type = element.getType ();
147             return type == IDataElement.Type.NONE ? "No Value" :
148                type == IDataElement.Type.BOOLEAN ? String.valueOf (element.getBooleanValue ()) :
149                type == IDataElement.Type.INTEGRAL ? String.valueOf (element.getIntegralValue ()) :
150                type == IDataElement.Type.LITERAL ? "\"" + element.getLiteralValue () + "\"" : String.valueOf (element.getRealValue ());
151          }
152          try {
153             element.memoryLock ();
154             StringBuffer value = new StringBuffer ("(");
155             for (long i = 1, l = element.getLength (); i <= l; i++)
156                value.append ((i == 1 ? "" : ", ") + DataElement.toString (element, i));
157             return value.append (")").toString ();
158          } finally {
159             element.memoryUnlock ();
160          }
161       }
162    
163       /**
164        * Renders the value of a specified position.
165        *
166        * @param element DataElement
167        * @param pos Render position
168        */
169    
170       public static String toString (IDataElement element, long pos) {
171          IDataElement.Type type = element.getType (pos);
172          return type == IDataElement.Type.NONE ? "No Value" :
173             type == IDataElement.Type.BOOLEAN ? String.valueOf (element.getBooleanValue (pos)) :
174             type == IDataElement.Type.INTEGRAL ? String.valueOf (element.getIntegralValue (pos)) :
175             type == IDataElement.Type.REAL ? String.valueOf (element.getRealValue (pos)) :
176             type == IDataElement.Type.LITERAL ? "\"" + element.getLiteralValue (pos) + "\"" : DataElement.toString (element.getListValue (pos));
177       }
178    
179       /**
180        * Renders the DataElement as an ordered tuple.
181        *
182        * @param element DataElement
183        * @param format Format
184        */
185    
186       public static String toString (IDataElement element, NumberFormat format) {
187          if (element == null)
188             return "No Value";
189          if (element.isScalar ()) {
190             IDataElement.Type type = element.getType ();
191             return type == IDataElement.Type.NONE ? "No Value" :
192                type == IDataElement.Type.BOOLEAN ? String.valueOf (element.getBooleanValue ()) :
193                type == IDataElement.Type.INTEGRAL ? format.format (element.getIntegralValue ()) :
194                type == IDataElement.Type.LITERAL ? "\"" + element.getLiteralValue () + "\"" : format.format (element.getRealValue ());
195          }
196          try {
197             element.memoryLock ();
198             StringBuffer value = new StringBuffer ("(");
199             for (long i = 1, l = element.getLength (); i <= l; i++)
200                value.append ((i == 1 ? "" : ", ") + DataElement.toString (element, i, format));
201             return value.append (")").toString ();
202          } finally {
203             element.memoryUnlock ();
204          }
205       }
206    
207       /**
208        * Renders the DataElement as an ordered tuple.
209        *
210        * @param element DataElement
211        * @param limit Whether to abbreviate the string.
212        * @param size Approximate length before abbreviation occurs.
213        */
214    
215       public static String toString (IDataElement element, boolean limit, int size) {
216          if (element == null)
217             return "No Value";
218          if (element.isScalar ()) {
219             IDataElement.Type type = element.getType ();
220             return type == IDataElement.Type.NONE ? "No Value" :
221                type == IDataElement.Type.BOOLEAN ? String.valueOf (element.getBooleanValue ()) :
222                type == IDataElement.Type.INTEGRAL ? String.valueOf (element.getIntegralValue ()) :
223                type == IDataElement.Type.LITERAL ? "\"" + element.getLiteralValue () + "\"" : String.valueOf (element.getRealValue ());
224          }
225          StringBuffer value = new StringBuffer ("(");
226          if (limit)
227             for (long i = 1, l = element.getLength (); i <= l; i++) {
228                int remain = size - value.length ();
229                if (remain <= 0) {
230                   value.append ("...");
231                   break;
232                } else
233                   value.append ((i == 1 ? "" : ", ") + DataElement.toString (element, true, remain, i));
234             }
235          else
236             for (long i = 1, l = element.getLength (); i <= l; i++)
237                value.append ((i == 1 ? "" : ", ") + DataElement.toString (element, i));
238          return value.append (")").toString ();
239       }
240    
241       /**
242        * Renders the value of a specified position.
243        *
244        * @param element DataElement
245        * @param pos Render position
246        * @param format Format
247        */
248    
249       public static String toString (IDataElement element, long pos, NumberFormat format) {
250          IDataElement.Type type = element.getType (pos);
251          return type == IDataElement.Type.NONE ? "No Value" :
252             type == IDataElement.Type.BOOLEAN ? String.valueOf (element.getBooleanValue (pos)) :
253             type == IDataElement.Type.INTEGRAL ? format.format (element.getIntegralValue (pos)) :
254             type == IDataElement.Type.REAL ? format.format (element.getRealValue (pos)) :
255             type == IDataElement.Type.LITERAL ? "\"" + element.getLiteralValue (pos) + "\"" :
256             DataElement.toString (element.getListValue (pos), format);
257       }
258    
259       /**
260        * Renders the DataElement as an ordered tuple.
261        *
262        * @param element DataElement
263        * @param limit Whether to abbreviate the string.
264        * @param size Approximate length before abbreviation occurs.
265        * @param format Format
266        */
267    
268       public static String toString (IDataElement element, boolean limit, int size, NumberFormat format) {
269          if (element == null)
270             return "No Value";
271          if (element.isScalar ()) {
272             IDataElement.Type type = element.getType ();
273             return type == IDataElement.Type.NONE ? "No Value" :
274                type == IDataElement.Type.BOOLEAN ? String.valueOf (element.getBooleanValue ()) :
275                type == IDataElement.Type.INTEGRAL ? format.format (element.getIntegralValue ()) :
276                type == IDataElement.Type.LITERAL ? "\"" + element.getLiteralValue () + "\"" : format.format (element.getRealValue ());
277          }
278          StringBuffer value = new StringBuffer ("(");
279          if (limit)
280             for (long i = 1, l = element.getLength (); i <= l; i++) {
281                int remain = size - value.length ();
282                if (remain <= 0) {
283                   value.append ("...");
284                   break;
285                } else
286                   value.append ((i == 1 ? "" : ", ") + DataElement.toString (element, true, remain, i, format));
287             }
288          else
289             for (long i = 1, l = element.getLength (); i <= l; i++)
290                value.append ((i == 1 ? "" : ", ") + DataElement.toString (element, i, format));
291          return value.append (")").toString ();
292       }
293    
294       /**
295        * Renders the value of a specified position.
296        *
297        * @param element DataElement
298        * @param limit Whether to abbreviate the string.
299        * @param size Approximate length before abbreviation occurs.
300        * @param pos Render position
301        */
302    
303       public static String toString (IDataElement element, boolean limit, int size, long pos) {
304          IDataElement.Type type = element.getType (pos);
305          return type == IDataElement.Type.NONE ? "No Value" :
306             type == IDataElement.Type.BOOLEAN ? String.valueOf (element.getBooleanValue (pos)) :
307             type == IDataElement.Type.INTEGRAL ? String.valueOf (element.getIntegralValue (pos)) :
308             type == IDataElement.Type.REAL ? String.valueOf (element.getRealValue (pos)) :
309             type == IDataElement.Type.LITERAL ? "\"" + element.getLiteralValue () + "\"" :
310             limit ? DataElement.toString (element.getListValue (pos), limit, size) : DataElement.toString (element.getListValue (pos));
311       }
312    
313       /**
314        * Renders the value of a specified position.
315        *
316        * @param element DataElement
317        * @param limit Whether to abbreviate the string.
318        * @param size Approximate length before abbreviation occurs.
319        * @param pos Render position
320        * @param format Format
321        */
322    
323       public static String toString (IDataElement element, boolean limit, int size, long pos, NumberFormat format) {
324          IDataElement.Type type = element.getType (pos);
325          return type == IDataElement.Type.NONE ? "No Value" :
326             type == IDataElement.Type.BOOLEAN ? String.valueOf (element.getBooleanValue (pos)) :
327             type == IDataElement.Type.INTEGRAL ? format.format (element.getIntegralValue (pos)) :
328             type == IDataElement.Type.REAL ? format.format (element.getRealValue (pos)) :
329             type == IDataElement.Type.LITERAL ? "\"" + element.getLiteralValue () + "\"" :
330             limit ? DataElement.toString (element.getListValue (pos), limit, size, format) :
331             DataElement.toString (element.getListValue (pos), format);
332       }
333    
334       /**
335        * Creates a new data element.
336        */
337    
338       public DataElement () {
339          super ();
340       }
341    
342       /**
343        * {@inheritDoc}
344        */
345    
346       public boolean forceBooleanValue () {
347          return forceBooleanValue (0);
348       }
349    
350       /**
351        * {@inheritDoc}
352        */
353    
354       public boolean forceBooleanValue (long pos) {
355          IDataElement.Type type = getType (pos);
356          return type == IDataElement.Type.BOOLEAN ? getBooleanValue (pos) :
357             type == IDataElement.Type.INTEGRAL ? getIntegralValue (pos) != 0 :
358             type == IDataElement.Type.REAL ? getRealValue (pos) != 0.0 :
359             type == IDataElement.Type.LITERAL ? Boolean.valueOf (getLiteralValue (pos)).booleanValue () : type == IDataElement.Type.MULTIPLE;
360       }
361    
362       /**
363        * {@inheritDoc}
364        */
365    
366       public long forceIntegralValue () {
367          return forceIntegralValue (0);
368       }
369    
370       /**
371        * {@inheritDoc}
372        */
373    
374       public long forceIntegralValue (long pos) {
375          IDataElement.Type type = getType (pos);
376          if (type == IDataElement.Type.INTEGRAL)
377             return getIntegralValue (pos);
378          if (type == IDataElement.Type.REAL)
379             return Math.round (getRealValue (pos));
380          if (type == IDataElement.Type.BOOLEAN)
381             return getBooleanValue (pos) ? 1 : 0;
382          if (type == IDataElement.Type.LITERAL)
383             try {
384                return Long.valueOf (getLiteralValue (pos)).longValue ();
385             } catch (Exception e) {}
386          return 0;
387       }
388    
389       /**
390        * {@inheritDoc}
391        */
392    
393       public IDataElement forceListValue (long pos) {
394          IDataElement.Type type = getType (pos);
395          if (type == IDataElement.Type.MULTIPLE)
396             return getListValue (pos);
397          IEditableDataElement element = new SparseTreeDataElement ();
398          if (type == IDataElement.Type.INTEGRAL)
399             element.setValue (1, getIntegralValue (pos));
400          else if (type == IDataElement.Type.REAL)
401             element.setValue (1, getRealValue (pos));
402          else if (type == IDataElement.Type.BOOLEAN)
403             element.setValue (1, getBooleanValue (pos));
404          else if (type == IDataElement.Type.LITERAL)
405             element.setValue (1, getLiteralValue (pos));
406          return element;
407       }
408    
409       /**
410        * {@inheritDoc}
411        */
412    
413       public String forceLiteralValue () {
414          String value = getLiteralValue ();
415          return value == null ? toString () : value;
416       }
417    
418       /**
419        * {@inheritDoc}
420        */
421    
422       public String forceLiteralValue (long pos) {
423          String value = getLiteralValue ();
424          return value == null ? toString (pos) : value;
425       }
426    
427       /**
428        * {@inheritDoc}
429        */
430    
431       public double forceRealValue () {
432          return forceRealValue (0);
433       }
434    
435       /**
436        * {@inheritDoc}
437        */
438    
439       public double forceRealValue (long pos) {
440          IDataElement.Type type = getType (pos);
441          if (type == IDataElement.Type.REAL)
442             return getRealValue (pos);
443          if (type == IDataElement.Type.INTEGRAL)
444             return (double) getIntegralValue (pos);
445          if (type == IDataElement.Type.BOOLEAN)
446             return getBooleanValue (pos) ? 1.0 : 0.0;
447          if (type == IDataElement.Type.LITERAL)
448             try {
449                return Double.valueOf (getLiteralValue (pos)).doubleValue ();
450             } catch (Exception e) {}
451          return Double.NaN;
452       }
453    
454       /**
455        * {@inheritDoc}
456        */
457    
458       public boolean [] forceSlice (boolean slice [], long start, int length, long stride) {
459          boolean value [] = getSlice (slice, start, length, stride);
460          if (value != null)
461             return value;
462          value = slice == null || slice.length < length ? new boolean [length] : slice;
463          long pos = start;
464          for (int i = 0; i < length; pos += stride) {
465             IDataElement.Type type = getType (pos);
466             value [i++] = type == IDataElement.Type.BOOLEAN ? getBooleanValue (pos) :
467                type == IDataElement.Type.INTEGRAL ? getIntegralValue (pos) != 0 :
468                type == IDataElement.Type.REAL ? getRealValue (pos) != 0.0 :
469                type == IDataElement.Type.LITERAL ? Boolean.valueOf (getLiteralValue (pos)).booleanValue () : type == IDataElement.Type.MULTIPLE;
470          }
471          return value;
472       }
473    
474       /**
475        * {@inheritDoc}
476        */
477    
478       public IDataElement [] forceSlice (IDataElement slice [], long start, int length, long stride) {
479          IDataElement value [] = getSlice (slice, start, length, stride);
480          if (value != null)
481             return value;
482          value = slice == null || slice.length < length ? new IDataElement [length] : slice;
483          long pos = start;
484          for (int i = 0; i < length; pos += stride) {
485             IDataElement.Type type = getType (pos);
486             if (type == IDataElement.Type.MULTIPLE) {
487                value [i++] = getListValue (pos);
488                continue;
489             }
490             IEditableDataElement element = new SparseTreeDataElement ();
491             if (type == IDataElement.Type.INTEGRAL)
492                element.setValue (1, getIntegralValue (pos));
493             else if (type == IDataElement.Type.REAL)
494                element.setValue (1, getRealValue (pos));
495             else if (type == IDataElement.Type.BOOLEAN)
496                element.setValue (1, getBooleanValue (pos));
497             else if (type == IDataElement.Type.LITERAL)
498                element.setValue (1, getLiteralValue (pos));
499             value [i++] = element;
500          }
501          return value;
502       }
503    
504       /**
505        * {@inheritDoc}
506        */
507    
508       public double [] forceSlice (double slice [], long start, int length, long stride) {
509          double value [] = getSlice (slice, start, length, stride);
510          if (value != null)
511             return value;
512          value = slice == null || slice.length < length ? new double [length] : slice;
513          long pos = start;
514          for (int i = 0; i < length; pos += stride) {
515             IDataElement.Type type = getType (pos);
516             value [i++] = type == IDataElement.Type.REAL ? getRealValue (pos) :
517                type == IDataElement.Type.INTEGRAL ? (double) getIntegralValue (pos) :
518                type == IDataElement.Type.BOOLEAN ? getBooleanValue (pos) ? 1.0 : 0.0 :
519                type == IDataElement.Type.LITERAL ? Double.valueOf (getLiteralValue (pos)).doubleValue () : Double.NaN;
520          }
521          return value;
522       }
523    
524       /**
525        * {@inheritDoc}
526        */
527    
528       public long [] forceSlice (long slice [], long start, int length, long stride) {
529          long value [] = getSlice (slice, start, length, stride);
530          if (value != null)
531             return value;
532          value = slice == null || slice.length < length ? new long [length] : slice;
533          long pos = start;
534          for (int i = 0; i < length; pos += stride) {
535             IDataElement.Type type = getType (pos);
536             value [i++] = type == IDataElement.Type.INTEGRAL ? getIntegralValue (pos) :
537                type == IDataElement.Type.REAL ? Math.round (getRealValue (pos)) :
538                type == IDataElement.Type.BOOLEAN ? getBooleanValue (pos) ? 1 : 0 :
539                type == IDataElement.Type.LITERAL ? Long.valueOf (getLiteralValue (pos)).longValue () : 0;
540          }
541          return value;
542       }
543    
544       /**
545        * {@inheritDoc}
546        */
547    
548       public String [] forceSlice (String slice [], long start, int length, long stride) {
549          String value [] = getSlice (slice, start, length, stride);
550          if (value != null)
551             return value;
552          value = slice == null || slice.length < length ? new String [length] : slice;
553          long pos = start;
554          for (int i = 0; i < length; pos += stride) {
555             String literal = getLiteralValue (pos);
556             value [i++] = literal == null ? toString (pos) : literal;
557          }
558          return value;
559       }
560    
561       /**
562        * {@inheritDoc}
563        */
564    
565       public boolean getBooleanValue () {
566          return getBooleanValue (0);
567       }
568    
569       /**
570        * {@inheritDoc}
571        */
572    
573       public boolean getBooleanValue (long pos) {
574          return false;
575       }
576    
577       /**
578        * {@inheritDoc}
579        */
580    
581       public long getIntegralValue () {
582          return getIntegralValue (0);
583       }
584    
585       /**
586        * {@inheritDoc}
587        */
588    
589       public long getIntegralValue (long pos) {
590          return 0;
591       }
592    
593       /**
594        * {@inheritDoc}
595        */
596    
597       public long getLength () {
598          return 0;
599       }
600    
601       /**
602        * {@inheritDoc}
603        */
604    
605       public IDataElement getListValue (long pos) {
606          return null;
607       }
608    
609       /**
610        * {@inheritDoc}
611        */
612    
613       public String getLiteralValue () {
614          return getLiteralValue (0);
615       }
616    
617       /**
618        * {@inheritDoc}
619        */
620    
621       public String getLiteralValue (long pos) {
622          return null;
623       }
624    
625       /**
626        * {@inheritDoc}
627        */
628    
629       public double getRealValue () {
630          return getRealValue (0);
631       }
632    
633       /**
634        * {@inheritDoc}
635        */
636    
637       public double getRealValue (long pos) {
638          return Double.NaN;
639       }
640    
641       /**
642        * {@inheritDoc}
643        */
644    
645       public boolean [] getSlice (boolean slice [], long start, int length, long stride) {
646          boolean value [] = slice == null || slice.length < length ? new boolean [length] : slice;
647          long pos = start;
648          for (int i = 0; i < length; pos += stride) {
649             IDataElement.Type type = getType (pos);
650             if (type == IDataElement.Type.BOOLEAN)
651                value [i++] = getBooleanValue (pos);
652             else
653                return null;
654          }
655          return value;
656       }
657    
658       /**
659        * {@inheritDoc}
660        */
661    
662       public IDataElement [] getSlice (IDataElement slice [], long start, int length, long stride) {
663          IDataElement value [] = slice == null || slice.length < length ? new IDataElement [length] : slice;
664          long pos = start;
665          for (int i = 0; i < length; pos += stride) {
666             IDataElement.Type type = getType (pos);
667             if (type == IDataElement.Type.MULTIPLE)
668                value [i++] = getListValue (pos);
669             else
670                return null;
671          }
672          return value;
673       }
674    
675       /**
676        * {@inheritDoc}
677        */
678    
679       public double [] getSlice (double slice [], long start, int length, long stride) {
680          double value [] = slice == null || slice.length < length ? new double [length] : slice;
681          long pos = start;
682          for (int i = 0; i < length; pos += stride) {
683             IDataElement.Type type = getType (pos);
684             if (type == IDataElement.Type.REAL)
685                value [i++] = getRealValue (pos);
686             else
687                return null;
688          }
689          return value;
690       }
691    
692       /**
693        * {@inheritDoc}
694        */
695    
696       public long [] getSlice (long slice [], long start, int length, long stride) {
697          long value [] = slice == null || slice.length < length ? new long [length] : slice;
698          long pos = start;
699          for (int i = 0; i < length; pos += stride) {
700             IDataElement.Type type = getType (pos);
701             if (type == IDataElement.Type.INTEGRAL)
702                value [i++] = getIntegralValue (pos);
703             else
704                return null;
705          }
706          return value;
707       }
708    
709       /**
710        * {@inheritDoc}
711        */
712    
713       public String [] getSlice (String slice [], long start, int length, long stride) {
714          String value [] = slice == null || slice.length < length ? new String [length] : slice;
715          long pos = start;
716          for (int i = 0; i < length; pos += stride) {
717             IDataElement.Type type = getType (pos);
718             if (type == IDataElement.Type.LITERAL)
719                value [i++] = getLiteralValue (pos);
720             else
721                return null;
722          }
723          return value;
724       }
725    
726       /**
727        * {@inheritDoc}
728        */
729    
730       public Object getTransferData (DataFlavor flavor) throws UnsupportedFlavorException, IOException {
731          if (!(flavor instanceof ComparatorDataFlavor))
732             throw new UnsupportedFlavorException (flavor);
733          ComparatorDataFlavor type = (ComparatorDataFlavor) flavor;
734          if (!type.isFlavorPlainTextType () || !type.getRepresentationClass ().isAssignableFrom (PipedReader.class))
735             return super.getTransferData (flavor);
736          PipedWriter out = new PipedWriter ();
737          out.write (toString ());
738          return new PipedReader (out);
739       }
740    
741       /**
742        * {@inheritDoc}
743        */
744    
745       public IDataElement.Type getType () {
746          return getType (0);
747       }
748    
749       /**
750        * {@inheritDoc}
751        */
752    
753       public IDataElement.Type getType (long pos) {
754          return IDataElement.Type.NONE;
755       }
756    
757       /**
758        * {@inheritDoc}
759        */
760    
761       public boolean isAvailable () {
762          if (lockCount > 0)
763             return true;
764          for (long i = 1, l = getLength (); i < l; i++) {
765             IDataElement value = getListValue (i);
766             if (value != null && !value.isAvailable ())
767                return false;
768          }
769          return true;
770       }
771    
772       /**
773        * {@inheritDoc}
774        */
775    
776       public boolean isScalar () {
777          return getLength () == 0;
778       }
779    
780       /**
781        * {@inheritDoc}
782        */
783    
784       public void memoryLock () {
785          if (lockCount++ > 0)
786             return;
787          for (long i = 1, l = getLength (); i < l; i++) {
788             IDataElement value = getListValue (i);
789             if (value != null)
790                value.memoryLock ();
791          }
792       }
793    
794       /**
795        * {@inheritDoc}
796        */
797    
798       public void memoryUnlock () {
799          if (--lockCount > 0)
800             return;
801          for (long i = 1, l = getLength (); i < l; i++) {
802             IDataElement value = getListValue (i);
803             if (value != null)
804                value.memoryUnlock ();
805          }
806       }
807    
808       /**
809        * Renders the DataElement as an ordered tuple.
810        */
811    
812       public String toString () {
813          return toString (this);
814       }
815    
816       /**
817        * {@inheritDoc}
818        */
819    
820       public String toString (NumberFormat format) {
821          return toString (this, format);
822       }
823    
824       /**
825        * {@inheritDoc}
826        */
827    
828       public String toString (long pos) {
829          return toString (this, pos);
830       }
831    
832       /**
833        * {@inheritDoc}
834        */
835    
836       public String toString (boolean limit, int size) {
837          return toString (this, limit, size);
838       }
839    
840       /**
841        * {@inheritDoc}
842        */
843    
844       public String toString (long pos, NumberFormat format) {
845          return toString (this, pos, format);
846       }
847    
848       /**
849        * {@inheritDoc}
850        */
851    
852       public String toString (boolean limit, int size, NumberFormat format) {
853          return toString (this, limit, size, format);
854       }
855    
856       /**
857        * {@inheritDoc}
858        */
859    
860       public String toString (boolean limit, int size, long pos) {
861          return toString (this, limit, size, pos);
862       }
863    
864       /**
865        * {@inheritDoc}
866        */
867    
868       public String toString (boolean limit, int size, long pos, NumberFormat format) {
869          return toString (this, limit, size, pos, format);
870       }
871    }